diff options
| author | tv <tv@krebsco.de> | 2026-11-12 02:36:21 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-12 02:36:21 +0000 |
| commit | 74fb1d515e6879922bc65fab4c7099dde9dd92e5 (patch) | |
| tree | 650a07d3a31923e3c724f9e709ece39d05a2a506 /pkgs | |
| parent | b0469337bd8eb3d8e325e82640ac855731975000 (diff) | |
tests: run populate's jq programs over lock files of both shapes
Depending on the version of Nix, lock files name subdirectories as
attribute dir or as query parameter dir of the URL. The VM tests run
one version, so only one shape gets covered there. The jq programs for
flakes move to pkgs/populate/flake-jq.nix, and a new test, jq, runs them
without VMs over lock files of both shapes, with follows, removed and
cyclic follows, and inputs given by relative paths.
Diffstat (limited to 'pkgs')
| -rw-r--r-- | pkgs/populate/default.nix | 67 | ||||
| -rw-r--r-- | pkgs/populate/flake-jq.nix | 70 |
2 files changed, 71 insertions, 66 deletions
diff --git a/pkgs/populate/default.nix b/pkgs/populate/default.nix index bd7e5e4..f3cf925 100644 --- a/pkgs/populate/default.nix +++ b/pkgs/populate/default.nix @@ -259,6 +259,7 @@ let pop.flake = target: source: pop.flake-input target (source // { name = null; }); pop.flake-input = target: source: let + inherit (import ./flake-jq.nix) selected selfIsRemote selfLocked; nix' = "${nix}/bin/nix --extra-experimental-features ${quote "nix-command flakes"}"; inputPath = if source.name == null then [] else splitString "/" source.name; fetchOnTarget = source.fetchOnTarget or false; @@ -291,72 +292,6 @@ let ${quote source.flake} ${quote (toString source.name)} exit 1 ''; - # jq definitions for subdirectories containing flakes, which flake - # references and lock entries name either as attribute dir or as query - # parameter dir of their URL, depending on the version of Nix. fetchTree - # supports neither. - subdirs = /* jq */ '' - def subdir: - .dir // ((.url // "") | capture("[?&]dir=(?<dir>[^&]*)").dir) // ""; - def withoutSubdir: - del(.__final, .dir) - | if (.url | type) == "string" then - .url |= (sub("(?<sep>[?&])dir=[^&]*&?"; "\(.sep)") | sub("[?&]$"; "")) - else . end; - def subdirOf($node): - [$node.locked, $node.original] - | map(select(. != null) | subdir | select(. != "")) - | first // ""; - ''; - # jq filter selecting the flake or input in nix flake metadata's output, - # by the path of input names $input, as what to fetch and the - # subdirectory containing it: {self, locked, subdir}. Names follow the - # flake's lock file, follows included; an empty follows path removes an - # input. The flake itself, and inputs given by paths relative to it, have - # self set instead of fetchTree arguments in locked. - selected = /* jq */ '' - ${subdirs} - . as $m - | .locks as $l - | def ref($path; $depth): - if $depth > 64 then error("follows nest too deep") else - reduce $path[] as $name ($l.root; - (($l.nodes[.].inputs // {})[$name]) as $next - | if $next == null or $next == [] then error("no input \($name)") - elif ($next | type) == "array" then ref($next; $depth + 1) - else $next end) - end; - def join($a; $b): - if $a == "" then $b elif $b == "" then $a else "\($a)/\($b)" end; - def resolve($key; $depth): - $l.nodes[$key] as $node - | if $depth > 64 then error("parents nest too deep") - elif $key == $l.root then - { self: true, locked: null, subdir: subdirOf($m) } - elif $node.parent != null then - resolve(ref($node.parent; 0); $depth + 1) as $base - | $base + { - subdir: join(join($base.subdir; - $node.locked.path | ltrimstr("./") | rtrimstr("/") | if . == "." then "" else . end); - subdirOf($node)) - } - else - { self: false, locked: ($node.locked | withoutSubdir), subdir: subdirOf($node) } - end; - resolve(ref($input; 0); 0) - ''; - # jq filter telling whether the target can fetch the flake itself, i.e. - # whether its locked reference doesn't refer to the deploying machine. - selfIsRemote = /* jq */ '' - .locked | (.type != "path") and ((.url // "") | startswith("file:") | not) - ''; - # jq filter replacing self in the selection $selected with the flake's - # locked reference. - selfLocked = /* jq */ '' - ${subdirs} - .locked as $self - | $selected + { self: false, locked: ($self | withoutSubdir) } - ''; # Shell function printing the store path $1, followed by the inputs its # flake in the subdirectory $2 pins in its own lock file, using the nix # command nix. Without a lock file, locking would change the flake, so diff --git a/pkgs/populate/flake-jq.nix b/pkgs/populate/flake-jq.nix new file mode 100644 index 0000000..41edcc5 --- /dev/null +++ b/pkgs/populate/flake-jq.nix @@ -0,0 +1,70 @@ +# jq programs populate uses for flake and flake-input sources, in a file of +# their own, so tests can run them. +rec { + # jq definitions for subdirectories containing flakes, which flake + # references and lock entries name either as attribute dir or as query + # parameter dir of their URL, depending on the version of Nix. fetchTree + # supports neither. + subdirs = /* jq */ '' + def subdir: + .dir // ((.url // "") | capture("[?&]dir=(?<dir>[^&]*)").dir) // ""; + def withoutSubdir: + del(.__final, .dir) + | if (.url | type) == "string" then + .url |= (sub("(?<sep>[?&])dir=[^&]*&?"; "\(.sep)") | sub("[?&]$"; "")) + else . end; + def subdirOf($node): + [$node.locked, $node.original] + | map(select(. != null) | subdir | select(. != "")) + | first // ""; + ''; + # jq filter selecting the flake or input in nix flake metadata's output, + # by the path of input names $input, as what to fetch and the + # subdirectory containing it: {self, locked, subdir}. Names follow the + # flake's lock file, follows included; an empty follows path removes an + # input. The flake itself, and inputs given by paths relative to it, have + # self set instead of fetchTree arguments in locked. + selected = /* jq */ '' + ${subdirs} + . as $m + | .locks as $l + | def ref($path; $depth): + if $depth > 64 then error("follows nest too deep") else + reduce $path[] as $name ($l.root; + (($l.nodes[.].inputs // {})[$name]) as $next + | if $next == null or $next == [] then error("no input \($name)") + elif ($next | type) == "array" then ref($next; $depth + 1) + else $next end) + end; + def join($a; $b): + if $a == "" then $b elif $b == "" then $a else "\($a)/\($b)" end; + def resolve($key; $depth): + $l.nodes[$key] as $node + | if $depth > 64 then error("parents nest too deep") + elif $key == $l.root then + { self: true, locked: null, subdir: subdirOf($m) } + elif $node.parent != null then + resolve(ref($node.parent; 0); $depth + 1) as $base + | $base + { + subdir: join(join($base.subdir; + $node.locked.path | ltrimstr("./") | rtrimstr("/") | if . == "." then "" else . end); + subdirOf($node)) + } + else + { self: false, locked: ($node.locked | withoutSubdir), subdir: subdirOf($node) } + end; + resolve(ref($input; 0); 0) + ''; + # jq filter telling whether the target can fetch the flake itself, i.e. + # whether its locked reference doesn't refer to the deploying machine. + selfIsRemote = /* jq */ '' + .locked | (.type != "path") and ((.url // "") | startswith("file:") | not) + ''; + # jq filter replacing self in the selection $selected with the flake's + # locked reference. + selfLocked = /* jq */ '' + ${subdirs} + .locked as $self + | $selected + { self: false, locked: ($self | withoutSubdir) } + ''; +} |
