Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6dde51d
extend preinstall script within package.json instead of .hooks directory
tlxzilia Aug 2, 2022
9e166a1
switch from npm install to npm ci
tlxzilia Aug 2, 2022
8e99638
remove node version check
tlxzilia Aug 2, 2022
ce45112
Revert "extend preinstall script within package.json instead of .hook…
tlxzilia Aug 5, 2022
ea08a4f
patch shebang for node_modules bin
tlxzilia Aug 5, 2022
a43429a
support lockfile v2 packages attribute
tlxzilia Aug 11, 2022
91fbba6
wrap patchSource into a set including json changeset and overrided pa…
tlxzilia Aug 11, 2022
79d702c
resolve github package to recaculate integrity
tlxzilia Aug 11, 2022
422c49e
packTgz already add .tgz suffix for buildTgzFromGitHub
tlxzilia Aug 11, 2022
2a1d4ee
npm use semantic version scheme, make github source compatible
tlxzilia Aug 11, 2022
90637dc
patch packages integrity using simpler sed substitution. jq query see…
tlxzilia Aug 11, 2022
b50c3db
sanitize packTgz name
tlxzilia Aug 11, 2022
4ce6678
activate node >= 16 tests
tlxzilia Aug 11, 2022
996b8eb
patch npm bin packages using coreutils to not depends on node version
tlxzilia Aug 11, 2022
1ef36e1
replace preInstallLinks with sourceOverrides
tlxzilia Aug 11, 2022
7733c95
custom unpackPhase for node module to fix tar extract ownership permi…
tlxzilia Aug 11, 2022
9f4c7cc
added sourceOverrides default override helper
tlxzilia Aug 11, 2022
6c58a54
update doc
tlxzilia Aug 11, 2022
0e89d9e
support lockfile v2 nested dependencies.
tlxzilia Aug 11, 2022
f5febc6
assert build not supported V2 with lower node version
tlxzilia Aug 13, 2022
55d333a
compile all latest node modules versions from package-lock.json and a…
tlxzilia Aug 15, 2022
d5588f8
add integration test for github source
tlxzilia Aug 15, 2022
105a684
also resolve "latest" version in package.json
tlxzilia Aug 15, 2022
78b23a0
execute build scripts as part of a rebuild process to support low RAM…
tlxzilia Aug 15, 2022
9de6842
pass file to jq directly
tlxzilia Aug 15, 2022
afb414c
only use direct dependencies in npm rebuild to handle lower node vers…
tlxzilia Aug 15, 2022
83eb7b2
rebuild must be followed with an npm install to run install scripts i…
tlxzilia Aug 15, 2022
4c1a4d3
Split v1/v2 npm lockfile support in different namespaces/codebases
picnoir Sep 14, 2022
10a49ca
[WIP] lockfiles v2: port v1 test suite
picnoir Sep 15, 2022
e360d51
[V2][bugfix] create missing dir in preInstallLinks script
picnoir Sep 15, 2022
12a2ce3
[v2][bugfix] Remove https references from patched package.json
picnoir Sep 16, 2022
e4c34ca
[v2] Updating documentation/variable names to fit v2 functions
picnoir Sep 16, 2022
70485df
[v2][bugfix] Support new Github url formats
picnoir Sep 16, 2022
64ca4f5
Remove lockfilev1-specific machinery
picnoir Sep 21, 2022
06f9aac
Reformatting nix code
picnoir Sep 26, 2022
3ea5cf1
[v2][bugfix] Patching shebangs of the bundled dependencies
picnoir Sep 26, 2022
2f88191
[v2][bugfix] Relax package dependencies version bounds
picnoir Sep 27, 2022
e3c207f
[v2][doc] Update API.md
picnoir Sep 29, 2022
4796361
[v2][bugfix] Accept missing resolved link for bundled dependencies
picnoir Oct 4, 2022
219159f
[v2][bugfix] Remove peerDependencies from produced lockfiles
picnoir Oct 4, 2022
3283c59
[v2][bugfix] Strip out URL query strings in resolved fields
picnoir Nov 25, 2022
bea15da
Expose the v1 API as default in default.nix with a warning
andir Dec 1, 2022
aff1c4c
Remove the functor thing from the v2 interface
andir Dec 1, 2022
0ea1cbd
Do a first pass on the API.md that recovers the v1 docs
andir Dec 1, 2022
7b2db50
Fix GitHub actions
andir Dec 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
jobs:
tests:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v18
Expand Down
101 changes: 93 additions & 8 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

The sections below describe the public API of _npmlock2nix_.

Npmlock2nix is currently in a transition phase. The npmlockfile format evolved with the npm v7 release so does the npmlock2nix parser. If you're trying to parse a lockfile v2, generated via npm >= 7, you'll have to use the `v2` top-level prefix.

IE. you'll have to call the following functions with these prefixes:

```nix
# V1 lockfiles

npmlock2nix.v1.build {
}

npmlock2nix.v1.node_modules {
}

npmlock2nix.v1.shell {
}

# V2 lockfiles

npmlock2nix.v2.build {
}

npmlock2nix.v2.node_modules {
}

npmlock2nix.v2.shell {
}
```

Aside from these `v1` and `v2` prefixes, the underlying public API stays the same.

If you forget to specify a `v1`/`v2` prefix, a warning containing some migration instructions will be emitted and npmlock2nix will fall back on using the lockfiles `v1` implementation.

## Functions

### node_modules
Expand Down Expand Up @@ -62,24 +100,26 @@ The `build` function takes an attribute set with the following attributes:
When _npmlock2nix_ is used in restricted evaluation mode (hydra for example), `node_modules` needs to be provided with the revision and sha256 of all GitHub dependencies via `githubSourceHashMap`:

```nix
npmlock2nix.node_modules {
npmlock2nix.v1.node_modules {
src = ./.;
githubSourceHashMap = {
tmcw.leftpad.db1442a0556c2b133627ffebf455a78a1ced64b9 = "1zyy1nxbby4wcl30rc8fsis1c3f7nafavnwd3qi4bg0x00gxjdnh";
};
}
```

Please refer to [github-dependency](https://github.com/tweag/npmlock2nix/blob/master/tests/examples-projects/github-dependency/default.nix) for a fully working example.
Please refer to [github-dependency](https://github.com/nix-community/npmlock2nix/blob/master/tests/tests-v2/examples-projects/github-dependency) for a fully working example.

### preInstallLinks

*NOTE* In the `v2` API the `preInstallLinks` attribute was removed. Use source derivation overrides `sourceOverrides`.

Sometimes you may want to augment or populate vendored dependencies in npm packages because they either aren't working or they cannot be fetched during the build phase. This can be achieved by passing a `preInstallLinks` attribute set to `node_modules`.

If you wanted to patch the [cwebp-bin](https://www.npmjs.com/package/cwebp-bin) package to contain the `cwebp` binary from nixpkgs under `vendor/cwebp-bin` you would do so as follows:

```nix
npmlock2nix.node_modules {
npmlock2nix.v1.node_modules {
src = ./.;
preInstallLinks = {
"cwebp-bin" = {
Expand Down Expand Up @@ -108,7 +148,7 @@ The first can be useful if you are also using `npm` to interactively update or m
When you actually want to describe a shell environment or a build, but you need to pass attributes to `node_modules` you can do so by passing them via `node_modules_attrs` in both `build` and `shell`:

```nix
npmlock2nix.build {
npmlock2nix.v1.build {
src = ./.;
node_modules_attrs = {
buildInputs = [ pkgs.zlib ];
Expand All @@ -123,7 +163,7 @@ npmlock2nix.build {
The `sourceOverrides` argument expects an attribute set mapping npm package names to a function describing the modifications of that package. Each function receives an attribute set as a first argument, containing either a `version` attribute if the version is known, or a `github = { org, repo, rev, ref }` attribute if the package is fetched from GitHub. These values can be used to have different overrides depending on the version. The function receives another argument which is the derivation of the fetched source, which can be modified using `.overrideAttrs`. The fetched source mainly runs the [patch phase](https://nixos.org/manual/nixpkgs/stable/#ssec-patch-phase), so of particular interest are the `patches` and `postPatch` attributes, in which `patchShebangs` can be called. Note that `patchShebangs` can only patch shebangs to binaries accessible in the derivation, which you can extend with `buildInputs`. For convenience, the correct version of `nodejs` is always included in `buildInputs`.

```nix
npmlock2nix.node_modules {
npmlock2nix.v1.node_modules {
sourceOverrides = {
# sourceInfo either contains:
# - A version attribute
Expand All @@ -135,12 +175,57 @@ npmlock2nix.node_modules {
some script
'';
# ...
})

# Example
});
# Example
node-pre-gyp = sourceInfo: drv: drv.overrideAttrs (old: {
postPatch = "patchShebangs bin";
});

};
}
```

*Note* In the `v2` API the following is the case:

Npm packages binaries interpreter are automatically patched with environment shebangs when an entry exist for the npm package.

To replace `preInstallLinks` functionality. Symlinked vendored binaries are compiled to be added on node modules installation using npm preinstall script, this is required since npm strip symlinks from package archive.

The `sourceOverrides` argument expects an attribute set mapping npm package names to a function describing the modifications of that package. Each function receives an attribute set as a first argument, containing either a `version` attribute if the version is known, or a `github = { org, repo, rev, ref }` attribute if the package is fetched from GitHub. These values can be used to have different overrides depending on the version. The function receives another argument which is the derivation of the fetched source, which can be modified using `.overrideAttrs`. The fetched source mainly runs the [patch phase](https://nixos.org/manual/nixpkgs/stable/#ssec-patch-phase), so of particular interest are the `patches` and `postPatch` attributes, in which `patchShebangs` can be called.

`sourceOverrides` comes with default override mechanism like patching all npm packages binaries dependencies with `buildRequirePatchShebangs` or patching individual npm package binaries with `packageRequirePatchShebangs`.

```nix
npmlock2nix.v2.node_modules {
sourceOverrides = {
# sourceInfo either contains:
# - A version attribute
# - A github = { org, repo, rev, ref } attribute for GitHub sources
package-name = sourceInfo: drv: drv.overrideAttrs (old: {
buildInputs = [ somePackage ];
patches = [ somePatch ];
postPatch = ''
mkdir -p vendor
ln -sf ${vendored_binary} ./vendor/vendored_binary
'';
# ...
})

# Patch all npm packages
buildRequirePatchShebangs = true;

# Patch individual package
node-pre-gyp = npmlock2nix.v2.packageRequirePatchShebangs;

# Link vendored binaries
package-name = sourceInfo: drv: drv.overrideAttrs (old: {
postPatch = ''
mkdir -p vendor
ln -sf ${vendored_binary} ./vendor/vendored_binary
'';
});

};
}
```
35 changes: 21 additions & 14 deletions default.nix
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
{ pkgs ? import ./nix { } }:
{ pkgs ? import ./nix { }, lib ? pkgs.lib }:
let
internal = pkgs.callPackage ./internal.nix { };
v1_internal = pkgs.callPackage ./internal-v1.nix { };
v2_internal = pkgs.callPackage ./internal-v2.nix { };
separatePublicAndInternalAPI = api: extraAttributes: {
inherit (api) shell build node_modules;

# *** WARNING ****
# using any of the functions exposed by `internal` is not supported. That
# being said, hiding them would only lead to copy&paste and it is also useful
# for testing internal building blocks.
internal = lib.warn "[npmlock2nix] You are using the unsupported internal API." (
api
);
} // (lib.listToAttrs (map (name: lib.nameValuePair name api.${name}) extraAttributes));
v1 = separatePublicAndInternalAPI v1_internal [ ];
v2 = separatePublicAndInternalAPI v2_internal [ "packageRequirePatchShebangs" ];
in
{
inherit (internal) shell build node_modules;

inherit v1;
v2 = lib.mapAttrs (_: lib.warn "[npmlock2nix] You are using the new v2 beta api. The interface isn't stable yet. Please report any issues at https://github.com/nix-community/npmlock2nix/issues") v2;
tests = pkgs.callPackage ./tests { };


# *** WARNING ****
# using any of the functions exposed by `internal` is not supported. That
# being said, hiding them would only lead to copy&paste and it is also useful
# for testing internal building blocks.
internal = builtins.trace "[npmlock2nix] You are using the unsupported internal API." (
internal
);
}
} // (lib.mapAttrs
(lib.warn "[npmlock2nix] You are using the unversion prefix for builders. This is fine for now. In the future we will move to a versioned interface (old versions remain as they are). The currently used functions are availabe as `npmlock2nix.v1` for example `npmlock2nix.v1.build`.")
v1)
6 changes: 0 additions & 6 deletions internal.nix → internal-v1.nix
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ rec {
rm -f node_modules
fi
''}

if test -e node_modules; then
echo '[npmlock2nix] There is already a `node_modules` directory. Not replacing it.' >&2
exit 1
Expand Down Expand Up @@ -433,9 +432,7 @@ rec {
in
''
#! ${stdenv.shell}

${preInstallLinkCommands}

if grep -I -q -r '/bin/' .; then
source $TMP/preinstall-env
patchShebangs .
Expand Down Expand Up @@ -494,14 +491,12 @@ rec {
# https://docs.npmjs.com/cli/v8/configuring-npm/package-lock-json#packages
# https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#tools_for_generating_sri_hashes
hash="sha512-$(openssl dgst -sha512 -binary ${lib.escapeShellArg file} | openssl base64 -A)"

# Constructs a simple { path, value } JSON of the given arguments
jq -c --argjson path ${lib.escapeShellArg (builtins.toJSON path)} --arg value "$hash" -n '$ARGS.named'
'') patchedLockfile'.integrityUpdates}
} | jq -s --slurpfile original ${patchedLockfile'.result} -f "$jqSetIntegrityPath" > package-lock.json
set +x
''}

ln -sf ${patchedPackagefilePath} package.json
'';

Expand All @@ -518,7 +513,6 @@ rec {
'';
installPhase = ''
mkdir "$out"

if test -d node_modules; then
if [ $(ls -1 node_modules | wc -l) -gt 0 ] || [ -e node_modules/.bin ]; then
mv node_modules $out/
Expand Down
Loading