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

Make nix nar cat work on pipes too

This was lost after 2.32 while making the accessor lazy. We can restore the support
for it pretty easily. Also this is significant optimization for nix nar cat.
E.g. with a NAR of a linux repo this speeds up by ~3x:

Benchmark 1: nix nar cat /tmp/linux.nar README
  Time (mean ± σ):     737.2 ms ±   5.6 ms    [User: 298.1 ms, System: 435.7 ms]
  Range (min … max):   728.6 ms … 746.9 ms    10 runs

Benchmark 2: build/src/nix/nix nar cat /tmp/linux.nar README
  Time (mean ± σ):     253.5 ms ±   2.9 ms    [User: 56.4 ms, System: 196.3 ms]
  Range (min … max):   248.1 ms … 258.7 ms    12 runs
This commit is contained in:
Sergei Zimmerman 2025-12-08 02:54:13 +03:00
parent b9b6defca6
commit c5c05e44b3
No known key found for this signature in database
3 changed files with 38 additions and 2 deletions

View file

@ -12,7 +12,7 @@ namespace nix {
*
* See `FileSystemObjectSink::createRegularFile`.
*/
struct CreateRegularFileSink : Sink
struct CreateRegularFileSink : virtual Sink
{
/**
* If set to true, the sink will not be called with the contents

View file

@ -1,5 +1,6 @@
#include "nix/cmd/command.hh"
#include "nix/store/store-api.hh"
#include "nix/util/archive.hh"
#include "nix/util/nar-accessor.hh"
#include "nix/util/serialise.hh"
#include "nix/util/source-accessor.hh"
@ -79,7 +80,40 @@ struct CmdCatNar : StoreCommand, MixCat
if (!fd)
throw SysError("opening NAR file '%s'", narPath);
auto source = FdSource{fd.get()};
cat(makeLazyNarAccessor(source, seekableGetNarBytes(fd.get())), CanonPath{path});
struct CatRegularFileSink : NullFileSystemObjectSink
{
CanonPath neededPath = CanonPath::root;
bool found = false;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> crf) override
{
struct : CreateRegularFileSink, FdSink
{
void isExecutable() override {}
} crfSink;
crfSink.fd = INVALID_DESCRIPTOR;
if (path == neededPath) {
logger->stop();
crfSink.skipContents = false;
crfSink.fd = STDOUT_FILENO;
found = true;
} else {
crfSink.skipContents = true;
}
crf(crfSink);
}
} sink;
sink.neededPath = CanonPath(path);
/* NOTE: We still parse the whole file to validate that it's a correct NAR. */
parseDump(sink, source);
if (!sink.found)
throw Error("NAR does not contain regular file '%1%'", path);
}
};

View file

@ -23,6 +23,8 @@ diff -u data.cat-nar "$storePath/foo/data"
# Check that file contents of baz match.
nix nar cat "$narFile" /foo/baz > baz.cat-nar
diff -u baz.cat-nar "$storePath/foo/baz"
nix nar cat /dev/stdin /foo/baz < "$narFile" > baz.cat-nar-pipe
expect 1 nix nar cat "$narFile" /foo/baz/doesntexist 2>&1 | grep "NAR does not contain regular file '/foo/baz/doesntexist'"
nix store cat "$storePath/foo/baz" > baz.cat-nar
diff -u baz.cat-nar "$storePath/foo/baz"