diff --git a/doc/manual/change-authors.yml b/doc/manual/change-authors.yml index 193c087c7..ea4fdd938 100644 --- a/doc/manual/change-authors.yml +++ b/doc/manual/change-authors.yml @@ -236,6 +236,11 @@ vigress8: forgejo: vigress8 github: vigress8 +vlinkz: + display_name: Victor Fuentes + forgejo: vlinkz + github: vlinkz + winter: forgejo: winter github: winterqt diff --git a/doc/manual/rl-next/nix-store-ls-read-nar-listings.md b/doc/manual/rl-next/nix-store-ls-read-nar-listings.md new file mode 100644 index 000000000..e394670c4 --- /dev/null +++ b/doc/manual/rl-next/nix-store-ls-read-nar-listings.md @@ -0,0 +1,12 @@ +--- +synopsis: Allow `nix store ls` to read nar listings from binary cache stores. +issues: [] +cls: [3225] +category: Improvements +credits: [vlinkz] +--- + +The `nix store ls` command now supports reading `.ls` nar listings from binary cache stores. +If a listing is detected for the store path being queried, the nar is no longer downloaded. +These nar listings are available in binary cache stores where the `write-nar-listing` option is +enabled, such as cache.nixos.org. diff --git a/lix/nix/ls.cc b/lix/nix/ls.cc index dcdd035ae..4f6de63cd 100644 --- a/lix/nix/ls.cc +++ b/lix/nix/ls.cc @@ -1,4 +1,5 @@ #include "lix/libcmd/command.hh" +#include "lix/libstore/binary-cache-store.hh" #include "lix/libstore/store-api.hh" #include "lix/libstore/fs-accessor.hh" #include "lix/libstore/nar-accessor.hh" @@ -123,7 +124,24 @@ struct CmdLsStore : StoreCommand, MixLs void run(ref store) override { - list(store->getFSAccessor()); + auto accessor = store->getFSAccessor(); + + try { + auto binaryCacheStore = store.try_cast_shared(); + if (binaryCacheStore) { + const auto [storePath, restPath] = store->toStorePath(path); + auto file = binaryCacheStore->getFile(fmt("%s.ls", storePath.hashPart()))->drain(); + JSON j = json::parse(std::move(file), "a nar content listing"); + if (j["version"] == 1) { + path = restPath; + accessor = makeLazyNarAccessor(j["root"].dump(), [](uint64_t, uint64_t) -> std::string { + throw Error("attempted to read NAR content during listing"); + }); + } + } + } catch (NoSuchBinaryCacheFile &) { } + + list(accessor); } }; diff --git a/tests/functional/nar-access.sh b/tests/functional/nar-access.sh index 426068e68..af22a87eb 100644 --- a/tests/functional/nar-access.sh +++ b/tests/functional/nar-access.sh @@ -59,3 +59,23 @@ if nix-store --dump $storePath >/dev/full ; then echo "dumping to /dev/full should fail" exit -1 fi + + +# Test reading from remote nar listings if available + +nix copy --to "file://$cacheDir?write-nar-listing=true" $storePath + +export _NIX_FORCE_HTTP=1 + +diff -u \ + <(nix store ls --json $storePath --store "file://$cacheDir" | jq -S) \ + <(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S) +diff -u \ + <(nix store ls --json -R $storePath/foo/bar --store "file://$cacheDir" | jq -S) \ + <(echo '{"narOffset": 368,"type":"regular","size":0}' | jq -S) + +# Confirm that we are reading from ".ls" file by deleting the nar +rm -rf $cacheDir/nar +diff -u \ + <(nix store ls --json -R $storePath/foo/bar --store "file://$cacheDir" | jq -S) \ + <(echo '{"narOffset": 368,"type":"regular","size":0}' | jq -S)