diff options
Diffstat (limited to 'nixpkgs/pkgs/applications/networking/browsers/chromium')
10 files changed, 1210 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md b/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md new file mode 100644 index 000000000000..9576cb486288 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md @@ -0,0 +1,99 @@ +# Maintainers + +- Note: We could always use more contributors, testers, etc. E.g.: + - A dedicated maintainer for the NixOS stable channel + - PRs with cleanups, improvements, fixes, etc. (but please try to make reviews + as easy as possible) + - People who handle stale issues/PRs +- Primary maintainer (responsible for all updates): @primeos +- Testers (test all stable channel updates) + - `nixos-unstable`: + - `x86_64`: @danielfullmer + - `aarch64`: @thefloweringash + - Stable channel: + - `x86_64`: @Frostman +- Other relevant packages: + - `chromiumBeta` and `chromiumDev`: For testing purposes only (not build on + Hydra). We use these channels for testing and to fix build errors in advance + so that `chromium` updates are trivial and can be merged fast. + - `google-chrome`, `google-chrome-beta`, `google-chrome-dev`: Updated via + Chromium's `upstream-info.json` + - `ungoogled-chromium`: @squalus + - `chromedriver`: Updated via Chromium's `upstream-info.json` and not built + from source. + +# Upstream links + +- Source code: https://source.chromium.org/chromium/chromium/src +- Bugs: https://bugs.chromium.org/p/chromium/issues/list +- Release updates: https://chromereleases.googleblog.com/ + - Available as Atom or RSS feed (filter for + "Stable Channel Update for Desktop") + - Channel overview: https://omahaproxy.appspot.com/ + - Release schedule: https://chromiumdash.appspot.com/schedule + +# Updating Chromium + +Simply run `./pkgs/applications/networking/browsers/chromium/update.py` to +update `upstream-info.json`. After updates it is important to test at least +`nixosTests.chromium` (or basic manual testing) and `google-chrome` (which +reuses `upstream-info.json`). + +Note: The source tarball is often only available a few hours after the release +was announced. The CI/CD status can be tracked here: +- https://ci.chromium.org/p/infra/builders/cron/publish_tarball +- https://ci.chromium.org/p/infra/builders/cron/publish_tarball_dispatcher + +To run all automated NixOS VM tests for Chromium, ungoogled-chromium, +and Google Chrome (not recommended, currently 6x tests!): +``` +nix-build nixos/tests/chromium.nix +``` + +A single test can be selected, e.g. to test `ungoogled-chromium` (see +`channelMap` in `nixos/tests/chromium.nix` for all available options): +``` +nix-build nixos/tests/chromium.nix -A ungoogled +``` +(Note: Testing Google Chrome requires `export NIXPKGS_ALLOW_UNFREE=1`.) + +For custom builds it's possible to "override" `channelMap`. + +## Backports + +All updates are considered security critical and should be ported to the stable +channel ASAP. When there is a new stable release the old one should receive +security updates for roughly one month. After that it is important to mark +Chromium as insecure (see 69e4ae56c4b for an example; it is important that the +tested job still succeeds and that all browsers that use `upstream-info.json` +are marked as insecure). + +## Major version updates + +Unfortunately, Chromium regularly breaks on major updates and might need +various patches. Either due to issues with the Nix build sandbox (e.g. we cannot +fetch dependencies via the network and do not use standard FHS paths) or due to +missing upstream fixes that need to be backported. + +Good sources for such patches and other hints: +- https://github.com/archlinux/svntogit-packages/tree/packages/chromium/trunk +- https://gitweb.gentoo.org/repo/gentoo.git/tree/www-client/chromium +- https://src.fedoraproject.org/rpms/chromium/tree/master + +If the build fails immediately due to unknown compiler flags this usually means +that a new major release of LLVM is required. + +## Beta and Dev channels + +Those channels are only used to test and fix builds in advance. They may be +broken at times and must not delay stable channel updates. + +# Testing + +Useful tests: +- Version: chrome://version/ +- GPU acceleration: chrome://gpu/ +- Essential functionality: Browsing, extensions, video+audio, JS, ... +- WebGL: https://get.webgl.org/ +- VA-API: https://wiki.archlinux.org/index.php/chromium#Hardware_video_acceleration +- Optional: Widevine CDM (proprietary), Benchmarks, Ozone, etc. diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix new file mode 100644 index 000000000000..96729f1dcda6 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix @@ -0,0 +1,98 @@ +{ lib, mkChromiumDerivation +, channel, chromiumVersionAtLeast +, enableWideVine, ungoogled +}: + +with lib; + +mkChromiumDerivation (base: rec { + name = "chromium-browser"; + packageName = "chromium"; + buildTargets = [ "mksnapshot" "chrome_sandbox" "chrome" ]; + + outputs = ["out" "sandbox"]; + + sandboxExecutableName = "__chromium-suid-sandbox"; + + installPhase = '' + mkdir -p "$libExecPath" + cp -v "$buildPath/"*.so "$buildPath/"*.pak "$buildPath/"*.bin "$libExecPath/" + cp -v "$buildPath/icudtl.dat" "$libExecPath/" + cp -vLR "$buildPath/locales" "$buildPath/resources" "$libExecPath/" + cp -v "$buildPath/chrome_crashpad_handler" "$libExecPath/" + cp -v "$buildPath/chrome" "$libExecPath/$packageName" + + # Swiftshader + # See https://stackoverflow.com/a/4264351/263061 for the find invocation. + if [ -n "$(find "$buildPath/swiftshader/" -maxdepth 1 -name '*.so' -print -quit)" ]; then + echo "Swiftshader files found; installing" + mkdir -p "$libExecPath/swiftshader" + cp -v "$buildPath/swiftshader/"*.so "$libExecPath/swiftshader/" + else + echo "Swiftshader files not found" + fi + + mkdir -p "$sandbox/bin" + cp -v "$buildPath/chrome_sandbox" "$sandbox/bin/${sandboxExecutableName}" + + mkdir -vp "$out/share/man/man1" + cp -v "$buildPath/chrome.1" "$out/share/man/man1/$packageName.1" + + for icon_file in chrome/app/theme/chromium/product_logo_*[0-9].png; do + num_and_suffix="''${icon_file##*logo_}" + icon_size="''${num_and_suffix%.*}" + expr "$icon_size" : "^[0-9][0-9]*$" || continue + logo_output_prefix="$out/share/icons/hicolor" + logo_output_path="$logo_output_prefix/''${icon_size}x''${icon_size}/apps" + mkdir -vp "$logo_output_path" + cp -v "$icon_file" "$logo_output_path/$packageName.png" + done + + # Install Desktop Entry + install -D chrome/installer/linux/common/desktop.template \ + $out/share/applications/chromium-browser.desktop + + substituteInPlace $out/share/applications/chromium-browser.desktop \ + --replace "@@MENUNAME@@" "Chromium" \ + --replace "@@PACKAGE@@" "chromium" \ + --replace "Exec=/usr/bin/@@USR_BIN_SYMLINK_NAME@@" "Exec=chromium" + + # Append more mime types to the end + sed -i '/^MimeType=/ s,$,x-scheme-handler/webcal;x-scheme-handler/mailto;x-scheme-handler/about;x-scheme-handler/unknown,' \ + $out/share/applications/chromium-browser.desktop + + # See https://github.com/NixOS/nixpkgs/issues/12433 + sed -i \ + -e '/\[Desktop Entry\]/a\' \ + -e 'StartupWMClass=chromium-browser' \ + $out/share/applications/chromium-browser.desktop + ''; + + passthru = { inherit sandboxExecutableName; }; + + requiredSystemFeatures = [ "big-parallel" ]; + + meta = { + description = "An open source web browser from Google" + + optionalString ungoogled ", with dependencies on Google web services removed"; + longDescription = '' + Chromium is an open source web browser from Google that aims to build a + safer, faster, and more stable way for all Internet users to experience + the web. It has a minimalist user interface and provides the vast majority + of source code for Google Chrome (which has some additional features). + ''; + homepage = if ungoogled + then "https://github.com/Eloston/ungoogled-chromium" + else "https://www.chromium.org/"; + maintainers = with maintainers; if ungoogled + then [ squalus primeos ] + else [ primeos thefloweringash ]; + license = if enableWideVine then licenses.unfree else licenses.bsd3; + platforms = platforms.linux; + mainProgram = "chromium"; + hydraPlatforms = if (channel == "stable" || channel == "ungoogled-chromium") + then ["aarch64-linux" "x86_64-linux"] + else []; + timeout = 172800; # 48 hours (increased from the Hydra default of 10h) + }; +}) diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix new file mode 100644 index 000000000000..4b7fbc38bbcc --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix @@ -0,0 +1,357 @@ +{ stdenv, lib, fetchurl, fetchpatch +# Channel data: +, channel, upstream-info +# Helper functions: +, chromiumVersionAtLeast, versionRange + +# Native build inputs: +, ninja, pkg-config +, python2, python3, perl +, gnutar, which +, llvmPackages +# postPatch: +, pkgsBuildHost +# configurePhase: +, gnChromium + +# Build inputs: +, libpng +, bzip2, flac, speex, libopus +, libevent, expat, libjpeg, snappy +, libcap +, xdg-utils, minizip, libwebp +, libusb1, re2 +, ffmpeg, libxslt, libxml2 +, nasm +, nspr, nss, systemd +, util-linux, alsa-lib +, bison, gperf, libkrb5 +, glib, gtk3, dbus-glib +, libXScrnSaver, libXcursor, libXtst, libxshmfence, libGLU, libGL +, mesa +, pciutils, protobuf, speechd, libXdamage, at-spi2-core +, pipewire +, libva +, libdrm, wayland, libxkbcommon # Ozone +, curl +# postPatch: +, glibc # gconv + locale + +# Package customization: +, gnomeSupport ? false, gnome2 ? null +, gnomeKeyringSupport ? false, libgnome-keyring3 ? null +, cupsSupport ? true, cups ? null +, proprietaryCodecs ? true +, pulseSupport ? false, libpulseaudio ? null +, ungoogled ? false, ungoogled-chromium +# Optional dependencies: +, libgcrypt ? null # gnomeSupport || cupsSupport +}: + +buildFun: + +with lib; + +let + python2WithPackages = python2.withPackages(ps: with ps; [ + ply jinja2 setuptools + ]); + python3WithPackages = python3.withPackages(ps: with ps; [ + ply jinja2 setuptools + ]); + + # The additional attributes for creating derivations based on the chromium + # source tree. + extraAttrs = buildFun base; + + githubPatch = { commit, sha256, revert ? false }: fetchpatch { + url = "https://github.com/chromium/chromium/commit/${commit}.patch"; + inherit sha256 revert; + }; + + mkGnFlags = + let + # Serialize Nix types into GN types according to this document: + # https://source.chromium.org/gn/gn/+/master:docs/language.md + mkGnString = value: "\"${escape ["\"" "$" "\\"] value}\""; + sanitize = value: + if value == true then "true" + else if value == false then "false" + else if isList value then "[${concatMapStringsSep ", " sanitize value}]" + else if isInt value then toString value + else if isString value then mkGnString value + else throw "Unsupported type for GN value `${value}'."; + toFlag = key: value: "${key}=${sanitize value}"; + in attrs: concatStringsSep " " (attrValues (mapAttrs toFlag attrs)); + + # https://source.chromium.org/chromium/chromium/src/+/master:build/linux/unbundle/replace_gn_files.py + gnSystemLibraries = lib.optionals (!chromiumVersionAtLeast "95") [ + "zlib" + ] ++ [ + # TODO: + # "ffmpeg" + # "snappy" + "flac" + "libjpeg" + "libpng" + "libwebp" + "libxslt" + "opus" + ]; + + opusWithCustomModes = libopus.override { + withCustomModes = true; + }; + + # build paths and release info + packageName = extraAttrs.packageName or extraAttrs.name; + buildType = "Release"; + buildPath = "out/${buildType}"; + libExecPath = "$out/libexec/${packageName}"; + + ungoogler = ungoogled-chromium { + inherit (upstream-info.deps.ungoogled-patches) rev sha256; + }; + + base = rec { + name = "${packageName}-unwrapped-${version}"; + inherit (upstream-info) version; + inherit packageName buildType buildPath; + + src = fetchurl { + url = "https://commondatastorage.googleapis.com/chromium-browser-official/chromium-${version}.tar.xz"; + inherit (upstream-info) sha256; + }; + + nativeBuildInputs = [ + ninja pkg-config + python2WithPackages python3WithPackages perl + gnutar which + llvmPackages.bintools + ]; + + buildInputs = [ + (libpng.override { apngSupport = false; }) # https://bugs.chromium.org/p/chromium/issues/detail?id=752403 + bzip2 flac speex opusWithCustomModes + libevent expat libjpeg snappy + libcap + xdg-utils minizip libwebp + libusb1 re2 + ffmpeg libxslt libxml2 + nasm + nspr nss systemd + util-linux alsa-lib + bison gperf libkrb5 + glib gtk3 dbus-glib + libXScrnSaver libXcursor libXtst libxshmfence libGLU libGL + mesa # required for libgbm + pciutils protobuf speechd libXdamage at-spi2-core + pipewire + libva + libdrm wayland mesa.drivers libxkbcommon + curl + ] ++ optionals gnomeSupport [ gnome2.GConf libgcrypt ] + ++ optional gnomeKeyringSupport libgnome-keyring3 + ++ optionals cupsSupport [ libgcrypt cups ] + ++ optional pulseSupport libpulseaudio; + + patches = [ + # Optional patch to use SOURCE_DATE_EPOCH in compute_build_timestamp.py (should be upstreamed): + ./patches/no-build-timestamps.patch + # For bundling Widevine (DRM), might be replaceable via bundle_widevine_cdm=true in gnFlags: + ./patches/widevine-79.patch + ]; + + postPatch = '' + # remove unused third-party + for lib in ${toString gnSystemLibraries}; do + if [ -d "third_party/$lib" ]; then + find "third_party/$lib" -type f \ + \! -path "third_party/$lib/chromium/*" \ + \! -path "third_party/$lib/google/*" \ + \! -path "third_party/harfbuzz-ng/utils/hb_scoped.h" \ + \! -regex '.*\.\(gn\|gni\|isolate\)' \ + -delete + fi + done + + # Required for patchShebangs (unsupported interpreter directive, basename: invalid option -- '*', etc.): + substituteInPlace native_client/SConstruct --replace "#! -*- python -*-" "" + if [ -e third_party/harfbuzz-ng/src/src/update-unicode-tables.make ]; then + substituteInPlace third_party/harfbuzz-ng/src/src/update-unicode-tables.make \ + --replace "/usr/bin/env -S make -f" "/usr/bin/make -f" + fi + chmod -x third_party/webgpu-cts/src/tools/${lib.optionalString (chromiumVersionAtLeast "96") "run_"}deno + + # We want to be able to specify where the sandbox is via CHROME_DEVEL_SANDBOX + substituteInPlace sandbox/linux/suid/client/setuid_sandbox_host.cc \ + --replace \ + 'return sandbox_binary;' \ + 'return base::FilePath(GetDevelSandboxPath());' + + substituteInPlace services/audio/audio_sandbox_hook_linux.cc \ + --replace \ + '/usr/share/alsa/' \ + '${alsa-lib}/share/alsa/' \ + --replace \ + '/usr/lib/x86_64-linux-gnu/gconv/' \ + '${glibc}/lib/gconv/' \ + --replace \ + '/usr/share/locale/' \ + '${glibc}/share/locale/' + + sed -i -e 's@"\(#!\)\?.*xdg-@"\1${xdg-utils}/bin/xdg-@' \ + chrome/browser/shell_integration_linux.cc + + sed -i -e '/lib_loader.*Load/s!"\(libudev\.so\)!"${lib.getLib systemd}/lib/\1!' \ + device/udev_linux/udev?_loader.cc + + sed -i -e '/libpci_loader.*Load/s!"\(libpci\.so\)!"${pciutils}/lib/\1!' \ + gpu/config/gpu_info_collector_linux.cc + + # Allow to put extensions into the system-path. + sed -i -e 's,/usr,/run/current-system/sw,' chrome/common/chrome_paths.cc + + patchShebangs . + # Link to our own Node.js and Java (required during the build): + mkdir -p third_party/node/linux/node-linux-x64/bin + ln -s "${pkgsBuildHost.nodejs}/bin/node" third_party/node/linux/node-linux-x64/bin/node + ln -s "${pkgsBuildHost.jre8}/bin/java" third_party/jdk/current/bin/ + + # Allow building against system libraries in official builds + sed -i 's/OFFICIAL_BUILD/GOOGLE_CHROME_BUILD/' tools/generate_shim_headers/generate_shim_headers.py + + '' + optionalString stdenv.isAarch64 '' + substituteInPlace build/toolchain/linux/BUILD.gn \ + --replace 'toolprefix = "aarch64-linux-gnu-"' 'toolprefix = ""' + '' + optionalString ungoogled '' + ${ungoogler}/utils/prune_binaries.py . ${ungoogler}/pruning.list || echo "some errors" + ${ungoogler}/utils/patches.py . ${ungoogler}/patches + ${ungoogler}/utils/domain_substitution.py apply -r ${ungoogler}/domain_regex.list -f ${ungoogler}/domain_substitution.list -c ./ungoogled-domsubcache.tar.gz . + ''; + + gnFlags = mkGnFlags ({ + # Main build and toolchain settings: + # Create an official and optimized release build (only official builds + # should be distributed to users, as non-official builds are intended for + # development and may not be configured appropriately for production, + # e.g. unsafe developer builds have developer-friendly features that may + # weaken or disable security measures like sandboxing or ASLR): + is_official_build = true; + disable_fieldtrial_testing_config = true; + # Build Chromium using the system toolchain (for Linux distributions): + custom_toolchain = "//build/toolchain/linux/unbundle:default"; + host_toolchain = "//build/toolchain/linux/unbundle:default"; + # Don't build against a sysroot image downloaded from Cloud Storage: + use_sysroot = false; + # The default value is hardcoded instead of using pkg-config: + system_wayland_scanner_path = "${wayland}/bin/wayland-scanner"; + # Because we use a different toolchain / compiler version: + treat_warnings_as_errors = false; + # We aren't compiling with Chrome's Clang (would enable Chrome-specific + # plugins for enforcing coding guidelines, etc.): + clang_use_chrome_plugins = false; + # Disable symbols (they would negatively affect the performance of the + # build since the symbols are large and dealing with them is slow): + symbol_level = 0; + blink_symbol_level = 0; + + # Google API key, see: https://www.chromium.org/developers/how-tos/api-keys + # Note: The API key is for NixOS/nixpkgs use ONLY. + # For your own distribution, please get your own set of keys. + google_api_key = "AIzaSyDGi15Zwl11UNe6Y-5XW_upsfyw31qwZPI"; + + # Optional features: + use_gio = gnomeSupport; + use_gnome_keyring = gnomeKeyringSupport; + use_cups = cupsSupport; + + # Feature overrides: + # Native Client support was deprecated in 2020 and support will end in June 2021: + enable_nacl = false; + # Enabling the Widevine component here doesn't affect whether we can + # redistribute the chromium package; the Widevine component is either + # added later in the wrapped -wv build or downloaded from Google: + enable_widevine = true; + # Provides the enable-webrtc-pipewire-capturer flag to support Wayland screen capture: + rtc_use_pipewire = true; + } // optionalAttrs proprietaryCodecs { + # enable support for the H.264 codec + proprietary_codecs = true; + enable_hangout_services_extension = true; + ffmpeg_branding = "Chrome"; + } // optionalAttrs pulseSupport { + use_pulseaudio = true; + link_pulseaudio = true; + } // optionalAttrs ungoogled { + chrome_pgo_phase = 0; + enable_hangout_services_extension = false; + enable_js_type_check = false; + enable_mdns = false; + enable_nacl_nonsfi = false; + enable_one_click_signin = false; + enable_reading_list = false; + enable_remoting = false; + enable_reporting = false; + enable_service_discovery = false; + exclude_unwind_tables = true; + google_api_key = ""; + google_default_client_id = ""; + google_default_client_secret = ""; + safe_browsing_mode = 0; + use_official_google_api_keys = false; + use_unofficial_version_number = false; + } // (extraAttrs.gnFlags or {})); + + configurePhase = '' + runHook preConfigure + + # This is to ensure expansion of $out. + libExecPath="${libExecPath}" + ${python2}/bin/python2 build/linux/unbundle/replace_gn_files.py --system-libraries ${toString gnSystemLibraries} + ${gnChromium}/bin/gn gen --args=${escapeShellArg gnFlags} out/Release | tee gn-gen-outputs.txt + + # Fail if `gn gen` contains a WARNING. + grep -o WARNING gn-gen-outputs.txt && echo "Found gn WARNING, exiting nix build" && exit 1 + + runHook postConfigure + ''; + + # Don't spam warnings about unknown warning options. This is useful because + # our Clang is always older than Chromium's and the build logs have a size + # of approx. 25 MB without this option (and this saves e.g. 66 %). + NIX_CFLAGS_COMPILE = "-Wno-unknown-warning-option"; + + buildPhase = let + buildCommand = target: '' + ninja -C "${buildPath}" -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES "${target}" + ( + source chrome/installer/linux/common/installer.include + PACKAGE=$packageName + MENUNAME="Chromium" + process_template chrome/app/resources/manpage.1.in "${buildPath}/chrome.1" + ) + ''; + targets = extraAttrs.buildTargets or []; + commands = map buildCommand targets; + in concatStringsSep "\n" commands; + + postFixup = '' + # Make sure that libGLESv2 is found by dlopen (if using EGL). + chromiumBinary="$libExecPath/$packageName" + origRpath="$(patchelf --print-rpath "$chromiumBinary")" + patchelf --set-rpath "${libGL}/lib:$origRpath" "$chromiumBinary" + ''; + + passthru = { + updateScript = ./update.py; + chromiumDeps = { + gn = gnChromium; + }; + }; + }; + +# Remove some extraAttrs we supplied to the base attributes already. +in stdenv.mkDerivation (base // removeAttrs extraAttrs [ + "name" "gnFlags" "buildTargets" +] // { passthru = base.passthru // (extraAttrs.passthru or {}); }) diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix new file mode 100644 index 000000000000..c4521c89caa6 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix @@ -0,0 +1,234 @@ +{ newScope, config, stdenv, fetchurl, makeWrapper +, llvmPackages_13, ed, gnugrep, coreutils, xdg-utils +, glib, gtk3, gnome, gsettings-desktop-schemas, gn, fetchgit +, libva, pipewire, wayland +, gcc, nspr, nss, runCommand +, lib + +# package customization +# Note: enable* flags should not require full rebuilds (i.e. only affect the wrapper) +, channel ? "stable" +, gnomeSupport ? false, gnome2 ? null +, gnomeKeyringSupport ? false +, proprietaryCodecs ? true +, enableWideVine ? false +, ungoogled ? false # Whether to build chromium or ungoogled-chromium +, cupsSupport ? true +, pulseSupport ? config.pulseaudio or stdenv.isLinux +, commandLineArgs ? "" +}: + +let + llvmPackages = llvmPackages_13; + stdenv = llvmPackages.stdenv; + + upstream-info = (lib.importJSON ./upstream-info.json).${channel}; + + # Helper functions for changes that depend on specific versions: + warnObsoleteVersionConditional = min-version: result: + let ungoogled-version = (lib.importJSON ./upstream-info.json).ungoogled-chromium.version; + in lib.warnIf + (lib.versionAtLeast ungoogled-version min-version) + "chromium: ungoogled version ${ungoogled-version} is newer than a conditional bounded at ${min-version}. You can safely delete it." + result; + chromiumVersionAtLeast = min-version: + let result = lib.versionAtLeast upstream-info.version min-version; + in warnObsoleteVersionConditional min-version result; + versionRange = min-version: upto-version: + let inherit (upstream-info) version; + result = lib.versionAtLeast version min-version && lib.versionOlder version upto-version; + in warnObsoleteVersionConditional upto-version result; + + callPackage = newScope chromium; + + chromium = rec { + inherit stdenv llvmPackages upstream-info; + + mkChromiumDerivation = callPackage ./common.nix ({ + inherit channel chromiumVersionAtLeast versionRange; + inherit gnome2 gnomeSupport gnomeKeyringSupport proprietaryCodecs + cupsSupport pulseSupport ungoogled; + gnChromium = gn.overrideAttrs (oldAttrs: { + inherit (upstream-info.deps.gn) version; + src = fetchgit { + inherit (upstream-info.deps.gn) url rev sha256; + }; + }); + }); + + browser = callPackage ./browser.nix { + inherit channel chromiumVersionAtLeast enableWideVine ungoogled; + }; + + ungoogled-chromium = callPackage ./ungoogled.nix {}; + }; + + pkgSuffix = if channel == "dev" then "unstable" else + (if channel == "ungoogled-chromium" then "stable" else channel); + pkgName = "google-chrome-${pkgSuffix}"; + chromeSrc = + let + # Use the latest stable Chrome version if necessary: + version = if chromium.upstream-info.sha256bin64 != null + then chromium.upstream-info.version + else (lib.importJSON ./upstream-info.json).stable.version; + sha256 = if chromium.upstream-info.sha256bin64 != null + then chromium.upstream-info.sha256bin64 + else (lib.importJSON ./upstream-info.json).stable.sha256bin64; + in fetchurl { + urls = map (repo: "${repo}/${pkgName}/${pkgName}_${version}-1_amd64.deb") [ + "https://dl.google.com/linux/chrome/deb/pool/main/g" + "http://95.31.35.30/chrome/pool/main/g" + "http://mirror.pcbeta.com/google/chrome/deb/pool/main/g" + "http://repo.fdzh.org/chrome/deb/pool/main/g" + ]; + inherit sha256; + }; + + mkrpath = p: "${lib.makeSearchPathOutput "lib" "lib64" p}:${lib.makeLibraryPath p}"; + widevineCdm = stdenv.mkDerivation { + name = "chrome-widevine-cdm"; + + src = chromeSrc; + + unpackCmd = let + widevineCdmPath = + if (channel == "stable" || channel == "ungoogled-chromium") then + "./opt/google/chrome/WidevineCdm" + else if channel == "beta" then + "./opt/google/chrome-beta/WidevineCdm" + else if channel == "dev" then + "./opt/google/chrome-unstable/WidevineCdm" + else + throw "Unknown chromium channel."; + in '' + # Extract just WidevineCdm from upstream's .deb file + ar p "$src" data.tar.xz | tar xJ "${widevineCdmPath}" + + # Move things around so that we don't have to reference a particular + # chrome-* directory later. + mv "${widevineCdmPath}" ./ + + # unpackCmd wants a single output directory; let it take WidevineCdm/ + rm -rf opt + ''; + + doCheck = true; + checkPhase = '' + ! find -iname '*.so' -exec ldd {} + | grep 'not found' + ''; + + PATCH_RPATH = mkrpath [ gcc.cc glib nspr nss ]; + + patchPhase = '' + patchelf --set-rpath "$PATCH_RPATH" _platform_specific/linux_x64/libwidevinecdm.so + ''; + + installPhase = '' + mkdir -p $out/WidevineCdm + cp -a * $out/WidevineCdm/ + ''; + + meta = { + platforms = [ "x86_64-linux" ]; + license = lib.licenses.unfree; + }; + }; + + suffix = if (channel == "stable" || channel == "ungoogled-chromium") + then "" + else "-" + channel; + + sandboxExecutableName = chromium.browser.passthru.sandboxExecutableName; + + version = chromium.browser.version; + + # We want users to be able to enableWideVine without rebuilding all of + # chromium, so we have a separate derivation here that copies chromium + # and adds the unfree WidevineCdm. + chromiumWV = let browser = chromium.browser; in if enableWideVine then + runCommand (browser.name + "-wv") { version = browser.version; } + '' + mkdir -p $out + cp -a ${browser}/* $out/ + chmod u+w $out/libexec/chromium + cp -a ${widevineCdm}/WidevineCdm $out/libexec/chromium/ + '' + else browser; + +in stdenv.mkDerivation { + name = lib.optionalString ungoogled "ungoogled-" + + "chromium${suffix}-${version}"; + inherit version; + + nativeBuildInputs = [ + makeWrapper ed + ]; + + buildInputs = [ + # needed for GSETTINGS_SCHEMAS_PATH + gsettings-desktop-schemas glib gtk3 + + # needed for XDG_ICON_DIRS + gnome.adwaita-icon-theme + ]; + + outputs = ["out" "sandbox"]; + + buildCommand = let + browserBinary = "${chromiumWV}/libexec/chromium/chromium"; + libPath = lib.makeLibraryPath [ libva pipewire wayland gtk3 ]; + + in with lib; '' + mkdir -p "$out/bin" + + eval makeWrapper "${browserBinary}" "$out/bin/chromium" \ + --add-flags ${escapeShellArg (escapeShellArg commandLineArgs)} + + ed -v -s "$out/bin/chromium" << EOF + 2i + + if [ -x "/run/wrappers/bin/${sandboxExecutableName}" ] + then + export CHROME_DEVEL_SANDBOX="/run/wrappers/bin/${sandboxExecutableName}" + else + export CHROME_DEVEL_SANDBOX="$sandbox/bin/${sandboxExecutableName}" + fi + + '' + lib.optionalString (libPath != "") '' + # To avoid loading .so files from cwd, LD_LIBRARY_PATH here must not + # contain an empty section before or after a colon. + export LD_LIBRARY_PATH="\$LD_LIBRARY_PATH\''${LD_LIBRARY_PATH:+:}${libPath}" + '' + '' + + # libredirect causes chromium to deadlock on startup + export LD_PRELOAD="\$(echo -n "\$LD_PRELOAD" | ${coreutils}/bin/tr ':' '\n' | ${gnugrep}/bin/grep -v /lib/libredirect\\\\.so$ | ${coreutils}/bin/tr '\n' ':')" + + export XDG_DATA_DIRS=$XDG_ICON_DIRS:$GSETTINGS_SCHEMAS_PATH\''${XDG_DATA_DIRS:+:}\$XDG_DATA_DIRS + + # Mainly for xdg-open but also other xdg-* tools: + export PATH="${xdg-utils}/bin\''${PATH:+:}\$PATH" + + . + w + EOF + + ln -sv "${chromium.browser.sandbox}" "$sandbox" + + ln -s "$out/bin/chromium" "$out/bin/chromium-browser" + + mkdir -p "$out/share" + for f in '${chromium.browser}'/share/*; do # hello emacs */ + ln -s -t "$out/share/" "$f" + done + ''; + + inherit (chromium.browser) packageName; + meta = chromium.browser.meta; + passthru = { + inherit (chromium) upstream-info browser; + mkDerivation = chromium.mkChromiumDerivation; + inherit chromeSrc sandboxExecutableName; + updateScript = ./update.py; + }; +} diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py b/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py new file mode 100755 index 000000000000..b0fbe20db8ef --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py @@ -0,0 +1,53 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i python3 -p python3Packages.feedparser python3Packages.requests + +# This script prints the Git commit message for stable channel updates. +# Usage: ./get-commit-message.py [version] + +import re +import sys +import textwrap + +from collections import OrderedDict + +import feedparser +import requests + +feed = feedparser.parse('https://chromereleases.googleblog.com/feeds/posts/default') +html_tags = re.compile(r'<[^>]+>') +target_version = sys.argv[1] if len(sys.argv) == 2 else None + +for entry in feed.entries: + url = requests.get(entry.link).url.split('?')[0] + if entry.title != 'Stable Channel Update for Desktop': + if target_version and entry.title == '': + # Workaround for a special case (Chrome Releases bug?): + if not 'the-stable-channel-has-been-updated-to' in url: + continue + else: + continue + content = entry.content[0].value + content = html_tags.sub('', content) # Remove any HTML tags + if re.search(r'Linux', content) is None: + continue + #print(url) # For debugging purposes + version = re.search(r'\d+(\.\d+){3}', content).group(0) + if target_version: + if version != target_version: + continue + else: + print('chromium: TODO -> ' + version + '\n') + print(url) + if fixes := re.search(r'This update includes .+ security fixes\.', content).group(0): + zero_days = re.search(r'Google is aware( of reports)? that .+ in the wild\.', content) + if zero_days: + fixes += " " + zero_days.group(0) + print('\n' + '\n'.join(textwrap.wrap(fixes, width=72))) + if cve_list := re.findall(r'CVE-[^: ]+', content): + cve_list = list(OrderedDict.fromkeys(cve_list)) # Remove duplicates but preserve the order + cve_string = ' '.join(cve_list) + print("\nCVEs:\n" + '\n'.join(textwrap.wrap(cve_string, width=72))) + sys.exit(0) # We only care about the most recent stable channel update + +print("Error: No match.") +sys.exit(1) diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch new file mode 100644 index 000000000000..6b788f43d29c --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch @@ -0,0 +1,17 @@ +--- chromium-70.0.3538.67/build/compute_build_timestamp.py.orig 2018-11-02 16:00:34.368933077 +0200 ++++ chromium-70.0.3538.67/build/compute_build_timestamp.py 2018-11-08 04:06:21.658105129 +0200 +@@ -94,6 +94,14 @@ + 'build_type', help='The type of build', choices=('official', 'default')) + args = argument_parser.parse_args() + ++ # I don't trust LASTCHANGE magic, and I definelly want something deterministic here ++ SOURCE_DATE_EPOCH = os.getenv("SOURCE_DATE_EPOCH", None) ++ if SOURCE_DATE_EPOCH is not None: ++ print(SOURCE_DATE_EPOCH) ++ return 0 ++ else: ++ raise RuntimeError("SOURCE_DATE_EPOCH not set") ++ + # The mtime of the revision in build/util/LASTCHANGE is stored in a file + # next to it. Read it, to get a deterministic time close to "now". + # That date is then modified as described at the top of the file so that diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch new file mode 100644 index 000000000000..32f0ae2fb5e6 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn +index ed0e2f5208b..5b431a030d5 100644 +--- a/third_party/widevine/cdm/BUILD.gn ++++ b/third_party/widevine/cdm/BUILD.gn +@@ -14,7 +14,7 @@ buildflag_header("buildflags") { + + flags = [ + "ENABLE_WIDEVINE=$enable_widevine", +- "BUNDLE_WIDEVINE_CDM=$bundle_widevine_cdm", ++ "BUNDLE_WIDEVINE_CDM=true", + "ENABLE_WIDEVINE_CDM_COMPONENT=$enable_widevine_cdm_component", + ] + } diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix new file mode 100644 index 000000000000..a8e84dae196d --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix @@ -0,0 +1,43 @@ +{ stdenv +, fetchFromGitHub +, python3Packages +, makeWrapper +, patch +}: + +{ rev +, sha256 +}: + +stdenv.mkDerivation rec { + pname = "ungoogled-chromium"; + + version = rev; + + src = fetchFromGitHub { + owner = "Eloston"; + repo = "ungoogled-chromium"; + inherit rev sha256; + }; + + dontBuild = true; + + buildInputs = [ + python3Packages.python + patch + ]; + + nativeBuildInputs = [ + makeWrapper + ]; + + patchPhase = '' + sed -i '/chromium-widevine/d' patches/series + ''; + + installPhase = '' + mkdir $out + cp -R * $out/ + wrapProgram $out/utils/patches.py --add-flags "apply" --prefix PATH : "${patch}/bin" + ''; +} diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py b/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py new file mode 100755 index 000000000000..72d6df055b38 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py @@ -0,0 +1,233 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python -p python3 nix nix-prefetch-git + +"""This script automatically updates chromium, google-chrome, chromedriver, and ungoogled-chromium +via upstream-info.json.""" +# Usage: ./update.py [--commit] + +import csv +import json +import re +import subprocess +import sys + +from codecs import iterdecode +from collections import OrderedDict +from datetime import datetime +from distutils.version import LooseVersion +from os.path import abspath, dirname +from urllib.request import urlopen + +HISTORY_URL = 'https://omahaproxy.appspot.com/history?os=linux' +DEB_URL = 'https://dl.google.com/linux/chrome/deb/pool/main/g' +BUCKET_URL = 'https://commondatastorage.googleapis.com/chromium-browser-official' + +JSON_PATH = dirname(abspath(__file__)) + '/upstream-info.json' +COMMIT_MESSAGE_SCRIPT = dirname(abspath(__file__)) + '/get-commit-message.py' + + +def load_json(path): + """Loads the given JSON file.""" + with open(path, 'r') as f: + return json.load(f) + + +def nix_prefetch_url(url, algo='sha256'): + """Prefetches the content of the given URL.""" + print(f'nix-prefetch-url {url}') + out = subprocess.check_output(['nix-prefetch-url', '--type', algo, url]) + return out.decode('utf-8').rstrip() + + +def nix_prefetch_git(url, rev): + """Prefetches the requested Git revision of the given repository URL.""" + print(f'nix-prefetch-git {url} {rev}') + out = subprocess.check_output(['nix-prefetch-git', '--quiet', '--url', url, '--rev', rev]) + return json.loads(out) + + +def get_file_revision(revision, file_path): + """Fetches the requested Git revision of the given Chromium file.""" + url = f'https://raw.githubusercontent.com/chromium/chromium/{revision}/{file_path}' + with urlopen(url) as http_response: + return http_response.read() + + +def get_matching_chromedriver(version): + """Gets the matching chromedriver version for the given Chromium version.""" + # See https://chromedriver.chromium.org/downloads/version-selection + build = re.sub('.[0-9]+$', '', version) + chromedriver_version_url = f'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_{build}' + with urlopen(chromedriver_version_url) as http_response: + chromedriver_version = http_response.read().decode() + def get_chromedriver_url(system): + return ('https://chromedriver.storage.googleapis.com/' + + f'{chromedriver_version}/chromedriver_{system}.zip') + return { + 'version': chromedriver_version, + 'sha256_linux': nix_prefetch_url(get_chromedriver_url('linux64')), + 'sha256_darwin': nix_prefetch_url(get_chromedriver_url('mac64')) + } + + +def get_channel_dependencies(version): + """Gets all dependencies for the given Chromium version.""" + deps = get_file_revision(version, 'DEPS') + gn_pattern = b"'gn_version': 'git_revision:([0-9a-f]{40})'" + gn_commit = re.search(gn_pattern, deps).group(1).decode() + gn = nix_prefetch_git('https://gn.googlesource.com/gn', gn_commit) + return { + 'gn': { + 'version': datetime.fromisoformat(gn['date']).date().isoformat(), + 'url': gn['url'], + 'rev': gn['rev'], + 'sha256': gn['sha256'] + } + } + + +def get_latest_ungoogled_chromium_tag(): + """Returns the latest ungoogled-chromium tag using the GitHub API.""" + api_tag_url = 'https://api.github.com/repos/Eloston/ungoogled-chromium/tags?per_page=1' + with urlopen(api_tag_url) as http_response: + tag_data = json.load(http_response) + return tag_data[0]['name'] + + +def get_latest_ungoogled_chromium_build(): + """Returns a dictionary for the latest ungoogled-chromium build.""" + tag = get_latest_ungoogled_chromium_tag() + version = tag.split('-')[0] + return { + 'channel': 'ungoogled-chromium', + 'version': version, + 'ungoogled_tag': tag + } + + +def channel_name_to_attr_name(channel_name): + """Maps a channel name to the corresponding main Nixpkgs attribute name.""" + if channel_name == 'stable': + return 'chromium' + if channel_name == 'beta': + return 'chromiumBeta' + if channel_name == 'dev': + return 'chromiumDev' + if channel_name == 'ungoogled-chromium': + return 'ungoogled-chromium' + print(f'Error: Unexpected channel: {channel_name}', file=sys.stderr) + sys.exit(1) + + +def get_channel_key(item): + """Orders Chromium channels by their name.""" + channel_name = item[0] + if channel_name == 'stable': + return 0 + if channel_name == 'beta': + return 1 + if channel_name == 'dev': + return 2 + if channel_name == 'ungoogled-chromium': + return 3 + print(f'Error: Unexpected channel: {channel_name}', file=sys.stderr) + sys.exit(1) + + +def print_updates(channels_old, channels_new): + """Print a summary of the updates.""" + print('Updates:') + for channel_name in channels_old: + version_old = channels_old[channel_name]["version"] + version_new = channels_new[channel_name]["version"] + if LooseVersion(version_old) < LooseVersion(version_new): + attr_name = channel_name_to_attr_name(channel_name) + print(f'- {attr_name}: {version_old} -> {version_new}') + + +channels = {} +last_channels = load_json(JSON_PATH) + + +print(f'GET {HISTORY_URL}', file=sys.stderr) +with urlopen(HISTORY_URL) as resp: + builds = csv.DictReader(iterdecode(resp, 'utf-8')) + builds = list(builds) + builds.append(get_latest_ungoogled_chromium_build()) + for build in builds: + channel_name = build['channel'] + + # If we've already found a newer build for this channel, we're + # no longer interested in it. + if channel_name in channels: + continue + + # If we're back at the last build we used, we don't need to + # keep going -- there's no new version available, and we can + # just reuse the info from last time. + if build['version'] == last_channels[channel_name]['version']: + channels[channel_name] = last_channels[channel_name] + continue + + channel = {'version': build['version']} + if channel_name == 'dev': + google_chrome_suffix = 'unstable' + elif channel_name == 'ungoogled-chromium': + google_chrome_suffix = 'stable' + else: + google_chrome_suffix = channel_name + + try: + channel['sha256'] = nix_prefetch_url(f'{BUCKET_URL}/chromium-{build["version"]}.tar.xz') + channel['sha256bin64'] = nix_prefetch_url( + f'{DEB_URL}/google-chrome-{google_chrome_suffix}/' + + f'google-chrome-{google_chrome_suffix}_{build["version"]}-1_amd64.deb') + except subprocess.CalledProcessError: + if (channel_name == 'ungoogled-chromium' and 'sha256' in channel and + build['version'].split('.')[0] == last_channels['stable']['version'].split('.')[0]): + # Sometimes ungoogled-chromium is updated to a newer tag than + # the latest stable Chromium version. In this case we'll set + # sha256bin64 to null and the Nixpkgs code will fall back to + # the latest stable Google Chrome (only required for + # Widevine/DRM which is disabled by default): + channel['sha256bin64'] = None + else: + # This build isn't actually available yet. Continue to + # the next one. + continue + + channel['deps'] = get_channel_dependencies(channel['version']) + if channel_name == 'stable': + channel['chromedriver'] = get_matching_chromedriver(channel['version']) + elif channel_name == 'ungoogled-chromium': + ungoogled_repo_url = 'https://github.com/Eloston/ungoogled-chromium.git' + channel['deps']['ungoogled-patches'] = { + 'rev': build['ungoogled_tag'], + 'sha256': nix_prefetch_git(ungoogled_repo_url, build['ungoogled_tag'])['sha256'] + } + + channels[channel_name] = channel + + +sorted_channels = OrderedDict(sorted(channels.items(), key=get_channel_key)) +if len(sys.argv) == 2 and sys.argv[1] == '--commit': + for channel_name in sorted_channels.keys(): + version_old = last_channels[channel_name]['version'] + version_new = sorted_channels[channel_name]['version'] + if LooseVersion(version_old) < LooseVersion(version_new): + last_channels[channel_name] = sorted_channels[channel_name] + with open(JSON_PATH, 'w') as out: + json.dump(last_channels, out, indent=2) + out.write('\n') + attr_name = channel_name_to_attr_name(channel_name) + commit_message = f'{attr_name}: {version_old} -> {version_new}' + if channel_name == 'stable': + body = subprocess.check_output([COMMIT_MESSAGE_SCRIPT, version_new]).decode('utf-8') + commit_message += '\n\n' + body + subprocess.run(['git', 'add', JSON_PATH], check=True) + subprocess.run(['git', 'commit', '--file=-'], input=commit_message.encode(), check=True) +else: + with open(JSON_PATH, 'w') as out: + json.dump(sorted_channels, out, indent=2) + out.write('\n') + print_updates(last_channels, sorted_channels) diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json b/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json new file mode 100644 index 000000000000..d7f29c4fefa2 --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json @@ -0,0 +1,63 @@ +{ + "stable": { + "version": "94.0.4606.61", + "sha256": "1gxrxmd2almwf067zycilyxkmc0d62h99ln8wp3n3i02bi9xnik4", + "sha256bin64": "116xrf8hcprbdpdx6a4xysac2phyvw88vs3n1bs24ly6pxydsasz", + "deps": { + "gn": { + "version": "2021-08-11", + "url": "https://gn.googlesource.com/gn", + "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263", + "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0" + } + }, + "chromedriver": { + "version": "94.0.4606.41", + "sha256_linux": "06flgis4am4jmd9qz6yn1jfdr07w2n3mfrlicw6a9icg5ir64fdq", + "sha256_darwin": "1mc0hhksqm5ms4k4aji043xzxncbifjwz5fqzywy4ji64w5kqrca" + } + }, + "beta": { + "version": "95.0.4638.17", + "sha256": "1v5r8m3wlwh6prcj7bd4zprsr4g43869lhxv43m207c5nlnqiriz", + "sha256bin64": "0h88gd8y4i2jmvhiwadbq6hzqygddym8jy1fhzp8qnwfhc30qm4m", + "deps": { + "gn": { + "version": "2021-08-11", + "url": "https://gn.googlesource.com/gn", + "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263", + "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0" + } + } + }, + "dev": { + "version": "96.0.4651.0", + "sha256": "0da1mhz3cy0k2igdh208i28k8fxca0yjfypvmj7624p7igrp4an6", + "sha256bin64": "1gslpdnpjp7w40lsl748rmbkbs31v22f2x45gahrijkvfrkgdqp9", + "deps": { + "gn": { + "version": "2021-08-11", + "url": "https://gn.googlesource.com/gn", + "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263", + "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0" + } + } + }, + "ungoogled-chromium": { + "version": "94.0.4606.54", + "sha256": "0p8kfnyhykbv1cylsx4hj2qdzqr2xdql9rhpva8bfla2w9hr8g83", + "sha256bin64": "0lq34l00zrr92g882xzqwq1lf2vf12x1mwidrr2qh6fz7v5418d3", + "deps": { + "gn": { + "version": "2021-08-11", + "url": "https://gn.googlesource.com/gn", + "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263", + "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0" + }, + "ungoogled-patches": { + "rev": "94.0.4606.54-1", + "sha256": "0phy87fiqdgikgl60yap7n1mvyvsidgznqp06j86287iihml3z2m" + } + } + } +} |