Merge pull request #3858 from edolstra/group-commands

Group 'nix' subcommands
This commit is contained in:
Eelco Dolstra 2020-12-03 23:55:28 +01:00 committed by GitHub
commit 8df58eae4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 297 additions and 139 deletions

View file

@ -86,6 +86,7 @@ void Args::parseCmdline(const Strings & _cmdline)
throw UsageError("unrecognised flag '%1%'", arg); throw UsageError("unrecognised flag '%1%'", arg);
} }
else { else {
pos = rewriteArgs(cmdline, pos);
pendingArgs.push_back(*pos++); pendingArgs.push_back(*pos++);
if (processArgs(pendingArgs, false)) if (processArgs(pendingArgs, false))
pendingArgs.clear(); pendingArgs.clear();
@ -390,10 +391,6 @@ MultiCommand::MultiCommand(const Commands & commands)
.optional = true, .optional = true,
.handler = {[=](std::string s) { .handler = {[=](std::string s) {
assert(!command); assert(!command);
if (auto alias = get(deprecatedAliases, s)) {
warn("'%s' is a deprecated alias for '%s'", s, *alias);
s = *alias;
}
if (auto prefix = needsCompletion(s)) { if (auto prefix = needsCompletion(s)) {
for (auto & [name, command] : commands) for (auto & [name, command] : commands)
if (hasPrefix(name, *prefix)) if (hasPrefix(name, *prefix))

View file

@ -115,6 +115,9 @@ protected:
virtual bool processArgs(const Strings & args, bool finish); virtual bool processArgs(const Strings & args, bool finish);
virtual Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos)
{ return pos; }
std::set<std::string> hiddenCategories; std::set<std::string> hiddenCategories;
public: public:
@ -257,8 +260,6 @@ public:
std::map<Command::Category, std::string> categories; std::map<Command::Category, std::string> categories;
std::map<std::string, std::string> deprecatedAliases;
// Selected command, if any. // Selected command, if any.
std::optional<std::pair<std::string, ref<Command>>> command; std::optional<std::pair<std::string, ref<Command>>> command;

View file

@ -43,8 +43,6 @@ struct CmdAddToStore : MixDryRun, StoreCommand
; ;
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
if (!namePart) namePart = baseNameOf(path); if (!namePart) namePart = baseNameOf(path);
@ -80,4 +78,4 @@ struct CmdAddToStore : MixDryRun, StoreCommand
} }
}; };
static auto rCmdAddToStore = registerCommand<CmdAddToStore>("add-to-store"); static auto rCmdAddToStore = registerCommand2<CmdAddToStore>({"store", "add-path"});

View file

@ -37,8 +37,6 @@ struct CmdCatStore : StoreCommand, MixCat
return "print the contents of a file in the Nix store on stdout"; return "print the contents of a file in the Nix store on stdout";
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
cat(store->getFSAccessor()); cat(store->getFSAccessor());
@ -64,13 +62,11 @@ struct CmdCatNar : StoreCommand, MixCat
return "print the contents of a file inside a NAR file on stdout"; return "print the contents of a file inside a NAR file on stdout";
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
cat(makeNarAccessor(make_ref<std::string>(readFile(narPath)))); cat(makeNarAccessor(make_ref<std::string>(readFile(narPath))));
} }
}; };
static auto rCmdCatStore = registerCommand<CmdCatStore>("cat-store"); static auto rCmdCatStore = registerCommand2<CmdCatStore>({"store", "cat"});
static auto rCmdCatNar = registerCommand<CmdCatNar>("cat-nar"); static auto rCmdCatNar = registerCommand2<CmdCatNar>({"nar", "cat"});

View file

@ -11,7 +11,21 @@ extern char * * environ __attribute__((weak));
namespace nix { namespace nix {
Commands * RegisterCommand::commands = nullptr; RegisterCommand::Commands * RegisterCommand::commands = nullptr;
nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
{
nix::Commands res;
for (auto & [name, command] : *RegisterCommand::commands)
if (name.size() == prefix.size() + 1) {
bool equal = true;
for (size_t i = 0; i < prefix.size(); ++i)
if (name[i] != prefix[i]) equal = false;
if (equal)
res.insert_or_assign(name[prefix.size()], command);
}
return res;
}
void NixMultiCommand::printHelp(const string & programName, std::ostream & out) void NixMultiCommand::printHelp(const string & programName, std::ostream & out)
{ {

View file

@ -176,20 +176,29 @@ struct StorePathCommand : public InstallablesCommand
/* A helper class for registering commands globally. */ /* A helper class for registering commands globally. */
struct RegisterCommand struct RegisterCommand
{ {
typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands;
static Commands * commands; static Commands * commands;
RegisterCommand(const std::string & name, RegisterCommand(std::vector<std::string> && name,
std::function<ref<Command>()> command) std::function<ref<Command>()> command)
{ {
if (!commands) commands = new Commands; if (!commands) commands = new Commands;
commands->emplace(name, command); commands->emplace(name, command);
} }
static nix::Commands getCommandsFor(const std::vector<std::string> & prefix);
}; };
template<class T> template<class T>
static RegisterCommand registerCommand(const std::string & name) static RegisterCommand registerCommand(const std::string & name)
{ {
return RegisterCommand(name, [](){ return make_ref<T>(); }); return RegisterCommand({name}, [](){ return make_ref<T>(); });
}
template<class T>
static RegisterCommand registerCommand2(std::vector<std::string> && name)
{
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
} }
Buildables build(ref<Store> store, Realise mode, Buildables build(ref<Store> store, Realise mode,

View file

@ -121,14 +121,12 @@ struct CmdDiffClosures : SourceExprCommand
return "show what packages and versions were added and removed between two closures"; return "show what packages and versions were added and removed between two closures";
} }
Category category() override { return catSecondary; }
Examples examples() override Examples examples() override
{ {
return { return {
{ {
"To show what got added and removed between two versions of the NixOS system profile:", "To show what got added and removed between two versions of the NixOS system profile:",
"nix diff-closures /nix/var/nix/profiles/system-655-link /nix/var/nix/profiles/system-658-link", "nix store diff-closures /nix/var/nix/profiles/system-655-link /nix/var/nix/profiles/system-658-link",
}, },
}; };
} }
@ -143,4 +141,4 @@ struct CmdDiffClosures : SourceExprCommand
} }
}; };
static auto rCmdDiffClosures = registerCommand<CmdDiffClosures>("diff-closures"); static auto rCmdDiffClosures = registerCommand2<CmdDiffClosures>({"store", "diff-closures"});

View file

@ -1,5 +1,6 @@
#include "command.hh" #include "command.hh"
#include "store-api.hh" #include "store-api.hh"
#include "archive.hh"
using namespace nix; using namespace nix;
@ -7,7 +8,7 @@ struct CmdDumpPath : StorePathCommand
{ {
std::string description() override std::string description() override
{ {
return "dump a store path to stdout (in NAR format)"; return "serialise a store path to stdout in NAR format";
} }
Examples examples() override Examples examples() override
@ -15,13 +16,11 @@ struct CmdDumpPath : StorePathCommand
return { return {
Example{ Example{
"To get a NAR from the binary cache https://cache.nixos.org/:", "To get a NAR from the binary cache https://cache.nixos.org/:",
"nix dump-path --store https://cache.nixos.org/ /nix/store/7crrmih8c52r8fbnqb933dxrsp44md93-glibc-2.25" "nix store dump-path --store https://cache.nixos.org/ /nix/store/7crrmih8c52r8fbnqb933dxrsp44md93-glibc-2.25"
}, },
}; };
} }
Category category() override { return catUtility; }
void run(ref<Store> store, const StorePath & storePath) override void run(ref<Store> store, const StorePath & storePath) override
{ {
FdSink sink(STDOUT_FILENO); FdSink sink(STDOUT_FILENO);
@ -30,4 +29,42 @@ struct CmdDumpPath : StorePathCommand
} }
}; };
static auto rDumpPath = registerCommand<CmdDumpPath>("dump-path"); static auto rDumpPath = registerCommand2<CmdDumpPath>({"store", "dump-path"});
struct CmdDumpPath2 : Command
{
Path path;
CmdDumpPath2()
{
expectArgs({
.label = "path",
.handler = {&path},
.completer = completePath
});
}
std::string description() override
{
return "serialise a path to stdout in NAR format";
}
Examples examples() override
{
return {
Example{
"To serialise directory 'foo' as a NAR:",
"nix nar dump-path ./foo"
},
};
}
void run() override
{
FdSink sink(STDOUT_FILENO);
dumpPath(path, sink);
sink.flush();
}
};
static auto rDumpPath2 = registerCommand2<CmdDumpPath2>({"nar", "dump-path"});

View file

@ -8,7 +8,7 @@
using namespace nix; using namespace nix;
struct CmdHash : Command struct CmdHashBase : Command
{ {
FileIngestionMethod mode; FileIngestionMethod mode;
Base base = SRI; Base base = SRI;
@ -17,7 +17,7 @@ struct CmdHash : Command
std::vector<std::string> paths; std::vector<std::string> paths;
std::optional<std::string> modulus; std::optional<std::string> modulus;
CmdHash(FileIngestionMethod mode) : mode(mode) CmdHashBase(FileIngestionMethod mode) : mode(mode)
{ {
mkFlag(0, "sri", "print hash in SRI format", &base, SRI); mkFlag(0, "sri", "print hash in SRI format", &base, SRI);
mkFlag(0, "base64", "print hash in base-64", &base, Base64); mkFlag(0, "base64", "print hash in base-64", &base, Base64);
@ -51,8 +51,6 @@ struct CmdHash : Command
return d; return d;
} }
Category category() override { return catUtility; }
void run() override void run() override
{ {
for (auto path : paths) { for (auto path : paths) {
@ -79,9 +77,6 @@ struct CmdHash : Command
} }
}; };
static RegisterCommand rCmdHashFile("hash-file", [](){ return make_ref<CmdHash>(FileIngestionMethod::Flat); });
static RegisterCommand rCmdHashPath("hash-path", [](){ return make_ref<CmdHash>(FileIngestionMethod::Recursive); });
struct CmdToBase : Command struct CmdToBase : Command
{ {
Base base; Base base;
@ -103,8 +98,6 @@ struct CmdToBase : Command
"SRI"); "SRI");
} }
Category category() override { return catUtility; }
void run() override void run() override
{ {
for (auto s : args) for (auto s : args)
@ -112,10 +105,41 @@ struct CmdToBase : Command
} }
}; };
static RegisterCommand rCmdToBase16("to-base16", [](){ return make_ref<CmdToBase>(Base16); }); struct CmdHash : NixMultiCommand
static RegisterCommand rCmdToBase32("to-base32", [](){ return make_ref<CmdToBase>(Base32); }); {
static RegisterCommand rCmdToBase64("to-base64", [](){ return make_ref<CmdToBase>(Base64); }); CmdHash()
static RegisterCommand rCmdToSRI("to-sri", [](){ return make_ref<CmdToBase>(SRI); }); : MultiCommand({
{"file", []() { return make_ref<CmdHashBase>(FileIngestionMethod::Flat);; }},
{"path", []() { return make_ref<CmdHashBase>(FileIngestionMethod::Recursive); }},
{"to-base16", []() { return make_ref<CmdToBase>(Base16); }},
{"to-base32", []() { return make_ref<CmdToBase>(Base32); }},
{"to-base64", []() { return make_ref<CmdToBase>(Base64); }},
{"to-sri", []() { return make_ref<CmdToBase>(SRI); }},
})
{ }
std::string description() override
{
return "compute and convert cryptographic hashes";
}
Category category() override { return catUtility; }
void run() override
{
if (!command)
throw UsageError("'nix hash' requires a sub-command.");
command->second->prepare();
command->second->run();
}
void printHelp(const string & programName, std::ostream & out) override
{
MultiCommand::printHelp(programName, out);
}
};
static auto rCmdHash = registerCommand<CmdHash>("hash");
/* Legacy nix-hash command. */ /* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv) static int compatNixHash(int argc, char * * argv)
@ -149,7 +173,7 @@ static int compatNixHash(int argc, char * * argv)
}); });
if (op == opHash) { if (op == opHash) {
CmdHash cmd(flat ? FileIngestionMethod::Flat : FileIngestionMethod::Recursive); CmdHashBase cmd(flat ? FileIngestionMethod::Flat : FileIngestionMethod::Recursive);
cmd.ht = ht; cmd.ht = ht;
cmd.base = base32 ? Base32 : Base16; cmd.base = base32 ? Base32 : Base16;
cmd.truncate = truncate; cmd.truncate = truncate;

View file

@ -97,7 +97,7 @@ struct CmdLsStore : StoreCommand, MixLs
return { return {
Example{ Example{
"To list the contents of a store path in a binary cache:", "To list the contents of a store path in a binary cache:",
"nix ls-store --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10" "nix store ls --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10"
}, },
}; };
} }
@ -107,8 +107,6 @@ struct CmdLsStore : StoreCommand, MixLs
return "show information about a path in the Nix store"; return "show information about a path in the Nix store";
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
list(store->getFSAccessor()); list(store->getFSAccessor());
@ -134,7 +132,7 @@ struct CmdLsNar : Command, MixLs
return { return {
Example{ Example{
"To list a specific file in a NAR:", "To list a specific file in a NAR:",
"nix ls-nar -l hello.nar /bin/hello" "nix nar ls -l hello.nar /bin/hello"
}, },
}; };
} }
@ -144,13 +142,11 @@ struct CmdLsNar : Command, MixLs
return "show information about a path inside a NAR file"; return "show information about a path inside a NAR file";
} }
Category category() override { return catUtility; }
void run() override void run() override
{ {
list(makeNarAccessor(make_ref<std::string>(readFile(narPath)))); list(makeNarAccessor(make_ref<std::string>(readFile(narPath))));
} }
}; };
static auto rCmdLsStore = registerCommand<CmdLsStore>("ls-store"); static auto rCmdLsStore = registerCommand2<CmdLsStore>({"store", "ls"});
static auto rCmdLsNar = registerCommand<CmdLsNar>("ls-nar"); static auto rCmdLsNar = registerCommand2<CmdLsNar>({"nar", "ls"});

View file

@ -59,7 +59,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
bool useNet = true; bool useNet = true;
bool refresh = false; bool refresh = false;
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix")
{ {
categories.clear(); categories.clear();
categories[Command::catDefault] = "Main commands"; categories[Command::catDefault] = "Main commands";
@ -112,8 +112,45 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
.description = "consider all previously downloaded files out-of-date", .description = "consider all previously downloaded files out-of-date",
.handler = {[&]() { refresh = true; }}, .handler = {[&]() { refresh = true; }},
}); });
}
deprecatedAliases.insert({"dev-shell", "develop"}); std::map<std::string, std::vector<std::string>> aliases = {
{"add-to-store", {"store", "add-path"}},
{"cat-nar", {"nar", "cat"}},
{"cat-store", {"store", "cat"}},
{"copy-sigs", {"store", "copy-sigs"}},
{"dev-shell", {"develop"}},
{"diff-closures", {"store", "diff-closures"}},
{"dump-path", {"store", "dump-path"}},
{"hash-file", {"hash", "file"}},
{"hash-path", {"hash", "path"}},
{"ls-nar", {"nar", "ls"}},
{"ls-store", {"store", "ls"}},
{"make-content-addressable", {"store", "make-content-addressable"}},
{"optimise-store", {"store", "optimise"}},
{"ping-store", {"store", "ping"}},
{"sign-paths", {"store", "sign-paths"}},
{"to-base16", {"hash", "to-base16"}},
{"to-base32", {"hash", "to-base32"}},
{"to-base64", {"hash", "to-base64"}},
{"verify", {"store", "verify"}},
};
bool aliasUsed = false;
Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override
{
if (aliasUsed || command || pos == args.end()) return pos;
auto arg = *pos;
auto i = aliases.find(arg);
if (i == aliases.end()) return pos;
warn("'%s' is a deprecated alias for '%s'",
arg, concatStringsSep(" ", i->second));
pos = args.erase(pos);
for (auto j = i->second.rbegin(); j != i->second.rend(); ++j)
pos = args.insert(pos, *j);
aliasUsed = true;
return pos;
} }
void printFlags(std::ostream & out) override void printFlags(std::ostream & out) override

View file

@ -23,17 +23,15 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
return { return {
Example{ Example{
"To create a content-addressable representation of GNU Hello (but not its dependencies):", "To create a content-addressable representation of GNU Hello (but not its dependencies):",
"nix make-content-addressable nixpkgs#hello" "nix store make-content-addressable nixpkgs#hello"
}, },
Example{ Example{
"To compute a content-addressable representation of the current NixOS system closure:", "To compute a content-addressable representation of the current NixOS system closure:",
"nix make-content-addressable -r /run/current-system" "nix store make-content-addressable -r /run/current-system"
}, },
}; };
} }
Category category() override { return catUtility; }
void run(ref<Store> store, StorePaths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
auto paths = store->topoSortPaths(StorePathSet(storePaths.begin(), storePaths.end())); auto paths = store->topoSortPaths(StorePathSet(storePaths.begin(), storePaths.end()));
@ -108,4 +106,4 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
} }
}; };
static auto rCmdMakeContentAddressable = registerCommand<CmdMakeContentAddressable>("make-content-addressable"); static auto rCmdMakeContentAddressable = registerCommand2<CmdMakeContentAddressable>({"store", "make-content-addressable"});

31
src/nix/nar.cc Normal file
View file

@ -0,0 +1,31 @@
#include "command.hh"
using namespace nix;
struct CmdNar : NixMultiCommand
{
CmdNar() : MultiCommand(RegisterCommand::getCommandsFor({"nar"}))
{ }
std::string description() override
{
return "query the contents of NAR files";
}
Category category() override { return catUtility; }
void run() override
{
if (!command)
throw UsageError("'nix nar' requires a sub-command.");
command->second->prepare();
command->second->run();
}
void printHelp(const string & programName, std::ostream & out) override
{
MultiCommand::printHelp(programName, out);
}
};
static auto rCmdNar = registerCommand<CmdNar>("nar");

View file

@ -18,17 +18,15 @@ struct CmdOptimiseStore : StoreCommand
return { return {
Example{ Example{
"To optimise the Nix store:", "To optimise the Nix store:",
"nix optimise-store" "nix store optimise"
}, },
}; };
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
store->optimiseStore(); store->optimiseStore();
} }
}; };
static auto rCmdOptimiseStore = registerCommand<CmdOptimiseStore>("optimise-store"); static auto rCmdOptimiseStore = registerCommand2<CmdOptimiseStore>({"store", "optimise"});

View file

@ -16,17 +16,15 @@ struct CmdPingStore : StoreCommand
return { return {
Example{ Example{
"To test whether connecting to a remote Nix store via SSH works:", "To test whether connecting to a remote Nix store via SSH works:",
"nix ping-store --store ssh://mac1" "nix store ping --store ssh://mac1"
}, },
}; };
} }
Category category() override { return catUtility; }
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
store->connect(); store->connect();
} }
}; };
static auto rCmdPingStore = registerCommand<CmdPingStore>("ping-store"); static auto rCmdPingStore = registerCommand2<CmdPingStore>({"store", "ping"});

View file

@ -413,7 +413,7 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile
return { return {
Example{ Example{
"To show what changed between each generation of the NixOS system profile:", "To show what changed between each generation of the NixOS system profile:",
"nix profile diff-closure --profile /nix/var/nix/profiles/system" "nix profile diff-closures --profile /nix/var/nix/profiles/system"
}, },
}; };
} }

View file

@ -1,4 +1,5 @@
// FIXME: integrate this with nix path-info? // FIXME: integrate this with nix path-info?
// FIXME: rename to 'nix store show-derivation' or 'nix debug show-derivation'?
#include "command.hh" #include "command.hh"
#include "common-args.hh" #include "common-args.hh"

View file

@ -27,8 +27,6 @@ struct CmdCopySigs : StorePathsCommand
return "copy path signatures from substituters (like binary caches)"; return "copy path signatures from substituters (like binary caches)";
} }
Category category() override { return catUtility; }
void run(ref<Store> store, StorePaths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
if (substituterUris.empty()) if (substituterUris.empty())
@ -92,7 +90,7 @@ struct CmdCopySigs : StorePathsCommand
} }
}; };
static auto rCmdCopySigs = registerCommand<CmdCopySigs>("copy-sigs"); static auto rCmdCopySigs = registerCommand2<CmdCopySigs>({"store", "copy-sigs"});
struct CmdSignPaths : StorePathsCommand struct CmdSignPaths : StorePathsCommand
{ {
@ -115,8 +113,6 @@ struct CmdSignPaths : StorePathsCommand
return "sign the specified paths"; return "sign the specified paths";
} }
Category category() override { return catUtility; }
void run(ref<Store> store, StorePaths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
if (secretKeyFile.empty()) if (secretKeyFile.empty())
@ -144,4 +140,4 @@ struct CmdSignPaths : StorePathsCommand
} }
}; };
static auto rCmdSignPaths = registerCommand<CmdSignPaths>("sign-paths"); static auto rCmdSignPaths = registerCommand2<CmdSignPaths>({"store", "sign-paths"});

31
src/nix/store.cc Normal file
View file

@ -0,0 +1,31 @@
#include "command.hh"
using namespace nix;
struct CmdStore : virtual NixMultiCommand
{
CmdStore() : MultiCommand(RegisterCommand::getCommandsFor({"store"}))
{ }
std::string description() override
{
return "manipulate a Nix store";
}
Category category() override { return catUtility; }
void run() override
{
if (!command)
throw UsageError("'nix store' requires a sub-command.");
command->second->prepare();
command->second->run();
}
void printHelp(const string & programName, std::ostream & out) override
{
MultiCommand::printHelp(programName, out);
}
};
static auto rCmdStore = registerCommand<CmdStore>("store");

View file

@ -40,17 +40,15 @@ struct CmdVerify : StorePathsCommand
return { return {
Example{ Example{
"To verify the entire Nix store:", "To verify the entire Nix store:",
"nix verify --all" "nix store verify --all"
}, },
Example{ Example{
"To check whether each path in the closure of Firefox has at least 2 signatures:", "To check whether each path in the closure of Firefox has at least 2 signatures:",
"nix verify -r -n2 --no-contents $(type -p firefox)" "nix store verify -r -n2 --no-contents $(type -p firefox)"
}, },
}; };
} }
Category category() override { return catSecondary; }
void run(ref<Store> store, StorePaths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
std::vector<ref<Store>> substituters; std::vector<ref<Store>> substituters;
@ -189,4 +187,4 @@ struct CmdVerify : StorePathsCommand
} }
}; };
static auto rCmdVerify = registerCommand<CmdVerify>("verify"); static auto rCmdVerify = registerCommand2<CmdVerify>({"store", "verify"});

View file

@ -188,7 +188,7 @@ unset _NIX_FORCE_HTTP
# Test 'nix verify --all' on a binary cache. # Test 'nix verify --all' on a binary cache.
nix verify -vvvvv --all --store file://$cacheDir --no-trust nix store verify -vvvvv --all --store file://$cacheDir --no-trust
# Test local NAR caching. # Test local NAR caching.
@ -196,13 +196,13 @@ narCache=$TEST_ROOT/nar-cache
rm -rf $narCache rm -rf $narCache
mkdir $narCache mkdir $narCache
[[ $(nix cat-store --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] [[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]]
rm -rfv "$cacheDir/nar" rm -rfv "$cacheDir/nar"
[[ $(nix cat-store --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] [[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]]
(! nix cat-store --store file://$cacheDir $outPath/foobar) (! nix store cat --store file://$cacheDir $outPath/foobar)
# Test NAR listing generation. # Test NAR listing generation.

View file

@ -9,13 +9,13 @@ outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to $cacheURI $outPath nix copy --to $cacheURI $outPath
HASH=$(nix hash-path $outPath) HASH=$(nix hash path $outPath)
clearStore clearStore
clearCacheCache clearCacheCache
nix copy --from $cacheURI $outPath --no-check-sigs nix copy --from $cacheURI $outPath --no-check-sigs
HASH2=$(nix hash-path $outPath) HASH2=$(nix hash path $outPath)
[[ $HASH = $HASH2 ]] [[ $HASH = $HASH2 ]]

View file

@ -12,7 +12,7 @@ cmp $outPath fetchurl.sh
# Now using a base-64 hash. # Now using a base-64 hash.
clearStore clearStore
hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh) hash=$(nix hash file --type sha512 --base64 ./fetchurl.sh)
outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha512 $hash --no-out-link) outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha512 $hash --no-out-link)
@ -21,7 +21,7 @@ cmp $outPath fetchurl.sh
# Now using an SRI hash. # Now using an SRI hash.
clearStore clearStore
hash=$(nix hash-file ./fetchurl.sh) hash=$(nix hash file ./fetchurl.sh)
[[ $hash =~ ^sha256- ]] [[ $hash =~ ^sha256- ]]
@ -34,14 +34,14 @@ clearStore
other_store=file://$TEST_ROOT/other_store?store=/fnord/store other_store=file://$TEST_ROOT/other_store?store=/fnord/store
hash=$(nix hash-file --type sha256 --base16 ./fetchurl.sh) hash=$(nix hash file --type sha256 --base16 ./fetchurl.sh)
storePath=$(nix --store $other_store add-to-store --flat ./fetchurl.sh) storePath=$(nix --store $other_store store add-path --flat ./fetchurl.sh)
outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha256 $hash --no-out-link --substituters $other_store) outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha256 $hash --no-out-link --substituters $other_store)
# Test hashed mirrors with an SRI hash. # Test hashed mirrors with an SRI hash.
nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr hash $(nix to-sri --type sha256 $hash) \ nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr hash $(nix hash to-sri --type sha256 $hash) \
--no-out-link --substituters $other_store --no-out-link --substituters $other_store
# Test unpacking a NAR. # Test unpacking a NAR.

View file

@ -2,9 +2,9 @@ source common.sh
clearStore clearStore
garbage1=$(nix add-to-store --name garbage1 ./nar-access.sh) garbage1=$(nix store add-path --name garbage1 ./nar-access.sh)
garbage2=$(nix add-to-store --name garbage2 ./nar-access.sh) garbage2=$(nix store add-path --name garbage2 ./nar-access.sh)
garbage3=$(nix add-to-store --name garbage3 ./nar-access.sh) garbage3=$(nix store add-path --name garbage3 ./nar-access.sh)
ls -l $garbage3 ls -l $garbage3
POSIXLY_CORRECT=1 du $garbage3 POSIXLY_CORRECT=1 du $garbage3

View file

@ -2,7 +2,7 @@ source common.sh
try () { try () {
printf "%s" "$2" > $TEST_ROOT/vector printf "%s" "$2" > $TEST_ROOT/vector
hash=$(nix hash-file --base16 $EXTRA --type "$1" $TEST_ROOT/vector) hash=$(nix hash file --base16 $EXTRA --type "$1" $TEST_ROOT/vector)
if test "$hash" != "$3"; then if test "$hash" != "$3"; then
echo "hash $1, expected $3, got $hash" echo "hash $1, expected $3, got $hash"
exit 1 exit 1
@ -69,17 +69,17 @@ try2 md5 "f78b733a68f5edbdf9413899339eaa4a"
# Conversion. # Conversion.
try3() { try3() {
h64=$(nix to-base64 --type "$1" "$2") h64=$(nix hash to-base64 --type "$1" "$2")
[ "$h64" = "$4" ] [ "$h64" = "$4" ]
sri=$(nix to-sri --type "$1" "$2") sri=$(nix hash to-sri --type "$1" "$2")
[ "$sri" = "$1-$4" ] [ "$sri" = "$1-$4" ]
h32=$(nix-hash --type "$1" --to-base32 "$2") h32=$(nix-hash --type "$1" --to-base32 "$2")
[ "$h32" = "$3" ] [ "$h32" = "$3" ]
h16=$(nix-hash --type "$1" --to-base16 "$h32") h16=$(nix-hash --type "$1" --to-base16 "$h32")
[ "$h16" = "$2" ] [ "$h16" = "$2" ]
h16=$(nix to-base16 --type "$1" "$h64") h16=$(nix hash to-base16 --type "$1" "$h64")
[ "$h16" = "$2" ] [ "$h16" = "$2" ]
h16=$(nix to-base16 "$sri") h16=$(nix hash to-base16 "$sri")
[ "$h16" = "$2" ] [ "$h16" = "$2" ]
} }
try3 sha1 "800d59cfcd3c05e900cb4e214be48f6b886a08df" "vw46m23bizj4n8afrc0fj19wrp7mj3c0" "gA1Zz808BekAy04hS+SPa4hqCN8=" try3 sha1 "800d59cfcd3c05e900cb4e214be48f6b886a08df" "vw46m23bizj4n8afrc0fj19wrp7mj3c0" "gA1Zz808BekAy04hS+SPa4hqCN8="

View file

@ -22,9 +22,9 @@ outPath=$(nix-build dependencies.nix --no-out-link --sandbox-paths /nix/store)
nix path-info -r $outPath | grep input-2 nix path-info -r $outPath | grep input-2
nix ls-store -R -l $outPath | grep foobar nix store ls -R -l $outPath | grep foobar
nix cat-store $outPath/foobar | grep FOOBAR nix store cat $outPath/foobar | grep FOOBAR
# Test --check without hash rewriting. # Test --check without hash rewriting.
nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store

View file

@ -9,45 +9,45 @@ cd "$TEST_ROOT"
narFile="$TEST_ROOT/path.nar" narFile="$TEST_ROOT/path.nar"
nix-store --dump $storePath > $narFile nix-store --dump $storePath > $narFile
# Check that find and ls-nar match. # Check that find and nar ls match.
( cd $storePath; find . | sort ) > files.find ( cd $storePath; find . | sort ) > files.find
nix ls-nar -R -d $narFile "" | sort > files.ls-nar nix nar ls -R -d $narFile "" | sort > files.ls-nar
diff -u files.find files.ls-nar diff -u files.find files.ls-nar
# Check that file contents of data match. # Check that file contents of data match.
nix cat-nar $narFile /foo/data > data.cat-nar nix nar cat $narFile /foo/data > data.cat-nar
diff -u data.cat-nar $storePath/foo/data diff -u data.cat-nar $storePath/foo/data
# Check that file contents of baz match. # Check that file contents of baz match.
nix cat-nar $narFile /foo/baz > baz.cat-nar nix nar cat $narFile /foo/baz > baz.cat-nar
diff -u baz.cat-nar $storePath/foo/baz diff -u baz.cat-nar $storePath/foo/baz
nix cat-store $storePath/foo/baz > baz.cat-nar nix store cat $storePath/foo/baz > baz.cat-nar
diff -u baz.cat-nar $storePath/foo/baz diff -u baz.cat-nar $storePath/foo/baz
# Test --json. # Test --json.
diff -u \ diff -u \
<(nix ls-nar --json $narFile / | jq -S) \ <(nix nar ls --json $narFile / | jq -S) \
<(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S) <(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S)
diff -u \ diff -u \
<(nix ls-nar --json -R $narFile /foo | jq -S) \ <(nix nar ls --json -R $narFile /foo | jq -S) \
<(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0,"narOffset":368},"baz":{"type":"regular","size":0,"narOffset":552},"data":{"type":"regular","size":58,"narOffset":736}}}' | jq -S) <(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0,"narOffset":368},"baz":{"type":"regular","size":0,"narOffset":552},"data":{"type":"regular","size":58,"narOffset":736}}}' | jq -S)
diff -u \ diff -u \
<(nix ls-nar --json -R $narFile /foo/bar | jq -S) \ <(nix nar ls --json -R $narFile /foo/bar | jq -S) \
<(echo '{"type":"regular","size":0,"narOffset":368}' | jq -S) <(echo '{"type":"regular","size":0,"narOffset":368}' | jq -S)
diff -u \ diff -u \
<(nix ls-store --json $storePath | jq -S) \ <(nix store ls --json $storePath | jq -S) \
<(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S) <(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S)
diff -u \ diff -u \
<(nix ls-store --json -R $storePath/foo | jq -S) \ <(nix store ls --json -R $storePath/foo | jq -S) \
<(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0},"baz":{"type":"regular","size":0},"data":{"type":"regular","size":58}}}' | jq -S) <(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0},"baz":{"type":"regular","size":0},"data":{"type":"regular","size":58}}}' | jq -S)
diff -u \ diff -u \
<(nix ls-store --json -R $storePath/foo/bar| jq -S) \ <(nix store ls --json -R $storePath/foo/bar| jq -S) \
<(echo '{"type":"regular","size":0}' | jq -S) <(echo '{"type":"regular","size":0}' | jq -S)
# Test missing files. # Test missing files.
nix ls-store --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR' nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
nix ls-store $storePath/xyzzy 2>&1 | grep 'does not exist' nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
# Test failure to dump. # Test failure to dump.
if nix-store --dump $storePath >/dev/full ; then if nix-store --dump $storePath >/dev/full ; then

View file

@ -15,7 +15,7 @@ nix eval --expr 'assert 1 + 2 == 3; true'
[[ $(nix eval --impure --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") == 123 ]] [[ $(nix eval --impure --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") == 123 ]]
(! nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") (! nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x")
nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash-file pure-eval.nix --type sha256)\"; })).x" nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash file pure-eval.nix --type sha256)\"; })).x"
rm -rf $TEST_ROOT/eval-out rm -rf $TEST_ROOT/eval-out
nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "bar"; y = { z = "bla"; }; }' nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "bar"; y = { z = "bla"; }; }'

View file

@ -7,7 +7,7 @@ clearStore
rm -f $TEST_ROOT/result rm -f $TEST_ROOT/result
export unreachable=$(nix add-to-store ./recursive.sh) export unreachable=$(nix store add-path ./recursive.sh)
NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr ' NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr '
with import ./config.nix; with import ./config.nix;
@ -38,7 +38,7 @@ NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command r
# Add something to the store. # Add something to the store.
echo foobar > foobar echo foobar > foobar
foobar=$(nix $opts add-to-store ./foobar) foobar=$(nix $opts store add-path ./foobar)
nix $opts path-info $foobar nix $opts path-info $foobar
nix $opts build $foobar nix $opts build $foobar

View file

@ -17,40 +17,40 @@ info=$(nix path-info --json $outPath)
[[ $info =~ 'cache1.example.org' ]] [[ $info =~ 'cache1.example.org' ]]
[[ $info =~ 'cache2.example.org' ]] [[ $info =~ 'cache2.example.org' ]]
# Test "nix verify". # Test "nix store verify".
nix verify -r $outPath nix store verify -r $outPath
expect 2 nix verify -r $outPath --sigs-needed 1 expect 2 nix store verify -r $outPath --sigs-needed 1
nix verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1 nix store verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1
expect 2 nix verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1 expect 2 nix store verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1
nix verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" nix store verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"
nix verify --all --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" nix store verify --all --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"
# Build something unsigned. # Build something unsigned.
outPath2=$(nix-build simple.nix --no-out-link) outPath2=$(nix-build simple.nix --no-out-link)
nix verify -r $outPath 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 $outPath2) info=$(nix path-info --json $outPath2)
[[ $info =~ '"ultimate":true' ]] [[ $info =~ '"ultimate":true' ]]
(! [[ $info =~ 'signatures' ]]) (! [[ $info =~ 'signatures' ]])
# Test "nix verify". # Test "nix store verify".
nix verify -r $outPath2 nix store verify -r $outPath2
expect 2 nix verify -r $outPath2 --sigs-needed 1 expect 2 nix store verify -r $outPath2 --sigs-needed 1
expect 2 nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 expect 2 nix store verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1
# Test "nix sign-paths". # Test "nix store sign-paths".
nix sign-paths --key-file $TEST_ROOT/sk1 $outPath2 nix store sign-paths --key-file $TEST_ROOT/sk1 $outPath2
nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 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)
@ -59,12 +59,12 @@ outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no
# 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.
nix verify $outPathCA nix store verify $outPathCA
nix verify $outPathCA --sigs-needed 1000 nix store verify $outPathCA --sigs-needed 1000
# Check that signing a content-addressed path doesn't overflow validSigs # Check that signing a content-addressed path doesn't overflow validSigs
nix sign-paths --key-file $TEST_ROOT/sk1 $outPathCA nix store sign-paths --key-file $TEST_ROOT/sk1 $outPathCA
nix verify -r $outPathCA --sigs-needed 1000 --trusted-public-keys $pk1 nix store verify -r $outPathCA --sigs-needed 1000 --trusted-public-keys $pk1
# Copy to a binary cache. # Copy to a binary cache.
nix copy --to file://$cacheDir $outPath2 nix copy --to file://$cacheDir $outPath2
@ -76,7 +76,7 @@ info=$(nix path-info --store file://$cacheDir --json $outPath2)
(! [[ $info =~ 'cache2.example.org' ]]) (! [[ $info =~ '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 sign-paths --store file://$cacheDir --key-file $TEST_ROOT/sk2 $outPath2 nix store sign-paths --store file://$cacheDir --key-file $TEST_ROOT/sk2 $outPath2
info=$(nix path-info --store file://$cacheDir --json $outPath2) info=$(nix path-info --store file://$cacheDir --json $outPath2)
[[ $info =~ 'cache1.example.org' ]] [[ $info =~ 'cache1.example.org' ]]
[[ $info =~ 'cache2.example.org' ]] [[ $info =~ 'cache2.example.org' ]]
@ -89,17 +89,17 @@ rm -rf $TEST_ROOT/store0
# But succeed if we supply the public keys. # But succeed if we supply the public keys.
nix copy --to $TEST_ROOT/store0 $outPath --trusted-public-keys $pk1 nix copy --to $TEST_ROOT/store0 $outPath --trusted-public-keys $pk1
expect 2 nix verify --store $TEST_ROOT/store0 -r $outPath expect 2 nix store verify --store $TEST_ROOT/store0 -r $outPath
nix verify --store $TEST_ROOT/store0 -r $outPath --trusted-public-keys $pk1 nix store verify --store $TEST_ROOT/store0 -r $outPath --trusted-public-keys $pk1
nix verify --store $TEST_ROOT/store0 -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" nix store verify --store $TEST_ROOT/store0 -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2"
# It should also succeed if we disable signature checking. # It should also succeed if we disable signature checking.
(! nix copy --to $TEST_ROOT/store0 $outPath2) (! nix copy --to $TEST_ROOT/store0 $outPath2)
nix copy --to $TEST_ROOT/store0?require-sigs=false $outPath2 nix copy --to $TEST_ROOT/store0?require-sigs=false $outPath2
# But signatures should still get copied. # But signatures should still get copied.
nix verify --store $TEST_ROOT/store0 -r $outPath2 --trusted-public-keys $pk1 nix store verify --store $TEST_ROOT/store0 -r $outPath2 --trusted-public-keys $pk1
# Content-addressed stuff can be copied without signatures. # Content-addressed stuff can be copied without signatures.
nix copy --to $TEST_ROOT/store0 $outPathCA nix copy --to $TEST_ROOT/store0 $outPathCA

View file

@ -11,6 +11,6 @@ store+=$remote_store
store+=$remote_store store+=$remote_store
store+=$remote_store store+=$remote_store
out=$(nix add-to-store --store "$store" $TEST_ROOT/hello.sh) out=$(nix store add-path --store "$store" $TEST_ROOT/hello.sh)
[ foo = $(< $out) ] [ foo = $(< $out) ]

View file

@ -10,7 +10,7 @@ mkdir -p $tarroot
cp dependencies.nix $tarroot/default.nix cp dependencies.nix $tarroot/default.nix
cp config.nix dependencies.builder*.sh $tarroot/ cp config.nix dependencies.builder*.sh $tarroot/
hash=$(nix hash-path $tarroot) hash=$(nix hash path $tarroot)
test_tarball() { test_tarball() {
local ext="$1" local ext="$1"