Unverified Commit 01d57709 authored by Doron Behar's avatar Doron Behar Committed by GitHub
Browse files

Merge pull request #290715 from Scrumplex/pkgs/build-support/fetchPnpmDeps

pnpm.fetchDeps: init
parents 046fa573 c704c029
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -310,6 +310,71 @@ See `node2nix` [docs](https://github.com/svanderburg/node2nix) for more info.
- `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`.
- `node2nix` does not like missing packages from npm. If you see something like `Cannot resolve version: vue-loader-v16@undefined` then you might want to try another tool. The package might have been pulled off of npm.

### pnpm {#javascript-pnpm}

Pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8` and `pnpm_9`, which support different sets of lock file versions.

When packaging an application that includes a `pnpm-lock.yaml`, you need to fetch the pnpm store for that project using a fixed-output-derivation. The functions `pnpm_8.fetchDeps` and `pnpm_9.fetchDeps` can create this pnpm store derivation. In conjunction, the setup hooks `pnpm_8.configHook` and `pnpm_9.configHook` will prepare the build environment to install the prefetched dependencies store. Here is an example for a package that contains a `package.json` and a `pnpm-lock.yaml` files using the above `pnpm_` attributes:

```nix
{
  stdenv,
  nodejs,
  # This is pinned as { pnpm = pnpm_9; }
  pnpm
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "foo";
  version = "0-unstable-1980-01-01";

  src = ...;

  nativeBuildInputs = [
    nodejs
    pnpm.configHook
  ];

  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pname version src;
    hash = "...";
  };
})
```

NOTE: It is highly recommended to use a pinned version of pnpm (i.e. `pnpm_8` or `pnpm_9`), to increase future reproducibility. It might also be required to use an older version, if the package needs support for a certain lock file version.

In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass `finalAttrs.patches` to the function as well (i.e. `inherit (finalAttrs) patches`.

#### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot}

NOTE: Nixpkgs pnpm tooling doesn't support building projects with a `pnpm-workspace.yaml`, or building monorepos. It maybe possible to use `pnpm.fetchDeps` for these projects, but it may be hard or impossible to produce a binary from such projects ([an example attempt](https://github.com/NixOS/nixpkgs/pull/290715#issuecomment-2144543728)).

If the pnpm project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`. Note, that projects using `pnpm-workspace.yaml` are currently not supported, and will probably not work using this approach.
If `sourceRoot` is different between the parent derivation and `fetchDeps`, you will have to set `pnpmRoot` to effectively be the same location as it is in `fetchDeps`.

Assuming the following directory structure, we can define `sourceRoot` and `pnpmRoot` as follows:

```
.
├── frontend
│   ├── ...
│   ├── package.json
│   └── pnpm-lock.yaml
└── ...
```

```nix
  ...
  pnpmDeps = pnpm.fetchDeps {
    ...
    sourceRoot = "${finalAttrs.src.name}/frontend";
  };

  # by default the working directory is the extracted source
  pnpmRoot = "frontend";
```

### yarn2nix {#javascript-yarn2nix}

#### Preparation {#javascript-yarn2nix-preparation}
+6 −46
Original line number Diff line number Diff line
@@ -4,12 +4,9 @@
, electron
, python3
, stdenv
, stdenvNoCC
, copyDesktopItems
, moreutils
, cacert
, jq
, nodePackages
, nodejs
, pnpm
, makeDesktopItem
}:

@@ -24,54 +21,17 @@ stdenv.mkDerivation (finalAttrs: {
    hash = "sha256-nxpctEG4XoxW6jOAxGdgTEYr6YnhFRR8+5HUQLxRJB0=";
  };

  pnpmDeps = stdenvNoCC.mkDerivation {
    pname = "${finalAttrs.pname}-pnpm-deps";
    inherit (finalAttrs) src version ELECTRON_SKIP_BINARY_DOWNLOAD;

    nativeBuildInputs = [ jq moreutils nodePackages.pnpm cacert ];

    installPhase = ''
      export HOME=$(mktemp -d)

      pnpm config set store-dir $out
      pnpm install --frozen-lockfile --ignore-script

      rm -rf $out/v3/tmp
      for f in $(find $out -name "*.json"); do
        sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
        jq --sort-keys . $f | sponge $f
      done
    '';

    dontBuild = true;
    dontFixup = true;
    outputHashMode = "recursive";
    outputHash = {
      x86_64-linux = "sha256-bujlQxP6Lr3qPUDxYXKyb702ZJY/xbuCsu3wVDhcb+8=";
      aarch64-linux = "sha256-0kyjjttpXpFVhdza5NAjGrRn++qc/N5/u2dQl7VufLE=";
      x86_64-darwin = "sha256-Q37QJt/mhfpSguOlkJGKFTCrIOrpbG3OBwaD/Bg09Us=";
      aarch64-darwin = "sha256-wbfjzoGa/6vIlOOVX3bKNQ2uxzph3WSofo3MGXqA6yQ=";
    }.${stdenv.system} or (throw "Unsupported system: ${stdenv.system}");
  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pname version src;
    hash = "sha256-8oeloQYiwUy+GDG4R+XtiynT+8Fad4WYFWTO1KANZKQ=";
  };

  nativeBuildInputs = [ makeWrapper python3 nodePackages.pnpm nodePackages.nodejs ]
  nativeBuildInputs = [ makeWrapper python3 nodejs pnpm.configHook ]
    ++ lib.optionals (!stdenv.isDarwin) [ copyDesktopItems ];


  ELECTRON_SKIP_BINARY_DOWNLOAD = 1;

  preBuild = ''
    export HOME=$(mktemp -d)
    export STORE_PATH=$(mktemp -d)

    cp -Tr "$pnpmDeps" "$STORE_PATH"
    chmod -R +w "$STORE_PATH"

    pnpm config set store-dir "$STORE_PATH"
    pnpm install --offline --frozen-lockfile --ignore-script
    patchShebangs node_modules/{*,.*}
  '';

  postBuild = lib.optionalString stdenv.isDarwin ''
    cp -R ${electron}/Applications/Electron.app Electron.app
    chmod -R u+w Electron.app
+19 −45
Original line number Diff line number Diff line
@@ -4,7 +4,8 @@
, fetchFromGitHub
, buildGoModule
, makeWrapper
, nodePackages
, nodejs
, pnpm
, cacert
, esbuild
, jq
@@ -48,7 +49,7 @@ in
    };
  };

  gui = stdenvNoCC.mkDerivation rec {
  gui = stdenvNoCC.mkDerivation (finalAttrs: {
    pname = "geph-gui";
    inherit version;

@@ -60,42 +61,11 @@ in
      fetchSubmodules = true;
    };

    pnpm-deps = stdenvNoCC.mkDerivation {
      pname = "${pname}-pnpm-deps";
      inherit src version;

      sourceRoot = "${src.name}/gephgui-wry/gephgui";

      nativeBuildInputs = [
        jq
        moreutils
        nodePackages.pnpm
        cacert
      ];

      installPhase = ''
        export HOME=$(mktemp -d)
        pnpm config set store-dir $out
        pnpm install --ignore-scripts

        # Remove timestamp and sort the json files
        rm -rf $out/v3/tmp
        for f in $(find $out -name "*.json"); do
          sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
          jq --sort-keys . $f | sponge $f
        done
      '';

      dontFixup = true;
      outputHashMode = "recursive";
      outputHash = "sha256-OKPx5xRI7DWd6m31nYx1biP0k6pcZ7fq7dfVlHda4O0=";
    };

    gephgui-wry = rustPlatform.buildRustPackage {
      pname = "gephgui-wry";
      inherit version src;
      inherit (finalAttrs) version src;

      sourceRoot = "${src.name}/gephgui-wry";
      sourceRoot = "${finalAttrs.src.name}/gephgui-wry";

      cargoLock = {
        lockFile = ./Cargo.lock;
@@ -105,10 +75,17 @@ in
        };
      };

      pnpmDeps = pnpm.fetchDeps {
        inherit (finalAttrs) pname version src;
        sourceRoot = "${finalAttrs.src.name}/gephgui-wry/gephgui";
        hash = "sha256-0MGlsLEgugQ1wEz07ROIwkanTa8PSKwIaxNahyS1014=";
      };

      nativeBuildInputs = [
        pkg-config
        nodePackages.pnpm
        pnpm.configHook
        makeWrapper
        nodejs
      ];

      buildInputs = [
@@ -132,22 +109,19 @@ in
        });
      })}";

      pnpmRoot = "gephgui";

      preBuild = ''
        cd gephgui
        export HOME=$(mktemp -d)
        pnpm config set store-dir ${pnpm-deps}
        pnpm install --ignore-scripts --offline
        chmod -R +w node_modules
        pnpm rebuild
        pushd gephgui
        pnpm build
        cd ..
        popd
      '';
    };

    dontBuild = true;

    installPhase = ''
      install -Dt $out/bin ${gephgui-wry}/bin/gephgui-wry
      install -Dt $out/bin ${finalAttrs.gephgui-wry}/bin/gephgui-wry
      install -d $out/share/icons/hicolor
      for i in '16' '32' '64' '128' '256'
      do
@@ -163,5 +137,5 @@ in
    meta = geph-meta // {
      license = with lib.licenses; [ unfree ];
    };
  };
  });
}
+10 −50
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@
, fetchFromGitHub
, copyDesktopItems
, stdenv
, stdenvNoCC
, rustc
, rustPlatform
, cargo
@@ -12,20 +11,18 @@
, webkitgtk
, pkg-config
, makeDesktopItem
, jq
, moreutils
, nodePackages
, cacert
, pnpm
, nodejs
}:

stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
  pname = "kiwitalk";
  version = "0.5.1";

  src = fetchFromGitHub {
    owner = "KiwiTalk";
    repo = "KiwiTalk";
    rev = "v${version}";
    rev = "v${finalAttrs.version}";
    hash = "sha256-Th8q+Zbc102fIk2v7O3OOeSriUV/ydz60QwxzmS7AY8=";
  };

@@ -34,43 +31,9 @@ stdenv.mkDerivation rec {
      --replace "libayatana-appindicator3.so.1" "${libayatana-appindicator}/lib/libayatana-appindicator3.so.1"
  '';

  pnpm-deps = stdenvNoCC.mkDerivation {
    pname = "${pname}-pnpm-deps";
    inherit src version;

    nativeBuildInputs = [
      jq
      moreutils
      nodePackages.pnpm
      cacert
    ];

    installPhase = ''
      export HOME=$(mktemp -d)
      pnpm config set store-dir $out
      # This version of the package has different versions of esbuild as a dependency.
      # You can use the command below to get esbuild binaries for a specific platform and calculate hashes for that platforms. (linux, darwin for os, and x86, arm64, ia32 for cpu)
      # cat package.json | jq '.pnpm.supportedArchitectures += { "os": ["linux"], "cpu": ["arm64"] }' | sponge package.json
      pnpm install --frozen-lockfile --ignore-script

      # Remove timestamp and sort the json files.
      rm -rf $out/v3/tmp
      for f in $(find $out -name "*.json"); do
        sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
        jq --sort-keys . $f | sponge $f
      done
    '';

    dontBuild = true;
    dontFixup = true;
    outputHashMode = "recursive";
    outputHash = {
      x86_64-linux = "sha256-LJPjWNpVfdUu8F5BMhAzpTo/h6ax7lxY2EESHj5P390=";
      aarch64-linux = "sha256-N1K4pV5rbWmO/KonvYegzBoWa6TYQIqhQyxH/sWjOJQ=";
      i686-linux = "sha256-/Q7VZahYhLdKVFB25CanROYxD2etQOcRg+4bXZUMqTc=";
      x86_64-darwin = "sha256-9biFAbFD7Bva7KPKztgCvcaoX8E6AlJBKkjlDQdP6Zw=";
      aarch64-darwin = "sha256-to5Y0R9tm9b7jUQAK3eBylLhpu+w5oDd63FbBCBAvd8=";
    }.${stdenv.system} or (throw "Unsupported system: ${stdenv.system}");
  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pname version src;
    hash = "sha256-gf3vmKUta8KksUOxyhQS4UO6ycAJDfEicyXVGMW8+4c=";
  };

  cargoDeps = rustPlatform.importCargoLock {
@@ -86,7 +49,8 @@ stdenv.mkDerivation rec {
    cargo
    rustc
    cargo-tauri
    nodePackages.pnpm
    nodejs
    pnpm.configHook
    copyDesktopItems
    pkg-config
  ];
@@ -98,10 +62,6 @@ stdenv.mkDerivation rec {
  ];

  preBuild = ''
    export HOME=$(mktemp -d)
    pnpm config set store-dir ${pnpm-deps}
    pnpm install --offline --frozen-lockfile --ignore-script
    pnpm rebuild
    cargo tauri build -b deb
  '';

@@ -131,4 +91,4 @@ stdenv.mkDerivation rec {
    platforms = platforms.linux ++ platforms.darwin;
    mainProgram = "kiwi-talk";
  };
 }
})
+19 −46
Original line number Diff line number Diff line
{ lib
, stdenv
, stdenvNoCC
, rustPlatform
, fetchFromGitHub
, nodejs
, pnpm
, wrapGAppsHook3
, cargo
, rustc
, cargo-tauri
, pkg-config
, nodePackages
, esbuild
, buildGoModule
, jq
, moreutils
, libayatana-appindicator
, gtk3
, webkitgtk
, libsoup
, openssl
, xdotool
, cacert
}:

stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
  pname = "pot";
  version = "2.7.9";

  src = fetchFromGitHub {
    owner = "pot-app";
    repo = "pot-desktop";
    rev = version;
    rev = finalAttrs.version;
    hash = "sha256-Y2gFLvRNBjOGxdpIeoY1CXEip0Ht73aymWIP5wuc9kU=";
  };

  sourceRoot = "${src.name}/src-tauri";
  sourceRoot = "${finalAttrs.src.name}/src-tauri";

  postPatch = ''
    substituteInPlace $cargoDepsCopy/libappindicator-sys-*/src/lib.rs \
      --replace "libayatana-appindicator3.so.1" "${libayatana-appindicator}/lib/libayatana-appindicator3.so.1"
  '';

  pnpm-deps = stdenvNoCC.mkDerivation {
    pname = "${pname}-pnpm-deps";
    inherit src version;

    nativeBuildInputs = [
      jq
      moreutils
      nodePackages.pnpm
      cacert
    ];

    installPhase = ''
      export HOME=$(mktemp -d)
      pnpm config set store-dir $out
      # use --ignore-script and --no-optional to avoid downloading binaries
      # use --frozen-lockfile to avoid checking git deps
      pnpm install --frozen-lockfile --no-optional --ignore-script

      # Remove timestamp and sort the json files
      rm -rf $out/v3/tmp
      for f in $(find $out -name "*.json"); do
        sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
        jq --sort-keys . $f | sponge $f
      done
    '';

    dontFixup = true;
    outputHashMode = "recursive";
    outputHash = "sha256-LuY5vh642DgSa91eUcA/AT+ovDcP9tZFE2dKyicCOeQ=";
  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pname version src;
    hash = "sha256-nRRUX6CH3s1cEoI80gtRmu0ovXpIwS+h1rFJo8kw60E=";
  };

  pnpmRoot = "..";

  cargoDeps = rustPlatform.importCargoLock {
    lockFile = ./Cargo.lock;
    outputHashes = {
@@ -84,8 +57,9 @@ stdenv.mkDerivation rec {
    cargo
    rustc
    cargo-tauri
    nodejs
    pnpm.configHook
    wrapGAppsHook3
    nodePackages.pnpm
    pkg-config
  ];

@@ -111,13 +85,13 @@ stdenv.mkDerivation rec {
    });
  })}";

  preBuild = ''
    export HOME=$(mktemp -d)
    pnpm config set store-dir ${pnpm-deps}
  preConfigure = ''
    # pnpm.configHook has to write to .., as our sourceRoot is set to src-tauri
    # TODO: move frontend into its own drv
    chmod +w ..
    pnpm install --offline --frozen-lockfile --no-optional --ignore-script
    chmod -R +w ../node_modules
    pnpm rebuild
  '';

  preBuild = ''
    # Use cargo-tauri from nixpkgs instead of pnpm tauri from npm
    cargo tauri build -b deb
  '';
@@ -134,5 +108,4 @@ stdenv.mkDerivation rec {
    license = licenses.gpl3Only;
    maintainers = with maintainers; [ linsui ];
  };
}
})
Loading