1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-08 18:11:02 +01:00

Merge pull request #14708 from obsidiansystems/version-path-info-outer

Make `nix path-info` follow the JSON guidelines
This commit is contained in:
John Ericson 2025-12-04 17:16:17 +00:00 committed by GitHub
commit a4fc3863dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 65 additions and 30 deletions

View file

@ -18,16 +18,30 @@ This is the legacy format, preserved for backwards compatibility:
- String-based hash values (e.g., `"narHash": "sha256:FePFYIlM..."`) - String-based hash values (e.g., `"narHash": "sha256:FePFYIlM..."`)
- String-based content addresses (e.g., `"ca": "fixed:r:sha256:1abc..."`) - String-based content addresses (e.g., `"ca": "fixed:r:sha256:1abc..."`)
- Full store paths in references (e.g., `"/nix/store/abc...-foo"`) - Full store paths for map keys and references (e.g., `"/nix/store/abc...-foo"`)
- Now includes `"storeDir"` field at the top level - Now includes `"storeDir"` field at the top level
### Version 2 (`--json-format 2`) ### Version 2 (`--json-format 2`)
The new structured format with the following changes: The new structured format follows the [JSON guidelines](@docroot@/development/json-guideline.md) with the following changes:
- **Store path base names in references**: - **Nested structure with top-level metadata**:
References use store path base names (e.g., `"abc...-foo"`) instead of full paths. The output is now wrapped in an object with `version`, `storeDir`, and `info` fields:
```json
{
"version": 2,
"storeDir": "/nix/store",
"info": { ... }
}
```
The map from store bath base names to store object info is nested under the `info` field.
- **Store path base names instead of full paths**:
Map keys and references use store path base names (e.g., `"abc...-foo"`) instead of full absolute store paths.
Combined with `storeDir`, the full path can be reconstructed. Combined with `storeDir`, the full path can be reconstructed.
- **Structured `ca` field**: - **Structured `ca` field**:

View file

@ -41,10 +41,14 @@ pathInfoToJSON(Store & store, const StorePathSet & storePaths, bool showClosureS
{ {
json::object_t jsonAllObjects = json::object(); json::object_t jsonAllObjects = json::object();
auto makeKey = [&](const StorePath & path) {
return format == PathInfoJsonFormat::V1 ? store.printStorePath(path) : std::string(path.to_string());
};
for (auto & storePath : storePaths) { for (auto & storePath : storePaths) {
json jsonObject; json jsonObject;
std::string key = store.printStorePath(storePath); std::string key = makeKey(storePath);
try { try {
auto info = store.queryPathInfo(storePath); auto info = store.queryPathInfo(storePath);
@ -52,7 +56,7 @@ pathInfoToJSON(Store & store, const StorePathSet & storePaths, bool showClosureS
// `storePath` has the representation `<hash>-x` rather than // `storePath` has the representation `<hash>-x` rather than
// `<hash>-<name>` in case of binary-cache stores & `--all` because we don't // `<hash>-<name>` in case of binary-cache stores & `--all` because we don't
// know the name yet until we've read the NAR info. // know the name yet until we've read the NAR info.
key = store.printStorePath(info->path); key = makeKey(info->path);
jsonObject = info->toJSON(format == PathInfoJsonFormat::V1 ? &store : nullptr, true, format); jsonObject = info->toJSON(format == PathInfoJsonFormat::V1 ? &store : nullptr, true, format);
@ -87,7 +91,16 @@ pathInfoToJSON(Store & store, const StorePathSet & storePaths, bool showClosureS
jsonAllObjects[key] = std::move(jsonObject); jsonAllObjects[key] = std::move(jsonObject);
} }
if (format == PathInfoJsonFormat::V1) {
return jsonAllObjects; return jsonAllObjects;
} else {
return {
{"version", format},
{"storeDir", store.storeDir},
{"info", std::move(jsonAllObjects)},
};
}
} }
struct CmdPathInfo : StorePathsCommand, MixJSON struct CmdPathInfo : StorePathsCommand, MixJSON

View file

@ -18,7 +18,7 @@ outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to "file://$cacheDir" "$outPath" nix copy --to "file://$cacheDir" "$outPath"
readarray -t paths < <(nix path-info --all --json --json-format 2 --store "file://$cacheDir" | jq 'keys|sort|.[]' -r) readarray -t paths < <(nix path-info --all --json --json-format 2 --store "file://$cacheDir" | jq '.info|keys|sort|.[]' -r)
[[ "${#paths[@]}" -eq 3 ]] [[ "${#paths[@]}" -eq 3 ]]
for path in "${paths[@]}"; do for path in "${paths[@]}"; do
[[ "$path" =~ -dependencies-input-0$ ]] \ [[ "$path" =~ -dependencies-input-0$ ]] \

View file

@ -15,7 +15,7 @@ nix-build fixed.nix -A bad --no-out-link && fail "should fail"
# a side-effect. # a side-effect.
[[ -e $path ]] [[ -e $path ]]
nix path-info --json --json-format 2 "$path" | jq -e \ nix path-info --json --json-format 2 "$path" | jq -e \
'.[].ca == { '.info.[].ca == {
method: "flat", method: "flat",
hash: { hash: {
algorithm: "md5", algorithm: "md5",

View file

@ -50,7 +50,7 @@ try2 () {
nix path-info --json --json-format 2 "$path" | jq -e \ nix path-info --json --json-format 2 "$path" | jq -e \
--arg algo "$hashAlgo" \ --arg algo "$hashAlgo" \
--arg hash "$hashFromGit" \ --arg hash "$hashFromGit" \
'.[].ca == { '.info.[].ca == {
method: "git", method: "git",
hash: { hash: {
algorithm: $algo, algorithm: $algo,

View file

@ -30,7 +30,7 @@ path1_stuff=$(echo "$json" | jq -r .[].outputs.stuff)
[[ $(< "$path1"/n) = 0 ]] [[ $(< "$path1"/n) = 0 ]]
[[ $(< "$path1_stuff"/bla) = 0 ]] [[ $(< "$path1_stuff"/bla) = 0 ]]
nix path-info --json --json-format 2 "$path1" | jq -e '.[].ca | .method == "nar" and .hash.algorithm == "sha256"' nix path-info --json --json-format 2 "$path1" | jq -e '.info.[].ca | .method == "nar" and .hash.algorithm == "sha256"'
path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | jq -r .[].outputs.out) path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | jq -r .[].outputs.out)
[[ $(< "$path2"/n) = 1 ]] [[ $(< "$path2"/n) = 1 ]]

View file

@ -166,7 +166,7 @@ printf 4.0 > "$flake1Dir"/version
printf Utrecht > "$flake1Dir"/who printf Utrecht > "$flake1Dir"/who
nix profile add "$flake1Dir" nix profile add "$flake1Dir"
[[ $("$TEST_HOME"/.nix-profile/bin/hello) = "Hello Utrecht" ]] [[ $("$TEST_HOME"/.nix-profile/bin/hello) = "Hello Utrecht" ]]
nix path-info --json --json-format 2 "$(realpath "$TEST_HOME"/.nix-profile/bin/hello)" | jq -e '.[].ca | .method == "nar" and .hash.algorithm == "sha256"' nix path-info --json --json-format 2 "$(realpath "$TEST_HOME"/.nix-profile/bin/hello)" | jq -e '.info.[].ca | .method == "nar" and .hash.algorithm == "sha256"'
# Override the outputs. # Override the outputs.
nix profile remove simple flake1 nix profile remove simple flake1

View file

@ -4,36 +4,44 @@ source common.sh
echo foo > "$TEST_ROOT"/foo echo foo > "$TEST_ROOT"/foo
foo=$(nix store add-file "$TEST_ROOT"/foo) foo=$(nix store add-file "$TEST_ROOT"/foo)
fooBase=$(basename "$foo")
echo bar > "$TEST_ROOT"/bar echo bar > "$TEST_ROOT"/bar
bar=$(nix store add-file "$TEST_ROOT"/bar) bar=$(nix store add-file "$TEST_ROOT"/bar)
barBase=$(basename "$bar")
echo baz > "$TEST_ROOT"/baz echo baz > "$TEST_ROOT"/baz
baz=$(nix store add-file "$TEST_ROOT"/baz) baz=$(nix store add-file "$TEST_ROOT"/baz)
bazBase=$(basename "$baz")
nix-store --delete "$baz" nix-store --delete "$baz"
diff --unified --color=always \ diff --unified --color=always \
<(nix path-info --json --json-format 2 "$foo" "$bar" "$baz" | <(nix path-info --json --json-format 2 "$foo" "$bar" "$baz" |
jq --sort-keys 'map_values(.narHash)') \ jq --sort-keys '.info | map_values(.narHash)') \
<(jq --sort-keys <<-EOF <(jq --sort-keys <<-EOF
{ {
"$foo": { "$fooBase": {
"algorithm": "sha256", "algorithm": "sha256",
"format": "base16", "format": "base16",
"hash": "42fb4031b525feebe2f8b08e6e6a8e86f34e6a91dd036ada888e311b9cc8e690" "hash": "42fb4031b525feebe2f8b08e6e6a8e86f34e6a91dd036ada888e311b9cc8e690"
}, },
"$bar": { "$barBase": {
"algorithm": "sha256", "algorithm": "sha256",
"format": "base16", "format": "base16",
"hash": "f5f8581aef5fab17100b629cf35aa1d91328d5070b054068f14fa93e7fa3b614" "hash": "f5f8581aef5fab17100b629cf35aa1d91328d5070b054068f14fa93e7fa3b614"
}, },
"$baz": null "$bazBase": null
} }
EOF EOF
) )
# Test that storeDir is returned in the JSON output # Test that storeDir is returned in the JSON output in individual store objects
nix path-info --json --json-format 2 "$foo" | jq -e \ nix path-info --json --json-format 2 "$foo" | jq -e \
--arg foo "$foo" \ --arg fooBase "$fooBase" \
--arg storeDir "${NIX_STORE_DIR:-/nix/store}" \ --arg storeDir "${NIX_STORE_DIR:-/nix/store}" \
'.[$foo].storeDir == $storeDir' '.info[$fooBase].storeDir == $storeDir'
# And also at the top -evel
echo | nix path-info --json --json-format 2 --stdin | jq -e \
--arg storeDir "${NIX_STORE_DIR:-/nix/store}" \
'.storeDir == $storeDir'

View file

@ -15,10 +15,10 @@ outPath=$(nix-build dependencies.nix --no-out-link --secret-key-files "$TEST_ROO
# Verify that the path got signed. # Verify that the path got signed.
info=$(nix path-info --json --json-format 2 "$outPath") info=$(nix path-info --json --json-format 2 "$outPath")
echo "$info" | jq -e '.[] | .ultimate == true' echo "$info" | jq -e '.info.[] | .ultimate == true'
TODO_NixOS # looks like an actual bug? Following line fails on NixOS: TODO_NixOS # looks like an actual bug? Following line fails on NixOS:
echo "$info" | jq -e '.[] | .signatures.[] | select(startswith("cache1.example.org"))' echo "$info" | jq -e '.info.[] | .signatures.[] | select(startswith("cache1.example.org"))'
echo "$info" | jq -e '.[] | .signatures.[] | select(startswith("cache2.example.org"))' echo "$info" | jq -e '.info.[] | .signatures.[] | select(startswith("cache2.example.org"))'
# Test "nix store verify". # Test "nix store verify".
nix store verify -r "$outPath" nix store verify -r "$outPath"
@ -40,8 +40,8 @@ nix store verify -r "$outPath"
# Verify that the path did not get signed but does have the ultimate bit. # Verify that the path did not get signed but does have the ultimate bit.
info=$(nix path-info --json --json-format 2 "$outPath2") info=$(nix path-info --json --json-format 2 "$outPath2")
echo "$info" | jq -e '.[] | .ultimate == true' echo "$info" | jq -e '.info.[] | .ultimate == true'
echo "$info" | jq -e '.[] | .signatures == []' echo "$info" | jq -e '.info.[] | .signatures == []'
# Test "nix store verify". # Test "nix store verify".
nix store verify -r "$outPath2" nix store verify -r "$outPath2"
@ -58,7 +58,7 @@ nix store verify -r "$outPath2" --sigs-needed 1 --trusted-public-keys "$pk1"
# Build something content-addressed. # Build something content-addressed.
outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link) outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link)
nix path-info --json --json-format 2 "$outPathCA" | jq -e '.[].ca | .method == "flat" and .hash.algorithm == "md5"' nix path-info --json --json-format 2 "$outPathCA" | jq -e '.info.[].ca | .method == "flat" and .hash.algorithm == "md5"'
# Content-addressed paths don't need signatures, so they verify # Content-addressed paths don't need signatures, so they verify
# regardless of --sigs-needed. # regardless of --sigs-needed.
@ -74,15 +74,15 @@ nix copy --to file://"$cacheDir" "$outPath2"
# Verify that signatures got copied. # Verify that signatures got copied.
info=$(nix path-info --store file://"$cacheDir" --json --json-format 2 "$outPath2") info=$(nix path-info --store file://"$cacheDir" --json --json-format 2 "$outPath2")
echo "$info" | jq -e '.[] | .ultimate == false' echo "$info" | jq -e '.info.[] | .ultimate == false'
echo "$info" | jq -e '.[] | .signatures.[] | select(startswith("cache1.example.org"))' echo "$info" | jq -e '.info.[] | .signatures.[] | select(startswith("cache1.example.org"))'
echo "$info" | expect 4 jq -e '.[] | .signatures.[] | select(startswith("cache2.example.org"))' echo "$info" | expect 4 jq -e '.info.[] | .signatures.[] | select(startswith("cache2.example.org"))'
# Verify that adding a signature to a path in a binary cache works. # Verify that adding a signature to a path in a binary cache works.
nix store sign --store file://"$cacheDir" --key-file "$TEST_ROOT"/sk2 "$outPath2" nix store sign --store file://"$cacheDir" --key-file "$TEST_ROOT"/sk2 "$outPath2"
info=$(nix path-info --store file://"$cacheDir" --json --json-format 2 "$outPath2") info=$(nix path-info --store file://"$cacheDir" --json --json-format 2 "$outPath2")
echo "$info" | jq -e '.[] | .signatures.[] | select(startswith("cache1.example.org"))' echo "$info" | jq -e '.info.[] | .signatures.[] | select(startswith("cache1.example.org"))'
echo "$info" | jq -e '.[] | .signatures.[] | select(startswith("cache2.example.org"))' echo "$info" | jq -e '.info.[] | .signatures.[] | select(startswith("cache2.example.org"))'
# Copying to a diverted store should fail due to a lack of signatures by trusted keys. # Copying to a diverted store should fail due to a lack of signatures by trusted keys.
chmod -R u+w "$TEST_ROOT"/store0 || true chmod -R u+w "$TEST_ROOT"/store0 || true