diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4c73aeb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +end_of_line = lf + +[*.sh] +indent_style = tab +tab_width = 4 + +[*.nix] +indent_style = space +indent_size = 2 diff --git a/flake.lock b/flake.lock index 66ce361..33aa5a6 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,14 +20,18 @@ }, "nixpkgs": { "locked": { - "lastModified": 0, - "narHash": "sha256-u+rxA79a0lyhG+u+oPBRtTDtzz8kvkc9a6SWSt9ekVc=", - "path": "/nix/store/0283cbhm47kd3lr9zmc5fvdrx9qkav8s-source", - "type": "path" + "lastModified": 1772773019, + "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", + "type": "github" }, "original": { - "id": "nixpkgs", - "type": "indirect" + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" } }, "root": { diff --git a/flake.nix b/flake.nix index f128dda..5ad3fd7 100644 --- a/flake.nix +++ b/flake.nix @@ -1,10 +1,19 @@ { description = "A flake for playwright"; - inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = import nixpkgs { inherit system; @@ -12,8 +21,8 @@ in { packages = { - playwright-test = pkgs.callPackage ./playwright-test/wrapped.nix { }; - playwright-driver = pkgs.callPackage ./playwright-driver { }; + playwright-test = (pkgs.callPackage ./playwright-driver/driver.nix { }).playwright-test; + playwright-driver = (pkgs.callPackage ./playwright-driver/driver.nix { }).playwright-core; }; devShells.default = pkgs.mkShell { diff --git a/playwright-driver/browsers.json b/playwright-driver/browsers.json new file mode 100644 index 0000000..bccc346 --- /dev/null +++ b/playwright-driver/browsers.json @@ -0,0 +1,38 @@ +{ + "comment": "This file is kept up to date via update.sh", + "browsers": { + "chromium": { + "revision": "1208", + "browserVersion": "145.0.7632.6", + "title": "Chrome for Testing" + }, + "chromium-headless-shell": { + "revision": "1208", + "browserVersion": "145.0.7632.6", + "title": "Chrome Headless Shell" + }, + "firefox": { + "revision": "1509", + "browserVersion": "146.0.1", + "title": "Firefox" + }, + "webkit": { + "revision": "2248", + "revisionOverrides": { + "debian11-x64": "2105", + "debian11-arm64": "2105", + "ubuntu20.04-x64": "2092", + "ubuntu20.04-arm64": "2092" + }, + "browserVersion": "26.0", + "title": "WebKit" + }, + "ffmpeg": { + "revision": "1011", + "revisionOverrides": { + "mac12": "1010", + "mac12-arm64": "1010" + } + } + } +} diff --git a/playwright-driver/chromium-headless-shell.nix b/playwright-driver/chromium-headless-shell.nix new file mode 100644 index 0000000..758e8fb --- /dev/null +++ b/playwright-driver/chromium-headless-shell.nix @@ -0,0 +1,83 @@ +{ + fetchzip, + revision, + suffix, + system, + throwSystem, + stdenv, + autoPatchelfHook, + patchelfUnstable, + + alsa-lib, + at-spi2-atk, + expat, + glib, + libXcomposite, + libXdamage, + libXfixes, + libXrandr, + libgbm, + libgcc, + libxkbcommon, + nspr, + nss, + ... +}: +let + linux = stdenv.mkDerivation { + name = "playwright-chromium-headless-shell"; + src = fetchzip { + url = "https://cdn.playwright.dev/builds/chromium/${revision}/chromium-headless-shell-${suffix}.zip"; + stripRoot = false; + hash = + { + x86_64-linux = "sha256-/xskLzTc9tTZmu1lwkMpjV3QV7XjP92D/7zRcFuVWT8="; + aarch64-linux = "sha256-jckH5+eGJ4BhH1NAa5LIgf3/salKLAHW9XUOo5gob4c="; + } + .${system} or throwSystem; + }; + + nativeBuildInputs = [ + autoPatchelfHook + patchelfUnstable + ]; + + buildInputs = [ + alsa-lib + at-spi2-atk + expat + glib + libXcomposite + libXdamage + libXfixes + libXrandr + libgbm + libgcc.lib + libxkbcommon + nspr + nss + ]; + + buildPhase = '' + cp -R . $out + ''; + }; + + darwin = fetchzip { + url = "https://cdn.playwright.dev/builds/chromium/${revision}/chromium-headless-shell-${suffix}.zip"; + stripRoot = false; + hash = + { + x86_64-darwin = "sha256-bgU7lZhp9XUFfGu58pFdZyhXho3Jiy4MjljR+yk0M1c="; + aarch64-darwin = "sha256-45DjMIu0t7IEYdXOmIqpV/1/MKdEfx/8T7DWagh6Zhc="; + } + .${system} or throwSystem; + }; +in +{ + x86_64-linux = linux; + aarch64-linux = linux; + x86_64-darwin = darwin; + aarch64-darwin = darwin; +} +.${system} or throwSystem diff --git a/playwright-driver/chromium.nix b/playwright-driver/chromium.nix new file mode 100644 index 0000000..ea1220f --- /dev/null +++ b/playwright-driver/chromium.nix @@ -0,0 +1,130 @@ +{ + runCommand, + makeWrapper, + fontconfig_file, + chromium, + fetchzip, + revision, + suffix, + system, + throwSystem, + lib, + alsa-lib, + at-spi2-atk, + atk, + autoPatchelfHook, + cairo, + cups, + dbus, + expat, + glib, + gobject-introspection, + libGL, + libgbm, + libgcc, + libxkbcommon, + nspr, + nss, + pango, + patchelf, + pciutils, + stdenv, + systemd, + vulkan-loader, + libX11, + libXcomposite, + libXdamage, + libXext, + libXfixes, + libXrandr, + libxcb, + ... +}: +let + chromium-linux = stdenv.mkDerivation { + name = "playwright-chromium"; + src = fetchzip { + url = "https://cdn.playwright.dev/builds/chromium/${revision}/chromium-${suffix}.zip"; + hash = + { + x86_64-linux = "sha256-dJSO05xOzlSl/EwOWNQCeuSb+lhUU6NlGBnRu59irnM="; + aarch64-linux = "sha256-9DFLCPuc9WZjYLzlRW+Df2pb+mViPK3/IOkkUozELsw="; + } + .${system} or throwSystem; + }; + + nativeBuildInputs = [ + autoPatchelfHook + patchelf + makeWrapper + ]; + buildInputs = [ + alsa-lib + at-spi2-atk + atk + cairo + cups + dbus + expat + glib + gobject-introspection + libgbm + libgcc + libxkbcommon + nspr + nss + pango + stdenv.cc.cc.lib + systemd + libX11 + libXcomposite + libXdamage + libXext + libXfixes + libXrandr + libxcb + ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out/chrome-linux64 + cp -R . $out/chrome-linux64 + + wrapProgram $out/chrome-linux64/chrome \ + --set-default SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt \ + --set-default FONTCONFIG_FILE ${fontconfig_file} + + runHook postInstall + ''; + + appendRunpaths = lib.makeLibraryPath [ + libGL + vulkan-loader + pciutils + ]; + + postFixup = '' + # replace bundled vulkan-loader since we are also already adding our own to RPATH + rm "$out/chrome-linux64/libvulkan.so.1" + ln -s -t "$out/chrome-linux64" "${lib.getLib vulkan-loader}/lib/libvulkan.so.1" + ''; + }; + chromium-darwin = fetchzip { + url = "https://cdn.playwright.dev/builds/chromium/${revision}/chromium-${suffix}.zip"; + stripRoot = false; + hash = + { + x86_64-darwin = "sha256-vQuBHM0jkk6S/Gco/bBqSPJqXi/CJt/+nkbGtFNpgwk="; + aarch64-darwin = "sha256-qXdgHeBS5IFIa4hZVmjq0+31v/uDPXHyc4aH7Wn2E7E="; + } + .${system} or throwSystem; + }; +in +{ + x86_64-linux = chromium-linux; + aarch64-linux = chromium-linux; + x86_64-darwin = chromium-darwin; + aarch64-darwin = chromium-darwin; +} +.${system} or throwSystem diff --git a/playwright-driver/default.nix b/playwright-driver/default.nix deleted file mode 100644 index 39a38d6..0000000 --- a/playwright-driver/default.nix +++ /dev/null @@ -1,198 +0,0 @@ -{ lib -, stdenv -, chromium -, ffmpeg -, git -, jq -, nodejs -, fetchFromGitHub -, fetchurl -, makeFontsConf -, makeWrapper -, runCommand -, unzip -, cacert -}: -let - inherit (stdenv.hostPlatform) system; - - throwSystem = throw "Unsupported system: ${system}"; - - driver = stdenv.mkDerivation (finalAttrs: - let - suffix = { - x86_64-linux = "linux"; - aarch64-linux = "linux-arm64"; - x86_64-darwin = "mac"; - aarch64-darwin = "mac-arm64"; - }.${system} or throwSystem; - filename = "playwright-${finalAttrs.version}-${suffix}.zip"; - in - { - pname = "playwright-driver"; - # run ./pkgs/development/python-modules/playwright/update.sh to update - version = "1.58.2"; - - src = fetchurl { - url = "https://cdn.playwright.dev/builds/driver/${filename}"; - sha256 = { - x86_64-linux = "1sszlwf18f5gbm97ph5vfll3j7c8syqxd1a8afw5cili1anyd12r"; - aarch64-linux = "05za0z6nnnksf9clfwzcmrxx46zz15q4mpq6nbrnc7f3hc86am3f"; - x86_64-darwin = "1837psp5vf9ickbx1w67x38zlz4isigazwlw85xwm4jd2wipfh74"; - aarch64-darwin = "0nwnx0sif1h0p13flnvhqqqwcvl6f4bx3gc899sdzzcz4hc5ckr2"; - }.${system} or throwSystem; - }; - - sourceRoot = "."; - - nativeBuildInputs = [ unzip ]; - - postPatch = '' - # Use Nix's NodeJS instead of the bundled one. - rm node - - patchShebangs package/bin/*.sh - ''; - - installPhase = '' - runHook preInstall - - mkdir -p $out/bin - # playwright.sh doesn't exist anymore, so we write a new one - cat > $out/bin/playwright < browser.json.tmp && mv browser.json.tmp packages/playwright-core/browsers.json + mkdir -p "$out/lib/node_modules/playwright-core" + cp -r packages/playwright-core/!(bundles|src|bin|.*) "$out/lib/node_modules/playwright-core" + + mkdir -p "$out/lib/node_modules/@playwright/test" + cp -r packages/playwright-test/* "$out/lib/node_modules/@playwright/test" + + runHook postInstall + ''; + + meta = { + description = "Framework for Web Testing and Automation"; + homepage = "https://playwright.dev"; + license = lib.licenses.asl20; + maintainers = with lib.maintainers; [ + kalekseev + marie + ]; + inherit (nodejs.meta) platforms; + }; + }; + + playwright-core = stdenv.mkDerivation (finalAttrs: { + pname = "playwright-core"; + inherit (playwright) version src meta; + + installPhase = '' + runHook preInstall + + cp -r ${playwright}/lib/node_modules/playwright-core "$out" + + runHook postInstall + ''; + + passthru = { + browsersJSON = (lib.importJSON ./browsers.json).browsers; + browsers = browsers { }; + browsers-chromium = browsers { + withFirefox = false; + withWebkit = false; + withChromiumHeadlessShell = false; + }; + inherit components; + }; + }); + + playwright-test = stdenv.mkDerivation (finalAttrs: { + pname = "playwright-test"; + inherit (playwright) version src; + + nativeBuildInputs = [ makeWrapper ]; + installPhase = '' + runHook preInstall + + shopt -s extglob + mkdir -p $out/bin + cp -r ${playwright}/* $out + + makeWrapper "${nodejs}/bin/node" "$out/bin/playwright" \ + --add-flags "$out/lib/node_modules/@playwright/test/cli.js" \ + --prefix NODE_PATH : ${placeholder "out"}/lib/node_modules \ + --set-default PLAYWRIGHT_BROWSERS_PATH "${playwright-core.passthru.browsers}" + + runHook postInstall + ''; + + meta = playwright.meta // { + mainProgram = "playwright"; + }; + }); + + components = { + chromium = callPackage ./chromium.nix { + inherit suffix system throwSystem; + inherit (playwright-core.passthru.browsersJSON.chromium) revision; + fontconfig_file = makeFontsConf { + fontDirectories = [ ]; + }; + }; + chromium-headless-shell = callPackage ./chromium-headless-shell.nix { + inherit suffix system throwSystem; + inherit (playwright-core.passthru.browsersJSON.chromium) revision; + }; + firefox = callPackage ./firefox.nix { + inherit suffix system throwSystem; + inherit (playwright-core.passthru.browsersJSON.firefox) revision; + }; + webkit = callPackage ./webkit.nix { + inherit suffix system throwSystem; + inherit (playwright-core.passthru.browsersJSON.webkit) revision; + }; + ffmpeg = callPackage ./ffmpeg.nix { + inherit suffix system throwSystem; + inherit (playwright-core.passthru.browsersJSON.ffmpeg) revision; + }; + }; + + browsers = lib.makeOverridable ( + { + withChromium ? true, + withFirefox ? true, + withWebkit ? true, # may require `export PLAYWRIGHT_HOST_PLATFORM_OVERRIDE="ubuntu-24.04"` + withFfmpeg ? true, + withChromiumHeadlessShell ? true, + fontconfig_file ? makeFontsConf { + fontDirectories = [ ]; + }, + }: + let + browsers = + lib.optionals withChromium [ "chromium" ] + ++ lib.optionals withChromiumHeadlessShell [ "chromium-headless-shell" ] + ++ lib.optionals withFirefox [ "firefox" ] + ++ lib.optionals withWebkit [ "webkit" ] + ++ lib.optionals withFfmpeg [ "ffmpeg" ]; + in + linkFarm "playwright-browsers" ( + lib.listToAttrs ( + map ( + name: + let + revName = if name == "chromium-headless-shell" then "chromium" else name; + value = playwright-core.passthru.browsersJSON.${revName}; + in + lib.nameValuePair + # TODO check platform for revisionOverrides + "${lib.replaceStrings [ "-" ] [ "_" ] name}-${value.revision}" + components.${name} + ) browsers + ) + ) + ); +in +{ + playwright-core = playwright-core; + playwright-test = playwright-test; +} diff --git a/playwright-driver/ffmpeg.nix b/playwright-driver/ffmpeg.nix new file mode 100644 index 0000000..8932b43 --- /dev/null +++ b/playwright-driver/ffmpeg.nix @@ -0,0 +1,19 @@ +{ + fetchzip, + suffix, + revision, + system, + throwSystem, +}: +fetchzip { + url = "https://cdn.playwright.dev/builds/ffmpeg/${revision}/ffmpeg-${suffix}.zip"; + stripRoot = false; + hash = + { + x86_64-linux = "sha256-AWTiui+ccKHxsIaQSgc5gWCJT5gYwIWzAEqSuKgVqZU="; + aarch64-linux = "sha256-1mOKO2lcnlwLsC6ob//xKnKrCOp94pw8X14uBxCdj0Q="; + x86_64-darwin = "sha256-zJ8BMzdneV6LlEt4I034l5u86dwW4UmO/UazWikpKV4="; + aarch64-darwin = "sha256-ky10UQj+XPVGpaWAPvKd51C5brml0y9xQ6iKcrxAMRc="; + } + .${system} or throwSystem; +} diff --git a/playwright-driver/firefox.nix b/playwright-driver/firefox.nix new file mode 100644 index 0000000..0f0855c --- /dev/null +++ b/playwright-driver/firefox.nix @@ -0,0 +1,56 @@ +{ + lib, + stdenv, + fetchzip, + firefox-bin, + suffix, + revision, + system, + throwSystem, +}: +let + firefox-linux = stdenv.mkDerivation { + name = "playwright-firefox"; + src = fetchzip { + url = "https://cdn.playwright.dev/builds/firefox/${revision}/firefox-${ + "ubuntu-22.04" + (lib.removePrefix "linux" suffix) + }.zip"; + hash = + { + x86_64-linux = "sha256-HBmCV6AFdQ2qTuCIa7WaCiSHU8Am7S+xhpmEWU6DL/U="; + aarch64-linux = "sha256-peP032z4GOoUp1WAszvzyeXnROw6RwRffG+KRe1Qf9k="; + } + .${system} or throwSystem; + }; + + inherit (firefox-bin.unwrapped) + nativeBuildInputs + buildInputs + runtimeDependencies + appendRunpaths + patchelfFlags + ; + + buildPhase = '' + mkdir -p $out/firefox + cp -R . $out/firefox + ''; + }; + firefox-darwin = fetchzip { + url = "https://cdn.playwright.dev/builds/firefox/${revision}/firefox-${suffix}.zip"; + stripRoot = false; + hash = + { + x86_64-darwin = "sha256-uxPOq2U1D9gFXqvNzclctLbHx4fZ9O92GtDQjCRYGiM="; + aarch64-darwin = "sha256-ZFRmtlNrzrjB3ELXmGC67XO1IhfWsWZ7rXaUQ6If65s="; + } + .${system} or throwSystem; + }; +in +{ + x86_64-linux = firefox-linux; + aarch64-linux = firefox-linux; + x86_64-darwin = firefox-darwin; + aarch64-darwin = firefox-darwin; +} +.${system} or throwSystem diff --git a/playwright-driver/webkit.nix b/playwright-driver/webkit.nix new file mode 100644 index 0000000..04b6f87 --- /dev/null +++ b/playwright-driver/webkit.nix @@ -0,0 +1,233 @@ +{ + lib, + stdenv, + fetchzip, + fetchFromGitHub, + makeWrapper, + autoPatchelfHook, + patchelfUnstable, + fetchpatch, + libjxl, + brotli, + at-spi2-atk, + cairo, + flite, + fontconfig, + freetype, + glib, + glib-networking, + gst_all_1, + harfbuzz, + harfbuzzFull, + icu70, + lcms, + libavif, + libdrm, + libepoxy, + libevent, + libgcc, + libgcrypt, + libgpg-error, + libjpeg8, + libopus, + libpng, + libsoup_3, + libtasn1, + libvpx, + libwebp, + libwpe, + libwpe-fdo, + libxkbcommon, + libxml2, + libxslt, + libgbm, + sqlite, + systemdLibs, + wayland-scanner, + woff2, + zlib, + suffix, + revision, + system, + throwSystem, +}: +let + suffix' = + if lib.hasPrefix "linux" suffix then + "ubuntu-22.04" + (lib.removePrefix "linux" suffix) + else if lib.hasPrefix "mac" suffix then + "mac-14" + (lib.removePrefix "mac" suffix) + else + suffix; + libvpx' = libvpx.overrideAttrs ( + finalAttrs: previousAttrs: { + version = "1.12.0"; + src = fetchFromGitHub { + owner = "webmproject"; + repo = finalAttrs.pname; + rev = "v${finalAttrs.version}"; + sha256 = "sha256-9SFFE2GfYYMgxp1dpmL3STTU2ea1R5vFKA1L0pZwIvQ="; + }; + } + ); + libavif' = libavif.overrideAttrs ( + finalAttrs: previousAttrs: { + version = "0.9.3"; + src = fetchFromGitHub { + owner = "AOMediaCodec"; + repo = finalAttrs.pname; + rev = "v${finalAttrs.version}"; + hash = "sha256-ME/mkaHhFeHajTbc7zhg9vtf/8XgkgSRu9I/mlQXnds="; + }; + postPatch = ""; + patches = [ ]; + } + ); + + libjxl' = libjxl.overrideAttrs ( + finalAttrs: previousAttrs: { + version = "0.8.2"; + src = fetchFromGitHub { + owner = "libjxl"; + repo = "libjxl"; + rev = "v${finalAttrs.version}"; + hash = "sha256-I3PGgh0XqRkCFz7lUZ3Q4eU0+0GwaQcVb6t4Pru1kKo="; + fetchSubmodules = true; + }; + patches = [ + # Add missing content to fix gcc compilation for RISCV architecture + # https://github.com/libjxl/libjxl/pull/2211 + (fetchpatch { + url = "https://github.com/libjxl/libjxl/commit/22d12d74e7bc56b09cfb1973aa89ec8d714fa3fc.patch"; + hash = "sha256-X4fbYTMS+kHfZRbeGzSdBW5jQKw8UN44FEyFRUtw0qo="; + }) + ]; + postPatch = '' + # Fix multiple definition errors by using C++17 instead of C++11 + substituteInPlace CMakeLists.txt \ + --replace "set(CMAKE_CXX_STANDARD 11)" "set(CMAKE_CXX_STANDARD 17)" + # Fix the build with CMake 4. + # See: + # * + # * + substituteInPlace third_party/sjpeg/CMakeLists.txt \ + --replace-fail \ + 'cmake_minimum_required(VERSION 2.8.7)' \ + 'cmake_minimum_required(VERSION 3.5...3.10)' + ''; + postInstall = ""; + + cmakeFlags = [ + "-DJPEGXL_FORCE_SYSTEM_BROTLI=ON" + "-DJPEGXL_FORCE_SYSTEM_HWY=ON" + "-DJPEGXL_FORCE_SYSTEM_GTEST=ON" + ] + ++ lib.optionals stdenv.hostPlatform.isStatic [ + "-DJPEGXL_STATIC=ON" + ] + ++ lib.optionals stdenv.hostPlatform.isAarch32 [ + "-DJPEGXL_FORCE_NEON=ON" + ]; + } + ); + webkit-linux = stdenv.mkDerivation { + name = "playwright-webkit"; + src = fetchzip { + url = "https://cdn.playwright.dev/builds/webkit/${revision}/webkit-${suffix'}.zip"; + stripRoot = false; + hash = + { + x86_64-linux = "sha256-h9dM6RR5WhUPHdZgn5yiJlM7QrhlDVaivnaHQCEZbXQ="; + aarch64-linux = "sha256-sOtPdOBmPLqApGGVhgH51OW3aoTv1Y40RfCSax7CyC4="; + } + .${system} or throwSystem; + }; + + nativeBuildInputs = [ + autoPatchelfHook + patchelfUnstable + makeWrapper + ]; + buildInputs = [ + at-spi2-atk + cairo + flite + fontconfig.lib + freetype + glib + brotli + libjxl' + gst_all_1.gst-plugins-bad + gst_all_1.gst-plugins-base + gst_all_1.gstreamer + harfbuzz + harfbuzzFull + icu70 + lcms + libavif' + libdrm + libepoxy + libevent + libgcc.lib + libgcrypt + libgpg-error + libjpeg8 + libopus + libpng + libsoup_3 + libtasn1 + libwebp + libwpe + libwpe-fdo + libvpx' + libxml2 + libxslt + libgbm + sqlite + systemdLibs + wayland-scanner + woff2.lib + libxkbcommon + zlib + ]; + + patchelfFlags = [ "--no-clobber-old-sections" ]; + buildPhase = '' + cp -R . $out + + # remove unused gtk browser + rm -rf $out/minibrowser-gtk + # remove bundled libs + rm -rf $out/minibrowser-wpe/sys + + # TODO: still fails on ubuntu trying to find libEGL_mesa.so.0 + wrapProgram $out/minibrowser-wpe/bin/MiniBrowser \ + --prefix GIO_EXTRA_MODULES ":" "${glib-networking}/lib/gio/modules/" \ + --prefix LD_LIBRARY_PATH ":" $out/minibrowser-wpe/lib + + ''; + + preFixup = '' + # Fix libxml2 breakage. See https://github.com/NixOS/nixpkgs/pull/396195#issuecomment-2881757108 + mkdir -p "$out/lib" + ln -s "${lib.getLib libxml2}/lib/libxml2.so" "$out/lib/libxml2.so.2" + ''; + }; + webkit-darwin = fetchzip { + url = "https://cdn.playwright.dev/builds/webkit/${revision}/webkit-${suffix'}.zip"; + stripRoot = false; + hash = + { + x86_64-darwin = "sha256-CC/ByUmh4b5jC+6weTqSS4mY22du1xLIO4fBkFVvfDs="; + aarch64-darwin = "sha256-+y7Ftu7LSM7fpP2b6ycrhGvcIWu5q1W8hcrbn4mhVT8="; + } + .${system} or throwSystem; + }; +in +{ + x86_64-linux = webkit-linux; + aarch64-linux = webkit-linux; + x86_64-darwin = webkit-darwin; + aarch64-darwin = webkit-darwin; +} +.${system} or throwSystem diff --git a/playwright-test/default.nix b/playwright-test/default.nix deleted file mode 100644 index 61a274c..0000000 --- a/playwright-test/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -# This file has been generated by node2nix 1.11.1. Do not edit! - -{pkgs ? import { - inherit system; - }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs_14"}: - -let - nodeEnv = import ./node-env.nix { - inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript; - inherit pkgs nodejs; - libtool = if pkgs.stdenv.isDarwin then pkgs.cctools or pkgs.darwin.cctools else null; - }; -in -import ./node-packages.nix { - inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit; - inherit nodeEnv; -} diff --git a/playwright-test/node-env.nix b/playwright-test/node-env.nix deleted file mode 100644 index 3fab04f..0000000 --- a/playwright-test/node-env.nix +++ /dev/null @@ -1,689 +0,0 @@ -# This file originates from node2nix - -{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile, writeShellScript}: - -let - # Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master - utillinux = if pkgs ? util-linux then pkgs.util-linux else pkgs.utillinux; - - python = if nodejs ? python then nodejs.python else python2; - - # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise - tarWrapper = runCommand "tarWrapper" {} '' - mkdir -p $out/bin - - cat > $out/bin/tar <> $out/nix-support/hydra-build-products - ''; - }; - - # Common shell logic - installPackage = writeShellScript "install-package" '' - installPackage() { - local packageName=$1 src=$2 - - local strippedName - - local DIR=$PWD - cd $TMPDIR - - unpackFile $src - - # Make the base dir in which the target dependency resides first - mkdir -p "$(dirname "$DIR/$packageName")" - - if [ -f "$src" ] - then - # Figure out what directory has been unpacked - packageDir="$(find . -maxdepth 1 -type d | tail -1)" - - # Restore write permissions to make building work - find "$packageDir" -type d -exec chmod u+x {} \; - chmod -R u+w "$packageDir" - - # Move the extracted tarball into the output folder - mv "$packageDir" "$DIR/$packageName" - elif [ -d "$src" ] - then - # Get a stripped name (without hash) of the source directory. - # On old nixpkgs it's already set internally. - if [ -z "$strippedName" ] - then - strippedName="$(stripHash $src)" - fi - - # Restore write permissions to make building work - chmod -R u+w "$strippedName" - - # Move the extracted directory into the output folder - mv "$strippedName" "$DIR/$packageName" - fi - - # Change to the package directory to install dependencies - cd "$DIR/$packageName" - } - ''; - - # Bundle the dependencies of the package - # - # Only include dependencies if they don't exist. They may also be bundled in the package. - includeDependencies = {dependencies}: - lib.optionalString (dependencies != []) ( - '' - mkdir -p node_modules - cd node_modules - '' - + (lib.concatMapStrings (dependency: - '' - if [ ! -e "${dependency.packageName}" ]; then - ${composePackage dependency} - fi - '' - ) dependencies) - + '' - cd .. - '' - ); - - # Recursively composes the dependencies of a package - composePackage = { name, packageName, src, dependencies ? [], ... }@args: - builtins.addErrorContext "while evaluating node package '${packageName}'" '' - installPackage "${packageName}" "${src}" - ${includeDependencies { inherit dependencies; }} - cd .. - ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} - ''; - - pinpointDependencies = {dependencies, production}: - let - pinpointDependenciesFromPackageJSON = writeTextFile { - name = "pinpointDependencies.js"; - text = '' - var fs = require('fs'); - var path = require('path'); - - function resolveDependencyVersion(location, name) { - if(location == process.env['NIX_STORE']) { - return null; - } else { - var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json"); - - if(fs.existsSync(dependencyPackageJSON)) { - var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON)); - - if(dependencyPackageObj.name == name) { - return dependencyPackageObj.version; - } - } else { - return resolveDependencyVersion(path.resolve(location, ".."), name); - } - } - } - - function replaceDependencies(dependencies) { - if(typeof dependencies == "object" && dependencies !== null) { - for(var dependency in dependencies) { - var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency); - - if(resolvedVersion === null) { - process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n"); - } else { - dependencies[dependency] = resolvedVersion; - } - } - } - } - - /* Read the package.json configuration */ - var packageObj = JSON.parse(fs.readFileSync('./package.json')); - - /* Pinpoint all dependencies */ - replaceDependencies(packageObj.dependencies); - if(process.argv[2] == "development") { - replaceDependencies(packageObj.devDependencies); - } - else { - packageObj.devDependencies = {}; - } - replaceDependencies(packageObj.optionalDependencies); - replaceDependencies(packageObj.peerDependencies); - - /* Write the fixed package.json file */ - fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2)); - ''; - }; - in - '' - node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"} - - ${lib.optionalString (dependencies != []) - '' - if [ -d node_modules ] - then - cd node_modules - ${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies} - cd .. - fi - ''} - ''; - - # Recursively traverses all dependencies of a package and pinpoints all - # dependencies in the package.json file to the versions that are actually - # being used. - - pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args: - '' - if [ -d "${packageName}" ] - then - cd "${packageName}" - ${pinpointDependencies { inherit dependencies production; }} - cd .. - ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} - fi - ''; - - # Extract the Node.js source code which is used to compile packages with - # native bindings - nodeSources = runCommand "node-sources" {} '' - tar --no-same-owner --no-same-permissions -xf ${nodejs.src} - mv node-* $out - ''; - - # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty) - addIntegrityFieldsScript = writeTextFile { - name = "addintegrityfields.js"; - text = '' - var fs = require('fs'); - var path = require('path'); - - function augmentDependencies(baseDir, dependencies) { - for(var dependencyName in dependencies) { - var dependency = dependencies[dependencyName]; - - // Open package.json and augment metadata fields - var packageJSONDir = path.join(baseDir, "node_modules", dependencyName); - var packageJSONPath = path.join(packageJSONDir, "package.json"); - - if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored - console.log("Adding metadata fields to: "+packageJSONPath); - var packageObj = JSON.parse(fs.readFileSync(packageJSONPath)); - - if(dependency.integrity) { - packageObj["_integrity"] = dependency.integrity; - } else { - packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads. - } - - if(dependency.resolved) { - packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided - } else { - packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories. - } - - if(dependency.from !== undefined) { // Adopt from property if one has been provided - packageObj["_from"] = dependency.from; - } - - fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2)); - } - - // Augment transitive dependencies - if(dependency.dependencies !== undefined) { - augmentDependencies(packageJSONDir, dependency.dependencies); - } - } - } - - if(fs.existsSync("./package-lock.json")) { - var packageLock = JSON.parse(fs.readFileSync("./package-lock.json")); - - if(![1, 2].includes(packageLock.lockfileVersion)) { - process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n"); - process.exit(1); - } - - if(packageLock.dependencies !== undefined) { - augmentDependencies(".", packageLock.dependencies); - } - } - ''; - }; - - # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes - reconstructPackageLock = writeTextFile { - name = "reconstructpackagelock.js"; - text = '' - var fs = require('fs'); - var path = require('path'); - - var packageObj = JSON.parse(fs.readFileSync("package.json")); - - var lockObj = { - name: packageObj.name, - version: packageObj.version, - lockfileVersion: 2, - requires: true, - packages: { - "": { - name: packageObj.name, - version: packageObj.version, - license: packageObj.license, - bin: packageObj.bin, - dependencies: packageObj.dependencies, - engines: packageObj.engines, - optionalDependencies: packageObj.optionalDependencies - } - }, - dependencies: {} - }; - - function augmentPackageJSON(filePath, packages, dependencies) { - var packageJSON = path.join(filePath, "package.json"); - if(fs.existsSync(packageJSON)) { - var packageObj = JSON.parse(fs.readFileSync(packageJSON)); - packages[filePath] = { - version: packageObj.version, - integrity: "sha1-000000000000000000000000000=", - dependencies: packageObj.dependencies, - engines: packageObj.engines, - optionalDependencies: packageObj.optionalDependencies - }; - dependencies[packageObj.name] = { - version: packageObj.version, - integrity: "sha1-000000000000000000000000000=", - dependencies: {} - }; - processDependencies(path.join(filePath, "node_modules"), packages, dependencies[packageObj.name].dependencies); - } - } - - function processDependencies(dir, packages, dependencies) { - if(fs.existsSync(dir)) { - var files = fs.readdirSync(dir); - - files.forEach(function(entry) { - var filePath = path.join(dir, entry); - var stats = fs.statSync(filePath); - - if(stats.isDirectory()) { - if(entry.substr(0, 1) == "@") { - // When we encounter a namespace folder, augment all packages belonging to the scope - var pkgFiles = fs.readdirSync(filePath); - - pkgFiles.forEach(function(entry) { - if(stats.isDirectory()) { - var pkgFilePath = path.join(filePath, entry); - augmentPackageJSON(pkgFilePath, packages, dependencies); - } - }); - } else { - augmentPackageJSON(filePath, packages, dependencies); - } - } - }); - } - } - - processDependencies("node_modules", lockObj.packages, lockObj.dependencies); - - fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2)); - ''; - }; - - # Script that links bins defined in package.json to the node_modules bin directory - # NPM does not do this for top-level packages itself anymore as of v7 - linkBinsScript = writeTextFile { - name = "linkbins.js"; - text = '' - var fs = require('fs'); - var path = require('path'); - - var packageObj = JSON.parse(fs.readFileSync("package.json")); - - var nodeModules = Array(packageObj.name.split("/").length).fill("..").join(path.sep); - - if(packageObj.bin !== undefined) { - fs.mkdirSync(path.join(nodeModules, ".bin")) - - if(typeof packageObj.bin == "object") { - Object.keys(packageObj.bin).forEach(function(exe) { - if(fs.existsSync(packageObj.bin[exe])) { - console.log("linking bin '" + exe + "'"); - fs.symlinkSync( - path.join("..", packageObj.name, packageObj.bin[exe]), - path.join(nodeModules, ".bin", exe) - ); - } - else { - console.log("skipping non-existent bin '" + exe + "'"); - } - }) - } - else { - if(fs.existsSync(packageObj.bin)) { - console.log("linking bin '" + packageObj.bin + "'"); - fs.symlinkSync( - path.join("..", packageObj.name, packageObj.bin), - path.join(nodeModules, ".bin", packageObj.name.split("/").pop()) - ); - } - else { - console.log("skipping non-existent bin '" + packageObj.bin + "'"); - } - } - } - else if(packageObj.directories !== undefined && packageObj.directories.bin !== undefined) { - fs.mkdirSync(path.join(nodeModules, ".bin")) - - fs.readdirSync(packageObj.directories.bin).forEach(function(exe) { - if(fs.existsSync(path.join(packageObj.directories.bin, exe))) { - console.log("linking bin '" + exe + "'"); - fs.symlinkSync( - path.join("..", packageObj.name, packageObj.directories.bin, exe), - path.join(nodeModules, ".bin", exe) - ); - } - else { - console.log("skipping non-existent bin '" + exe + "'"); - } - }) - } - ''; - }; - - prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}: - let - forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com"; - in - '' - # Pinpoint the versions of all dependencies to the ones that are actually being used - echo "pinpointing versions of dependencies..." - source $pinpointDependenciesScriptPath - - # Patch the shebangs of the bundled modules to prevent them from - # calling executables outside the Nix store as much as possible - patchShebangs . - - # Deploy the Node.js package by running npm install. Since the - # dependencies have been provided already by ourselves, it should not - # attempt to install them again, which is good, because we want to make - # it Nix's responsibility. If it needs to install any dependencies - # anyway (e.g. because the dependency parameters are - # incomplete/incorrect), it fails. - # - # The other responsibilities of NPM are kept -- version checks, build - # steps, postprocessing etc. - - export HOME=$TMPDIR - cd "${packageName}" - runHook preRebuild - - ${lib.optionalString bypassCache '' - ${lib.optionalString reconstructLock '' - if [ -f package-lock.json ] - then - echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!" - echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!" - rm package-lock.json - else - echo "No package-lock.json file found, reconstructing..." - fi - - node ${reconstructPackageLock} - ''} - - node ${addIntegrityFieldsScript} - ''} - - npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild - - runHook postRebuild - - if [ "''${dontNpmInstall-}" != "1" ] - then - # NPM tries to download packages even when they already exist if npm-shrinkwrap is used. - rm -f npm-shrinkwrap.json - - npm ${forceOfflineFlag} --nodedir=${nodeSources} --no-bin-links --ignore-scripts ${npmFlags} ${lib.optionalString production "--production"} install - fi - - # Link executables defined in package.json - node ${linkBinsScript} - ''; - - # Builds and composes an NPM package including all its dependencies - buildNodePackage = - { name - , packageName - , version ? null - , dependencies ? [] - , buildInputs ? [] - , production ? true - , npmFlags ? "" - , dontNpmInstall ? false - , bypassCache ? false - , reconstructLock ? false - , preRebuild ? "" - , dontStrip ? true - , unpackPhase ? "true" - , buildPhase ? "true" - , meta ? {} - , ... }@args: - - let - extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ]; - in - stdenv.mkDerivation ({ - name = "${name}${if version == null then "" else "-${version}"}"; - buildInputs = [ tarWrapper python nodejs ] - ++ lib.optional (stdenv.isLinux) utillinux - ++ lib.optional (stdenv.isDarwin) libtool - ++ buildInputs; - - inherit nodejs; - - inherit dontStrip; # Stripping may fail a build for some package deployments - inherit dontNpmInstall preRebuild unpackPhase buildPhase; - - compositionScript = composePackage args; - pinpointDependenciesScript = pinpointDependenciesOfPackage args; - - passAsFile = [ "compositionScript" "pinpointDependenciesScript" ]; - - installPhase = '' - source ${installPackage} - - # Create and enter a root node_modules/ folder - mkdir -p $out/lib/node_modules - cd $out/lib/node_modules - - # Compose the package and all its dependencies - source $compositionScriptPath - - ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }} - - # Create symlink to the deployed executable folder, if applicable - if [ -d "$out/lib/node_modules/.bin" ] - then - ln -s $out/lib/node_modules/.bin $out/bin - - # Fixup all executables - ls $out/bin/* | while read i - do - file="$(readlink -f "$i")" - chmod u+rwx "$file" - if isScript "$file" - then - sed -i 's/\r$//' "$file" # convert crlf to lf - fi - done - fi - - # Create symlinks to the deployed manual page folders, if applicable - if [ -d "$out/lib/node_modules/${packageName}/man" ] - then - mkdir -p $out/share - for dir in "$out/lib/node_modules/${packageName}/man/"* - do - mkdir -p $out/share/man/$(basename "$dir") - for page in "$dir"/* - do - ln -s $page $out/share/man/$(basename "$dir") - done - done - fi - - # Run post install hook, if provided - runHook postInstall - ''; - - meta = { - # default to Node.js' platforms - platforms = nodejs.meta.platforms; - } // meta; - } // extraArgs); - - # Builds a node environment (a node_modules folder and a set of binaries) - buildNodeDependencies = - { name - , packageName - , version ? null - , src - , dependencies ? [] - , buildInputs ? [] - , production ? true - , npmFlags ? "" - , dontNpmInstall ? false - , bypassCache ? false - , reconstructLock ? false - , dontStrip ? true - , unpackPhase ? "true" - , buildPhase ? "true" - , ... }@args: - - let - extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ]; - in - stdenv.mkDerivation ({ - name = "node-dependencies-${name}${if version == null then "" else "-${version}"}"; - - buildInputs = [ tarWrapper python nodejs ] - ++ lib.optional (stdenv.isLinux) utillinux - ++ lib.optional (stdenv.isDarwin) libtool - ++ buildInputs; - - inherit dontStrip; # Stripping may fail a build for some package deployments - inherit dontNpmInstall unpackPhase buildPhase; - - includeScript = includeDependencies { inherit dependencies; }; - pinpointDependenciesScript = pinpointDependenciesOfPackage args; - - passAsFile = [ "includeScript" "pinpointDependenciesScript" ]; - - installPhase = '' - source ${installPackage} - - mkdir -p $out/${packageName} - cd $out/${packageName} - - source $includeScriptPath - - # Create fake package.json to make the npm commands work properly - cp ${src}/package.json . - chmod 644 package.json - ${lib.optionalString bypassCache '' - if [ -f ${src}/package-lock.json ] - then - cp ${src}/package-lock.json . - chmod 644 package-lock.json - fi - ''} - - # Go to the parent folder to make sure that all packages are pinpointed - cd .. - ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} - - ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }} - - # Expose the executables that were installed - cd .. - ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} - - mv ${packageName} lib - ln -s $out/lib/node_modules/.bin $out/bin - ''; - } // extraArgs); - - # Builds a development shell - buildNodeShell = - { name - , packageName - , version ? null - , src - , dependencies ? [] - , buildInputs ? [] - , production ? true - , npmFlags ? "" - , dontNpmInstall ? false - , bypassCache ? false - , reconstructLock ? false - , dontStrip ? true - , unpackPhase ? "true" - , buildPhase ? "true" - , ... }@args: - - let - nodeDependencies = buildNodeDependencies args; - extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "unpackPhase" "buildPhase" ]; - in - stdenv.mkDerivation ({ - name = "node-shell-${name}${if version == null then "" else "-${version}"}"; - - buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs; - buildCommand = '' - mkdir -p $out/bin - cat > $out/bin/shell < "$root/version.txt" - -# Check if files have changed -if git diff --exit-code; then - echo "No changes" - echo "updated=false" > updated.txt - exit 0 -fi +prefetch_browser() { + local url="$1" + local strip_root="$2" + + # nix-prefetch is used to obtain sha with `stripRoot = false` + # doesn't work on macOS https://github.com/msteen/nix-prefetch/issues/53 + nix-prefetch --option extra-experimental-features flakes -q "{ stdenv, fetchzip }: stdenv.mkDerivation { name=\"browser\"; src = fetchzip { url = \"$url\"; stripRoot = $strip_root; }; }" +} + +browser_download_url() { + local name="$1" + local buildname="$2" + local platform="$3" + local arch="$4" + local revision="$5" + local browser_version="$6" + local suffix="$7" + local artifact + local cft_platform + + # Chromium and chromium-headless-shell use Chrome for Testing artifacts on + # Linux/macOS on x86_64 and aarch64-darwin. + if [ "$name" = "chromium" ] || [ "$name" = "chromium-headless-shell" ]; then + if [ "$name" = "chromium" ]; then + artifact="chrome" + else + artifact="chrome-headless-shell" + fi + + if [ "$platform" = "linux" ] && [ "$arch" = "x86_64" ]; then + echo "https://cdn.playwright.dev/chrome-for-testing-public/${browser_version}/linux64/${artifact}-linux64.zip" + return + fi + + if [ "$platform" = "darwin" ]; then + if [ "$arch" = "x86_64" ]; then + cft_platform="mac-x64" + else + cft_platform="mac-arm64" + fi + echo "https://cdn.playwright.dev/chrome-for-testing-public/${browser_version}/${cft_platform}/${artifact}-${cft_platform}.zip" + return + fi + fi + + echo "https://cdn.playwright.dev/dbazure/download/playwright/builds/${buildname}/${revision}/${name}-${suffix}.zip" +} + +update_browser() { + local name="$1" + local platform="$2" + local stripRoot="false" + local suffix + local aarch64_suffix + local buildname + local revision + local browser_version + local x86_64_url + local aarch64_url + + if [ "$platform" = "darwin" ]; then + if [ "$name" = "webkit" ]; then + suffix="mac-14" + else + suffix="mac" + fi + else + if [ "$name" = "ffmpeg" ] || [ "$name" = "chromium-headless-shell" ]; then + suffix="linux" + elif [ "$name" = "chromium" ]; then + stripRoot="true" + suffix="linux" + elif [ "$name" = "firefox" ]; then + stripRoot="true" + suffix="ubuntu-22.04" + else + suffix="ubuntu-22.04" + fi + fi + aarch64_suffix="$suffix-arm64" + if [ "$name" = "chromium-headless-shell" ]; then + buildname="chromium" + else + buildname="$name" + fi + + revision="$(jq -r ".browsers[\"$buildname\"].revision" "$playwright_browsers_file")" + browser_version="$(jq -r ".browsers[\"$buildname\"].browserVersion // empty" "$playwright_browsers_file")" + x86_64_url="$(browser_download_url "$name" "$buildname" "$platform" "x86_64" "$revision" "$browser_version" "$suffix")" + aarch64_url="$(browser_download_url "$name" "$buildname" "$platform" "aarch64" "$revision" "$browser_version" "$aarch64_suffix")" + replace_sha "$root/playwright-driver/$name.nix" "x86_64-$platform" \ + "$(prefetch_browser "$x86_64_url" "$stripRoot")" + replace_sha "$root/playwright-driver/$name.nix" "aarch64-$platform" \ + "$(prefetch_browser "$aarch64_url" "$stripRoot")" +} + +curl -fsSL \ + "https://raw.githubusercontent.com/microsoft/playwright/v${driver_version}/packages/playwright-core/browsers.json" \ + | jq ' + .comment = "This file is kept up to date via update.sh" + | .browsers |= ( + [.[] + | select(.installByDefault) | del(.installByDefault)] + | map({(.name): . | del(.name)}) + | add + ) + ' > "$playwright_browsers_file" + +for platform in "${browser_platforms[@]}"; do + for browser in "${browser_names[@]}"; do + update_browser "$browser" "$platform" + done +done + +# Update package-lock.json files for all npm deps that are built in playwright + +# Download `package-lock.json` for a given sourceRoot path and update its hash. +update_hash() { + local source_root_path="$1" + local download_url + local lock_file + local new_hash + local source_root_pattern + + download_url="${playwright_raw_repo_url}/v${driver_version}${source_root_path}/package-lock.json" + lock_file="${temp_dir}/$(echo "$source_root_path" | tr '/.' '__').package-lock.json" + curl -fsSL -o "$lock_file" "$download_url" + new_hash=$(prefetch-npm-deps "$lock_file") + + source_root_pattern=$(printf '%s\n' "$source_root_path" | sed 's/[][\\/.*^$+?(){}|]/\\&/g') + sed -E -i "/sourceRoot = \"\\\$\\{src.name\\}${source_root_pattern}\";/,/npmDepsHash = / s#npmDepsHash = \"[^\"]*\";#npmDepsHash = \"${new_hash}\";#" "$playwright_driver_file" +} -# Update the node-packages.json -(cd "$playwright_test"; node2nix -i node-packages.json) -echo "updated=true" > updated.txt +while IFS= read -r source_root_path; do + update_hash "$source_root_path" +done < <( + # shellcheck disable=SC2016 + sed -n 's#^[[:space:]]*sourceRoot = "${src.name}\(.*\)";.*$#\1#p' "$playwright_driver_file" +)