aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/add-to-store.cc7
-rw-r--r--src/nix/build.cc10
-rw-r--r--src/nix/cat.cc14
-rw-r--r--src/nix/command.cc74
-rw-r--r--src/nix/command.hh130
-rw-r--r--src/nix/copy.cc7
-rw-r--r--src/nix/doctor.cc7
-rw-r--r--src/nix/dump-path.cc7
-rw-r--r--src/nix/edit.cc7
-rw-r--r--src/nix/eval.cc7
-rw-r--r--src/nix/flake-template.nix15
-rw-r--r--src/nix/flake.cc527
-rw-r--r--src/nix/hash.cc26
-rw-r--r--src/nix/installables.cc403
-rw-r--r--src/nix/local.mk2
-rw-r--r--src/nix/log.cc11
-rw-r--r--src/nix/ls.cc14
-rw-r--r--src/nix/main.cc13
-rw-r--r--src/nix/optimise-store.cc11
-rw-r--r--src/nix/path-info.cc7
-rw-r--r--src/nix/ping-store.cc7
-rw-r--r--src/nix/repl.cc4
-rw-r--r--src/nix/run.cc112
-rw-r--r--src/nix/search.cc11
-rw-r--r--src/nix/shell.cc271
-rw-r--r--src/nix/show-config.cc11
-rw-r--r--src/nix/show-derivation.cc7
-rw-r--r--src/nix/sigs.cc14
-rw-r--r--src/nix/upgrade-nix.cc7
-rw-r--r--src/nix/verify.cc7
-rw-r--r--src/nix/why-depends.cc11
31 files changed, 1331 insertions, 430 deletions
diff --git a/src/nix/add-to-store.cc b/src/nix/add-to-store.cc
index e86b96e3f..296b2c7e4 100644
--- a/src/nix/add-to-store.cc
+++ b/src/nix/add-to-store.cc
@@ -22,11 +22,6 @@ struct CmdAddToStore : MixDryRun, StoreCommand
.dest(&namePart);
}
- std::string name() override
- {
- return "add-to-store";
- }
-
std::string description() override
{
return "add a path to the Nix store";
@@ -58,4 +53,4 @@ struct CmdAddToStore : MixDryRun, StoreCommand
}
};
-static RegisterCommand r1(make_ref<CmdAddToStore>());
+static auto r1 = registerCommand<CmdAddToStore>("add-to-store");
diff --git a/src/nix/build.cc b/src/nix/build.cc
index b329ac38a..d8ce8cc80 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -1,3 +1,4 @@
+#include "eval.hh"
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
@@ -24,11 +25,6 @@ struct CmdBuild : MixDryRun, InstallablesCommand
.set(&outLink, Path(""));
}
- std::string name() override
- {
- return "build";
- }
-
std::string description() override
{
return "build a derivation or fetch a store path";
@@ -52,6 +48,8 @@ struct CmdBuild : MixDryRun, InstallablesCommand
{
auto buildables = build(store, dryRun ? DryRun : Build, installables);
+ auto evalState = std::make_shared<EvalState>(searchPath, store);
+ evalState->addRegistryOverrides(registryOverrides);
if (dryRun) return;
for (size_t i = 0; i < buildables.size(); ++i) {
@@ -69,4 +67,4 @@ struct CmdBuild : MixDryRun, InstallablesCommand
}
};
-static RegisterCommand r1(make_ref<CmdBuild>());
+static auto r1 = registerCommand<CmdBuild>("build");
diff --git a/src/nix/cat.cc b/src/nix/cat.cc
index a35f640d8..851f90abd 100644
--- a/src/nix/cat.cc
+++ b/src/nix/cat.cc
@@ -28,11 +28,6 @@ struct CmdCatStore : StoreCommand, MixCat
expectArg("path", &path);
}
- std::string name() override
- {
- return "cat-store";
- }
-
std::string description() override
{
return "print the contents of a store file on stdout";
@@ -54,11 +49,6 @@ struct CmdCatNar : StoreCommand, MixCat
expectArg("path", &path);
}
- std::string name() override
- {
- return "cat-nar";
- }
-
std::string description() override
{
return "print the contents of a file inside a NAR file";
@@ -70,5 +60,5 @@ struct CmdCatNar : StoreCommand, MixCat
}
};
-static RegisterCommand r1(make_ref<CmdCatStore>());
-static RegisterCommand r2(make_ref<CmdCatNar>());
+static auto r1 = registerCommand<CmdCatStore>("cat-store");
+static auto r2 = registerCommand<CmdCatNar>("cat-nar");
diff --git a/src/nix/command.cc b/src/nix/command.cc
index 3d7d582d6..89fa0cba4 100644
--- a/src/nix/command.cc
+++ b/src/nix/command.cc
@@ -4,79 +4,7 @@
namespace nix {
-Commands * RegisterCommand::commands = 0;
-
-void Command::printHelp(const string & programName, std::ostream & out)
-{
- Args::printHelp(programName, out);
-
- auto exs = examples();
- if (!exs.empty()) {
- out << "\n";
- out << "Examples:\n";
- for (auto & ex : exs)
- out << "\n"
- << " " << ex.description << "\n" // FIXME: wrap
- << " $ " << ex.command << "\n";
- }
-}
-
-MultiCommand::MultiCommand(const Commands & _commands)
- : commands(_commands)
-{
- expectedArgs.push_back(ExpectedArg{"command", 1, true, [=](std::vector<std::string> ss) {
- assert(!command);
- auto i = commands.find(ss[0]);
- if (i == commands.end())
- throw UsageError("'%s' is not a recognised command", ss[0]);
- command = i->second;
- }});
-}
-
-void MultiCommand::printHelp(const string & programName, std::ostream & out)
-{
- if (command) {
- command->printHelp(programName + " " + command->name(), out);
- return;
- }
-
- out << "Usage: " << programName << " <COMMAND> <FLAGS>... <ARGS>...\n";
-
- out << "\n";
- out << "Common flags:\n";
- printFlags(out);
-
- out << "\n";
- out << "Available commands:\n";
-
- Table2 table;
- for (auto & command : commands) {
- auto descr = command.second->description();
- if (!descr.empty())
- table.push_back(std::make_pair(command.second->name(), descr));
- }
- printTable(out, table);
-
-#if 0
- out << "\n";
- out << "For full documentation, run 'man " << programName << "' or 'man " << programName << "-<COMMAND>'.\n";
-#endif
-}
-
-bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
-{
- if (Args::processFlag(pos, end)) return true;
- if (command && command->processFlag(pos, end)) return true;
- return false;
-}
-
-bool MultiCommand::processArgs(const Strings & args, bool finish)
-{
- if (command)
- return command->processArgs(args, finish);
- else
- return Args::processArgs(args, finish);
-}
+Commands * RegisterCommand::commands = nullptr;
StoreCommand::StoreCommand()
{
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 97a6fee7f..59c6f8578 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -2,6 +2,7 @@
#include "args.hh"
#include "common-eval-args.hh"
+#include <optional>
namespace nix {
@@ -10,30 +11,12 @@ extern std::string programPath;
struct Value;
class Bindings;
class EvalState;
-
-/* A command is an argument parser that can be executed by calling its
- run() method. */
-struct Command : virtual Args
-{
- virtual std::string name() = 0;
- virtual void prepare() { };
- virtual void run() = 0;
-
- struct Example
- {
- std::string description;
- std::string command;
- };
-
- typedef std::list<Example> Examples;
-
- virtual Examples examples() { return Examples(); }
-
- void printHelp(const string & programName, std::ostream & out) override;
-};
-
class Store;
+namespace flake {
+enum HandleLockFile : unsigned int;
+}
+
/* A command that require a Nix store. */
struct StoreCommand : virtual Command
{
@@ -55,6 +38,15 @@ struct Buildable
typedef std::vector<Buildable> Buildables;
+struct App
+{
+ PathSet context;
+ Path program;
+ // FIXME: add args, sandbox settings, metadata, ...
+
+ App(EvalState & state, Value & vApp);
+};
+
struct Installable
{
virtual std::string what() = 0;
@@ -66,31 +58,64 @@ struct Installable
Buildable toBuildable();
+ App toApp(EvalState & state);
+
virtual Value * toValue(EvalState & state)
{
throw Error("argument '%s' cannot be evaluated", what());
}
};
-struct SourceExprCommand : virtual Args, StoreCommand, MixEvalArgs
+struct EvalCommand : virtual StoreCommand, MixEvalArgs
{
- Path file;
-
- SourceExprCommand();
-
- /* Return a value representing the Nix expression from which we
- are installing. This is either the file specified by ‘--file’,
- or an attribute set constructed from $NIX_PATH, e.g. ‘{ nixpkgs
- = import ...; bla = import ...; }’. */
- Value * getSourceExpr(EvalState & state);
-
ref<EvalState> getEvalState();
private:
std::shared_ptr<EvalState> evalState;
+};
+
+struct MixFlakeOptions : virtual Args
+{
+ bool recreateLockFile = false;
+
+ bool saveLockFile = true;
+
+ bool useRegistries = true;
+
+ MixFlakeOptions();
- Value * vSourceExpr = 0;
+ flake::HandleLockFile getLockFileMode();
+};
+
+struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
+{
+ std::optional<Path> file;
+
+ SourceExprCommand();
+
+ std::vector<std::shared_ptr<Installable>> parseInstallables(
+ ref<Store> store, std::vector<std::string> ss);
+
+ std::shared_ptr<Installable> parseInstallable(
+ ref<Store> store, const std::string & installable);
+
+ virtual Strings getDefaultFlakeAttrPaths()
+ {
+ return {"defaultPackage"};
+ }
+
+ virtual Strings getDefaultFlakeAttrPathPrefixes()
+ {
+ return {
+ // As a convenience, look for the attribute in
+ // 'outputs.packages'.
+ "packages.",
+ // As a temporary hack until Nixpkgs is properly converted
+ // to provide a clean 'packages' set, look in 'legacyPackages'.
+ "legacyPackages."
+ };
+ }
};
enum RealiseMode { Build, NoBuild, DryRun };
@@ -121,14 +146,14 @@ struct InstallableCommand : virtual Args, SourceExprCommand
InstallableCommand()
{
- expectArg("installable", &_installable);
+ expectArg("installable", &_installable, true);
}
void prepare() override;
private:
- std::string _installable;
+ std::string _installable{"."};
};
/* A command that operates on zero or more store paths. */
@@ -162,41 +187,24 @@ struct StorePathCommand : public InstallablesCommand
void run(ref<Store> store) override;
};
-typedef std::map<std::string, ref<Command>> Commands;
-
-/* An argument parser that supports multiple subcommands,
- i.e. ‘<command> <subcommand>’. */
-class MultiCommand : virtual Args
-{
-public:
- Commands commands;
-
- std::shared_ptr<Command> command;
-
- MultiCommand(const Commands & commands);
-
- void printHelp(const string & programName, std::ostream & out) override;
-
- bool processFlag(Strings::iterator & pos, Strings::iterator end) override;
-
- bool processArgs(const Strings & args, bool finish) override;
-};
-
/* A helper class for registering commands globally. */
struct RegisterCommand
{
static Commands * commands;
- RegisterCommand(ref<Command> command)
+ RegisterCommand(const std::string & name,
+ std::function<ref<Command>()> command)
{
if (!commands) commands = new Commands;
- commands->emplace(command->name(), command);
+ commands->emplace(name, command);
}
};
-std::shared_ptr<Installable> parseInstallable(
- SourceExprCommand & cmd, ref<Store> store, const std::string & installable,
- bool useDefaultInstallables);
+template<class T>
+static RegisterCommand registerCommand(const std::string & name)
+{
+ return RegisterCommand(name, [](){ return make_ref<T>(); });
+}
Buildables build(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables);
diff --git a/src/nix/copy.cc b/src/nix/copy.cc
index 12a9f9cd3..b1aceb15c 100644
--- a/src/nix/copy.cc
+++ b/src/nix/copy.cc
@@ -42,11 +42,6 @@ struct CmdCopy : StorePathsCommand
.set(&substitute, Substitute);
}
- std::string name() override
- {
- return "copy";
- }
-
std::string description() override
{
return "copy paths between Nix stores";
@@ -97,4 +92,4 @@ struct CmdCopy : StorePathsCommand
}
};
-static RegisterCommand r1(make_ref<CmdCopy>());
+static auto r1 = registerCommand<CmdCopy>("copy");
diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc
index 7b5444619..98260127b 100644
--- a/src/nix/doctor.cc
+++ b/src/nix/doctor.cc
@@ -20,11 +20,6 @@ struct CmdDoctor : StoreCommand
{
bool success = true;
- std::string name() override
- {
- return "doctor";
- }
-
std::string description() override
{
return "check your system for potential problems";
@@ -121,4 +116,4 @@ struct CmdDoctor : StoreCommand
}
};
-static RegisterCommand r1(make_ref<CmdDoctor>());
+static auto r1 = registerCommand<CmdDoctor>("doctor");
diff --git a/src/nix/dump-path.cc b/src/nix/dump-path.cc
index f411c0cb7..90f1552d9 100644
--- a/src/nix/dump-path.cc
+++ b/src/nix/dump-path.cc
@@ -5,11 +5,6 @@ using namespace nix;
struct CmdDumpPath : StorePathCommand
{
- std::string name() override
- {
- return "dump-path";
- }
-
std::string description() override
{
return "dump a store path to stdout (in NAR format)";
@@ -33,4 +28,4 @@ struct CmdDumpPath : StorePathCommand
}
};
-static RegisterCommand r1(make_ref<CmdDumpPath>());
+static auto r1 = registerCommand<CmdDumpPath>("dump-path");
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index c9671f76d..c62b35c46 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -10,11 +10,6 @@ using namespace nix;
struct CmdEdit : InstallableCommand
{
- std::string name() override
- {
- return "edit";
- }
-
std::string description() override
{
return "open the Nix expression of a Nix package in $EDITOR";
@@ -78,4 +73,4 @@ struct CmdEdit : InstallableCommand
}
};
-static RegisterCommand r1(make_ref<CmdEdit>());
+static auto r1 = registerCommand<CmdEdit>("edit");
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index b7058361c..524bac304 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -18,11 +18,6 @@ struct CmdEval : MixJSON, InstallableCommand
mkFlag(0, "raw", "print strings unquoted", &raw);
}
- std::string name() override
- {
- return "eval";
- }
-
std::string description() override
{
return "evaluate a Nix expression";
@@ -74,4 +69,4 @@ struct CmdEval : MixJSON, InstallableCommand
}
};
-static RegisterCommand r1(make_ref<CmdEval>());
+static auto r1 = registerCommand<CmdEval>("eval");
diff --git a/src/nix/flake-template.nix b/src/nix/flake-template.nix
new file mode 100644
index 000000000..bec613f6c
--- /dev/null
+++ b/src/nix/flake-template.nix
@@ -0,0 +1,15 @@
+{
+ name = "hello";
+
+ description = "A flake for building Hello World";
+
+ epoch = 201906;
+
+ requires = [ "nixpkgs" ];
+
+ provides = deps: rec {
+
+ packages.hello = deps.nixpkgs.provides.packages.hello;
+
+ };
+}
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
new file mode 100644
index 000000000..49f7c33c7
--- /dev/null
+++ b/src/nix/flake.cc
@@ -0,0 +1,527 @@
+#include "command.hh"
+#include "common-args.hh"
+#include "shared.hh"
+#include "progress-bar.hh"
+#include "eval.hh"
+#include "eval-inline.hh"
+#include "flake/flake.hh"
+#include "get-drvs.hh"
+#include "store-api.hh"
+#include "derivations.hh"
+
+#include <nlohmann/json.hpp>
+#include <queue>
+#include <iomanip>
+
+using namespace nix;
+using namespace nix::flake;
+
+class FlakeCommand : virtual Args, public EvalCommand, public MixFlakeOptions
+{
+ std::string flakeUri = ".";
+
+public:
+
+ FlakeCommand()
+ {
+ expectArg("flake-uri", &flakeUri, true);
+ }
+
+ FlakeRef getFlakeRef()
+ {
+ if (flakeUri.find('/') != std::string::npos || flakeUri == ".")
+ return FlakeRef(flakeUri, true);
+ else
+ return FlakeRef(flakeUri);
+ }
+
+ Flake getFlake()
+ {
+ auto evalState = getEvalState();
+ return flake::getFlake(*evalState,
+ maybeLookupFlake(*evalState, getFlakeRef(), useRegistries));
+ }
+
+ ResolvedFlake resolveFlake()
+ {
+ return flake::resolveFlake(*getEvalState(), getFlakeRef(), getLockFileMode());
+ }
+};
+
+struct CmdFlakeList : EvalCommand
+{
+ std::string description() override
+ {
+ return "list available Nix flakes";
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto registries = getEvalState()->getFlakeRegistries();
+
+ stopProgressBar();
+
+ for (auto & entry : registries[FLAG_REGISTRY]->entries)
+ std::cout << entry.first.to_string() << " flags " << entry.second.to_string() << "\n";
+
+ for (auto & entry : registries[USER_REGISTRY]->entries)
+ std::cout << entry.first.to_string() << " user " << entry.second.to_string() << "\n";
+
+ for (auto & entry : registries[GLOBAL_REGISTRY]->entries)
+ std::cout << entry.first.to_string() << " global " << entry.second.to_string() << "\n";
+ }
+};
+
+static void printSourceInfo(const SourceInfo & sourceInfo)
+{
+ std::cout << fmt("URI: %s\n", sourceInfo.resolvedRef.to_string());
+ if (sourceInfo.resolvedRef.ref)
+ std::cout << fmt("Branch: %s\n",*sourceInfo.resolvedRef.ref);
+ if (sourceInfo.resolvedRef.rev)
+ std::cout << fmt("Revision: %s\n", sourceInfo.resolvedRef.rev->to_string(Base16, false));
+ if (sourceInfo.revCount)
+ std::cout << fmt("Revisions: %s\n", *sourceInfo.revCount);
+ if (sourceInfo.lastModified)
+ std::cout << fmt("Last modified: %s\n",
+ std::put_time(std::localtime(&*sourceInfo.lastModified), "%F %T"));
+ std::cout << fmt("Path: %s\n", sourceInfo.storePath);
+}
+
+static void sourceInfoToJson(const SourceInfo & sourceInfo, nlohmann::json & j)
+{
+ j["uri"] = sourceInfo.resolvedRef.to_string();
+ if (sourceInfo.resolvedRef.ref)
+ j["branch"] = *sourceInfo.resolvedRef.ref;
+ if (sourceInfo.resolvedRef.rev)
+ j["revision"] = sourceInfo.resolvedRef.rev->to_string(Base16, false);
+ if (sourceInfo.revCount)
+ j["revCount"] = *sourceInfo.revCount;
+ if (sourceInfo.lastModified)
+ j["lastModified"] = *sourceInfo.lastModified;
+ j["path"] = sourceInfo.storePath;
+}
+
+static void printFlakeInfo(const Flake & flake)
+{
+ std::cout << fmt("ID: %s\n", flake.id);
+ std::cout << fmt("Description: %s\n", flake.description);
+ std::cout << fmt("Epoch: %s\n", flake.epoch);
+ printSourceInfo(flake.sourceInfo);
+}
+
+static nlohmann::json flakeToJson(const Flake & flake)
+{
+ nlohmann::json j;
+ j["id"] = flake.id;
+ j["description"] = flake.description;
+ j["epoch"] = flake.epoch;
+ sourceInfoToJson(flake.sourceInfo, j);
+ return j;
+}
+
+#if 0
+static void printNonFlakeInfo(const NonFlake & nonFlake)
+{
+ std::cout << fmt("ID: %s\n", nonFlake.alias);
+ printSourceInfo(nonFlake.sourceInfo);
+}
+
+// FIXME: merge info CmdFlakeInfo?
+struct CmdFlakeDeps : FlakeCommand
+{
+ std::string description() override
+ {
+ return "list informaton about dependencies";
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto evalState = getEvalState();
+ evalState->addRegistryOverrides(registryOverrides);
+
+ std::queue<ResolvedFlake> todo;
+ todo.push(resolveFlake());
+
+ stopProgressBar();
+
+ while (!todo.empty()) {
+ auto resFlake = std::move(todo.front());
+ todo.pop();
+
+ for (auto & nonFlake : resFlake.nonFlakeDeps)
+ printNonFlakeInfo(nonFlake);
+
+ for (auto & info : resFlake.flakeDeps) {
+ printFlakeInfo(info.second.flake);
+ todo.push(info.second);
+ }
+ }
+ }
+};
+#endif
+
+struct CmdFlakeUpdate : FlakeCommand
+{
+ std::string description() override
+ {
+ return "update flake lock file";
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto evalState = getEvalState();
+
+ auto flakeRef = getFlakeRef();
+
+ if (std::get_if<FlakeRef::IsPath>(&flakeRef.data))
+ updateLockFile(*evalState, flakeRef, true);
+ else
+ throw Error("cannot update lockfile of flake '%s'", flakeRef);
+ }
+};
+
+static void enumerateOutputs(EvalState & state, Value & vFlake,
+ std::function<void(const std::string & name, Value & vProvide)> callback)
+{
+ state.forceAttrs(vFlake);
+
+ auto vOutputs = (*vFlake.attrs->get(state.symbols.create("outputs")))->value;
+
+ state.forceAttrs(*vOutputs);
+
+ for (auto & attr : *vOutputs->attrs)
+ callback(attr.name, *attr.value);
+}
+
+struct CmdFlakeInfo : FlakeCommand, MixJSON
+{
+ std::string description() override
+ {
+ return "list info about a given flake";
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto flake = getFlake();
+ stopProgressBar();
+
+ if (json) {
+ auto json = flakeToJson(flake);
+
+ auto state = getEvalState();
+ auto flake = resolveFlake();
+
+ auto vFlake = state->allocValue();
+ flake::callFlake(*state, flake, *vFlake);
+
+ auto outputs = nlohmann::json::object();
+
+ enumerateOutputs(*state,
+ *vFlake,
+ [&](const std::string & name, Value & vProvide) {
+ auto provide = nlohmann::json::object();
+
+ if (name == "checks" || name == "packages") {
+ state->forceAttrs(vProvide);
+ for (auto & aCheck : *vProvide.attrs)
+ provide[aCheck.name] = nlohmann::json::object();
+ }
+
+ outputs[name] = provide;
+ });
+
+ json["outputs"] = std::move(outputs);
+
+ std::cout << json.dump() << std::endl;
+ } else
+ printFlakeInfo(flake);
+ }
+};
+
+struct CmdFlakeCheck : FlakeCommand, MixJSON
+{
+ bool build = true;
+
+ CmdFlakeCheck()
+ {
+ mkFlag()
+ .longName("no-build")
+ .description("do not build checks")
+ .set(&build, false);
+ }
+
+ std::string description() override
+ {
+ return "check whether the flake evaluates and run its tests";
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ settings.readOnlyMode = !build;
+
+ auto state = getEvalState();
+ auto flake = resolveFlake();
+
+ auto checkDerivation = [&](const std::string & attrPath, Value & v) {
+ try {
+ auto drvInfo = getDerivation(*state, v, false);
+ if (!drvInfo)
+ throw Error("flake attribute '%s' is not a derivation", attrPath);
+ // FIXME: check meta attributes
+ return drvInfo->queryDrvPath();
+ } catch (Error & e) {
+ e.addPrefix(fmt("while checking the derivation '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
+ throw;
+ }
+ };
+
+ PathSet drvPaths;
+
+ auto checkApp = [&](const std::string & attrPath, Value & v) {
+ try {
+ auto app = App(*state, v);
+ for (auto & i : app.context) {
+ auto [drvPath, outputName] = decodeContext(i);
+ if (!outputName.empty() && nix::isDerivation(drvPath))
+ drvPaths.insert(drvPath + "!" + outputName);
+ }
+ } catch (Error & e) {
+ e.addPrefix(fmt("while checking the app definition '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
+ throw;
+ }
+ };
+
+ {
+ Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
+
+ auto vFlake = state->allocValue();
+ flake::callFlake(*state, flake, *vFlake);
+
+ enumerateOutputs(*state,
+ *vFlake,
+ [&](const std::string & name, Value & vProvide) {
+ Activity act(*logger, lvlChatty, actUnknown,
+ fmt("checking flake output '%s'", name));
+
+ try {
+ state->forceValue(vProvide);
+
+ if (name == "checks") {
+ state->forceAttrs(vProvide);
+ for (auto & aCheck : *vProvide.attrs)
+ drvPaths.insert(checkDerivation(
+ name + "." + (std::string) aCheck.name, *aCheck.value));
+ }
+
+ else if (name == "packages") {
+ state->forceAttrs(vProvide);
+ for (auto & aCheck : *vProvide.attrs)
+ checkDerivation(
+ name + "." + (std::string) aCheck.name, *aCheck.value);
+ }
+
+ else if (name == "apps") {
+ state->forceAttrs(vProvide);
+ for (auto & aCheck : *vProvide.attrs)
+ checkApp(
+ name + "." + (std::string) aCheck.name, *aCheck.value);
+ }
+
+ else if (name == "defaultPackage" || name == "devShell")
+ checkDerivation(name, vProvide);
+
+ else if (name == "defaultApp")
+ checkApp(name, vProvide);
+
+ else if (name == "legacyPackages")
+ // FIXME: do getDerivations?
+ ;
+
+ else
+ warn("unknown flake output '%s'", name);
+
+ } catch (Error & e) {
+ e.addPrefix(fmt("while checking flake output '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", name));
+ throw;
+ }
+ });
+ }
+
+ if (build && !drvPaths.empty()) {
+ Activity act(*logger, lvlInfo, actUnknown, "running flake checks");
+ store->buildPaths(drvPaths);
+ }
+ }
+};
+
+struct CmdFlakeAdd : MixEvalArgs, Command
+{
+ FlakeUri alias;
+ FlakeUri uri;
+
+ std::string description() override
+ {
+ return "upsert flake in user flake registry";
+ }
+
+ CmdFlakeAdd()
+ {
+ expectArg("alias", &alias);
+ expectArg("flake-uri", &uri);
+ }
+
+ void run() override
+ {
+ FlakeRef aliasRef(alias);
+ Path userRegistryPath = getUserRegistryPath();
+ auto userRegistry = readRegistry(userRegistryPath);
+ userRegistry->entries.erase(aliasRef);
+ userRegistry->entries.insert_or_assign(aliasRef, FlakeRef(uri));
+ writeRegistry(*userRegistry, userRegistryPath);
+ }
+};
+
+struct CmdFlakeRemove : virtual Args, MixEvalArgs, Command
+{
+ FlakeUri alias;
+
+ std::string description() override
+ {
+ return "remove flake from user flake registry";
+ }
+
+ CmdFlakeRemove()
+ {
+ expectArg("alias", &alias);
+ }
+
+ void run() override
+ {
+ Path userRegistryPath = getUserRegistryPath();
+ auto userRegistry = readRegistry(userRegistryPath);
+ userRegistry->entries.erase(FlakeRef(alias));
+ writeRegistry(*userRegistry, userRegistryPath);
+ }
+};
+
+struct CmdFlakePin : virtual Args, EvalCommand
+{
+ FlakeUri alias;
+
+ std::string description() override
+ {
+ return "pin flake require in user flake registry";
+ }
+
+ CmdFlakePin()
+ {
+ expectArg("alias", &alias);
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto evalState = getEvalState();
+
+ Path userRegistryPath = getUserRegistryPath();
+ FlakeRegistry userRegistry = *readRegistry(userRegistryPath);
+ auto it = userRegistry.entries.find(FlakeRef(alias));
+ if (it != userRegistry.entries.end()) {
+ it->second = getFlake(*evalState, maybeLookupFlake(*evalState, it->second, true)).sourceInfo.resolvedRef;
+ writeRegistry(userRegistry, userRegistryPath);
+ } else {
+ std::shared_ptr<FlakeRegistry> globalReg = evalState->getGlobalFlakeRegistry();
+ it = globalReg->entries.find(FlakeRef(alias));
+ if (it != globalReg->entries.end()) {
+ auto newRef = getFlake(*evalState, maybeLookupFlake(*evalState, it->second, true)).sourceInfo.resolvedRef;
+ userRegistry.entries.insert_or_assign(alias, newRef);
+ writeRegistry(userRegistry, userRegistryPath);
+ } else
+ throw Error("the flake alias '%s' does not exist in the user or global registry", alias);
+ }
+ }
+};
+
+struct CmdFlakeInit : virtual Args, Command
+{
+ std::string description() override
+ {
+ return "create a skeleton 'flake.nix' file in the current directory";
+ }
+
+ void run() override
+ {
+ Path flakeDir = absPath(".");
+
+ if (!pathExists(flakeDir + "/.git"))
+ throw Error("the directory '%s' is not a Git repository", flakeDir);
+
+ Path flakePath = flakeDir + "/flake.nix";
+
+ if (pathExists(flakePath))
+ throw Error("file '%s' already exists", flakePath);
+
+ writeFile(flakePath,
+#include "flake-template.nix.gen.hh"
+ );
+ }
+};
+
+struct CmdFlakeClone : FlakeCommand
+{
+ Path destDir;
+
+ std::string description() override
+ {
+ return "clone flake repository";
+ }
+
+ CmdFlakeClone()
+ {
+ expectArg("dest-dir", &destDir, true);
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto evalState = getEvalState();
+
+ Registries registries = evalState->getFlakeRegistries();
+ gitCloneFlake(getFlakeRef().to_string(), *evalState, registries, destDir);
+ }
+};
+
+struct CmdFlake : virtual MultiCommand, virtual Command
+{
+ CmdFlake()
+ : MultiCommand({
+ {"list", []() { return make_ref<CmdFlakeList>(); }},
+ {"update", []() { return make_ref<CmdFlakeUpdate>(); }},
+ {"info", []() { return make_ref<CmdFlakeInfo>(); }},
+ {"check", []() { return make_ref<CmdFlakeCheck>(); }},
+ {"add", []() { return make_ref<CmdFlakeAdd>(); }},
+ {"remove", []() { return make_ref<CmdFlakeRemove>(); }},
+ {"pin", []() { return make_ref<CmdFlakePin>(); }},
+ {"init", []() { return make_ref<CmdFlakeInit>(); }},
+ {"clone", []() { return make_ref<CmdFlakeClone>(); }},
+ })
+ {
+ }
+
+ std::string description() override
+ {
+ return "manage Nix flakes";
+ }
+
+ void run() override
+ {
+ if (!command)
+ throw UsageError("'nix flake' requires a sub-command.");
+ command->run();
+ }
+
+ void printHelp(const string & programName, std::ostream & out) override
+ {
+ MultiCommand::printHelp(programName, out);
+ }
+};
+
+static auto r1 = registerCommand<CmdFlake>("flake");
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index af4105e28..1b3ba729e 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -26,11 +26,6 @@ struct CmdHash : Command
expectArgs("paths", &paths);
}
- std::string name() override
- {
- return mode == mFile ? "hash-file" : "hash-path";
- }
-
std::string description() override
{
return mode == mFile
@@ -49,8 +44,8 @@ struct CmdHash : Command
}
};
-static RegisterCommand r1(make_ref<CmdHash>(CmdHash::mFile));
-static RegisterCommand r2(make_ref<CmdHash>(CmdHash::mPath));
+static RegisterCommand r1("hash-file", [](){ return make_ref<CmdHash>(CmdHash::mFile); });
+static RegisterCommand r2("hash-path", [](){ return make_ref<CmdHash>(CmdHash::mPath); });
struct CmdToBase : Command
{
@@ -66,15 +61,6 @@ struct CmdToBase : Command
expectArgs("strings", &args);
}
- std::string name() override
- {
- return
- base == Base16 ? "to-base16" :
- base == Base32 ? "to-base32" :
- base == Base64 ? "to-base64" :
- "to-sri";
- }
-
std::string description() override
{
return fmt("convert a hash to %s representation",
@@ -91,10 +77,10 @@ struct CmdToBase : Command
}
};
-static RegisterCommand r3(make_ref<CmdToBase>(Base16));
-static RegisterCommand r4(make_ref<CmdToBase>(Base32));
-static RegisterCommand r5(make_ref<CmdToBase>(Base64));
-static RegisterCommand r6(make_ref<CmdToBase>(SRI));
+static RegisterCommand r3("to-base16", [](){ return make_ref<CmdToBase>(Base16); });
+static RegisterCommand r4("to-base32", [](){ return make_ref<CmdToBase>(Base32); });
+static RegisterCommand r5("to-base64", [](){ return make_ref<CmdToBase>(Base64); });
+static RegisterCommand r6("to-sri", [](){ return make_ref<CmdToBase>(SRI); });
/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 0c1ad3ab3..d43f86c0c 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -7,71 +7,54 @@
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"
+#include "flake/flake.hh"
+#include "flake/eval-cache.hh"
#include <regex>
+#include <queue>
namespace nix {
+MixFlakeOptions::MixFlakeOptions()
+{
+ mkFlag()
+ .longName("recreate-lock-file")
+ .description("recreate lock file from scratch")
+ .set(&recreateLockFile, true);
+
+ mkFlag()
+ .longName("no-save-lock-file")
+ .description("do not save the newly generated lock file")
+ .set(&saveLockFile, false);
+
+ mkFlag()
+ .longName("no-registries")
+ .description("don't use flake registries")
+ .set(&useRegistries, false);
+}
+
+flake::HandleLockFile MixFlakeOptions::getLockFileMode()
+{
+ using namespace flake;
+ return
+ useRegistries
+ ? recreateLockFile
+ ? (saveLockFile ? RecreateLockFile : UseNewLockFile)
+ : (saveLockFile ? UpdateLockFile : UseUpdatedLockFile)
+ : AllPure;
+}
+
SourceExprCommand::SourceExprCommand()
{
mkFlag()
.shortName('f')
.longName("file")
.label("file")
- .description("evaluate FILE rather than the default")
+ .description("evaluate a set of attributes from FILE (deprecated)")
.dest(&file);
}
-Value * SourceExprCommand::getSourceExpr(EvalState & state)
-{
- if (vSourceExpr) return vSourceExpr;
-
- auto sToplevel = state.symbols.create("_toplevel");
-
- vSourceExpr = state.allocValue();
-
- if (file != "")
- state.evalFile(lookupFileArg(state, file), *vSourceExpr);
-
- else {
-
- /* Construct the installation source from $NIX_PATH. */
-
- auto searchPath = state.getSearchPath();
-
- state.mkAttrs(*vSourceExpr, searchPath.size() + 1);
-
- mkBool(*state.allocAttr(*vSourceExpr, sToplevel), true);
-
- std::unordered_set<std::string> seen;
-
- for (auto & i : searchPath) {
- if (i.first == "") continue;
- if (seen.count(i.first)) continue;
- seen.insert(i.first);
-#if 0
- auto res = state.resolveSearchPathElem(i);
- if (!res.first) continue;
- if (!pathExists(res.second)) continue;
- mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
- state.getBuiltin("import"),
- mkString(*state.allocValue(), res.second));
-#endif
- Value * v1 = state.allocValue();
- mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
- Value * v2 = state.allocValue();
- mkApp(*v2, *v1, mkString(*state.allocValue(), i.first));
- mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
- state.getBuiltin("import"), *v2);
- }
-
- vSourceExpr->attrs->sort();
- }
-
- return vSourceExpr;
-}
-
-ref<EvalState> SourceExprCommand::getEvalState()
+ref<EvalState> EvalCommand::getEvalState()
{
if (!evalState)
evalState = std::make_shared<EvalState>(searchPath, getStore());
@@ -86,6 +69,27 @@ Buildable Installable::toBuildable()
return std::move(buildables[0]);
}
+App::App(EvalState & state, Value & vApp)
+{
+ state.forceAttrs(vApp);
+
+ auto aType = vApp.attrs->need(state.sType);
+ if (state.forceStringNoCtx(*aType.value, *aType.pos) != "app")
+ throw Error("value does not have type 'app', at %s", *aType.pos);
+
+ auto aProgram = vApp.attrs->need(state.symbols.create("program"));
+ program = state.forceString(*aProgram.value, context, *aProgram.pos);
+
+ // FIXME: check that 'program' is in the closure of 'context'.
+ if (!state.store->isInStore(program))
+ throw Error("app program '%s' is not in the Nix store", program);
+}
+
+App Installable::toApp(EvalState & state)
+{
+ return App(state, *toValue(state));
+}
+
struct InstallableStorePath : Installable
{
Path storePath;
@@ -106,7 +110,7 @@ struct InstallableValue : Installable
InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }
- Buildables toBuildables() override
+ virtual std::vector<flake::EvalCache::Derivation> toDerivations()
{
auto state = cmd.getEvalState();
@@ -114,22 +118,36 @@ struct InstallableValue : Installable
Bindings & autoArgs = *cmd.getAutoArgs(*state);
- DrvInfos drvs;
- getDerivations(*state, *v, "", autoArgs, drvs, false);
+ DrvInfos drvInfos;
+ getDerivations(*state, *v, "", autoArgs, drvInfos, false);
+
+ std::vector<flake::EvalCache::Derivation> res;
+ for (auto & drvInfo : drvInfos) {
+ res.push_back({
+ drvInfo.queryDrvPath(),
+ drvInfo.queryOutPath(),
+ drvInfo.queryOutputName()
+ });
+ }
+
+ return res;
+ }
+ Buildables toBuildables() override
+ {
Buildables res;
PathSet drvPaths;
- for (auto & drv : drvs) {
- Buildable b{drv.queryDrvPath()};
+ for (auto & drv : toDerivations()) {
+ Buildable b{drv.drvPath};
drvPaths.insert(b.drvPath);
- auto outputName = drv.queryOutputName();
+ auto outputName = drv.outputName;
if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);
- b.outputs.emplace(outputName, drv.queryOutPath());
+ b.outputs.emplace(outputName, drv.outPath);
res.push_back(std::move(b));
}
@@ -165,24 +183,189 @@ struct InstallableExpr : InstallableValue
struct InstallableAttrPath : InstallableValue
{
+ Value * v;
std::string attrPath;
- InstallableAttrPath(SourceExprCommand & cmd, const std::string & attrPath)
- : InstallableValue(cmd), attrPath(attrPath)
+ InstallableAttrPath(SourceExprCommand & cmd, Value * v, const std::string & attrPath)
+ : InstallableValue(cmd), v(v), attrPath(attrPath)
{ }
std::string what() override { return attrPath; }
Value * toValue(EvalState & state) override
{
- auto source = cmd.getSourceExpr(state);
+ auto vRes = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), *v);
+ state.forceValue(*vRes);
+ return vRes;
+ }
+};
- Bindings & autoArgs = *cmd.getAutoArgs(state);
+void makeFlakeClosureGCRoot(Store & store,
+ const FlakeRef & origFlakeRef,
+ const flake::ResolvedFlake & resFlake)
+{
+ if (std::get_if<FlakeRef::IsPath>(&origFlakeRef.data)) return;
+
+ /* Get the store paths of all non-local flakes. */
+ PathSet closure;
+
+ assert(store.isValidPath(resFlake.flake.sourceInfo.storePath));
+ closure.insert(resFlake.flake.sourceInfo.storePath);
+
+ std::queue<std::reference_wrapper<const flake::FlakeInputs>> queue;
+ queue.push(resFlake.lockFile);
+
+ while (!queue.empty()) {
+ const flake::FlakeInputs & flake = queue.front();
+ queue.pop();
+ /* Note: due to lazy fetching, these paths might not exist
+ yet. */
+ for (auto & dep : flake.flakeInputs) {
+ auto path = dep.second.computeStorePath(store);
+ if (store.isValidPath(path))
+ closure.insert(path);
+ queue.push(dep.second);
+ }
+ for (auto & dep : flake.nonFlakeInputs) {
+ auto path = dep.second.computeStorePath(store);
+ if (store.isValidPath(path))
+ closure.insert(path);
+ }
+ }
- Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
- state.forceValue(*v);
+ if (closure.empty()) return;
- return v;
+ /* Write the closure to a file in the store. */
+ auto closurePath = store.addTextToStore("flake-closure", concatStringsSep(" ", closure), closure);
+
+ Path cacheDir = getCacheDir() + "/nix/flake-closures";
+ createDirs(cacheDir);
+
+ auto s = origFlakeRef.to_string();
+ assert(s[0] != '.');
+ s = replaceStrings(s, "%", "%25");
+ s = replaceStrings(s, "/", "%2f");
+ s = replaceStrings(s, ":", "%3a");
+ Path symlink = cacheDir + "/" + s;
+ debug("writing GC root '%s' for flake closure of '%s'", symlink, origFlakeRef);
+ replaceSymlink(closurePath, symlink);
+ store.addIndirectRoot(symlink);
+}
+
+struct InstallableFlake : InstallableValue
+{
+ FlakeRef flakeRef;
+ Strings attrPaths;
+ Strings prefixes;
+
+ InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, Strings attrPaths)
+ : InstallableValue(cmd), flakeRef(flakeRef), attrPaths(std::move(attrPaths))
+ { }
+
+ InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef,
+ std::string attrPath, Strings && prefixes)
+ : InstallableValue(cmd), flakeRef(flakeRef), attrPaths{attrPath},
+ prefixes(prefixes)
+ { }
+
+ std::string what() override { return flakeRef.to_string() + ":" + *attrPaths.begin(); }
+
+ std::vector<std::string> getActualAttrPaths()
+ {
+ std::vector<std::string> res;
+
+ for (auto & prefix : prefixes)
+ res.push_back(prefix + *attrPaths.begin());
+
+ for (auto & s : attrPaths)
+ res.push_back(s);
+
+ return res;
+ }
+
+ Value * getFlakeOutputs(EvalState & state, const flake::ResolvedFlake & resFlake)
+ {
+ auto vFlake = state.allocValue();
+
+ callFlake(state, resFlake, *vFlake);
+
+ makeFlakeClosureGCRoot(*state.store, flakeRef, resFlake);
+
+ auto vOutputs = (*vFlake->attrs->get(state.symbols.create("outputs")))->value;
+
+ state.forceValue(*vOutputs);
+
+ return vOutputs;
+ }
+
+ std::vector<flake::EvalCache::Derivation> toDerivations() override
+ {
+ auto state = cmd.getEvalState();
+
+ auto resFlake = resolveFlake(*state, flakeRef, cmd.getLockFileMode());
+
+ Value * vOutputs = nullptr;
+
+ auto emptyArgs = state->allocBindings(0);
+
+ auto & evalCache = flake::EvalCache::singleton();
+
+ auto fingerprint = resFlake.getFingerprint();
+
+ for (auto & attrPath : getActualAttrPaths()) {
+ auto drv = evalCache.getDerivation(fingerprint, attrPath);
+ if (drv) {
+ if (state->store->isValidPath(drv->drvPath))
+ return {*drv};
+ }
+
+ if (!vOutputs)
+ vOutputs = getFlakeOutputs(*state, resFlake);
+
+ try {
+ auto * v = findAlongAttrPath(*state, attrPath, *emptyArgs, *vOutputs);
+ state->forceValue(*v);
+
+ auto drvInfo = getDerivation(*state, *v, false);
+ if (!drvInfo)
+ throw Error("flake output attribute '%s' is not a derivation", attrPath);
+
+ auto drv = flake::EvalCache::Derivation{
+ drvInfo->queryDrvPath(),
+ drvInfo->queryOutPath(),
+ drvInfo->queryOutputName()
+ };
+
+ evalCache.addDerivation(fingerprint, attrPath, drv);
+
+ return {drv};
+ } catch (AttrPathNotFound & e) {
+ }
+ }
+
+ throw Error("flake '%s' does not provide attribute %s",
+ flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
+ }
+
+ Value * toValue(EvalState & state) override
+ {
+ auto resFlake = resolveFlake(state, flakeRef, cmd.getLockFileMode());
+
+ auto vOutputs = getFlakeOutputs(state, resFlake);
+
+ auto emptyArgs = state.allocBindings(0);
+
+ for (auto & attrPath : getActualAttrPaths()) {
+ try {
+ auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
+ state.forceValue(*v);
+ return v;
+ } catch (AttrPathNotFound & e) {
+ }
+ }
+
+ throw Error("flake '%s' does not provide attribute %s",
+ flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
}
};
@@ -190,45 +373,79 @@ struct InstallableAttrPath : InstallableValue
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));
-static std::vector<std::shared_ptr<Installable>> parseInstallables(
- SourceExprCommand & cmd, ref<Store> store, std::vector<std::string> ss, bool useDefaultInstallables)
+std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
+ ref<Store> store, std::vector<std::string> ss)
{
std::vector<std::shared_ptr<Installable>> result;
- if (ss.empty() && useDefaultInstallables) {
- if (cmd.file == "")
- cmd.file = ".";
- ss = {""};
- }
+ if (file) {
+ // FIXME: backward compatibility hack
+ evalSettings.pureEval = false;
- for (auto & s : ss) {
+ auto state = getEvalState();
+ auto vFile = state->allocValue();
+ state->evalFile(lookupFileArg(*state, *file), *vFile);
- if (s.compare(0, 1, "(") == 0)
- result.push_back(std::make_shared<InstallableExpr>(cmd, s));
+ if (ss.empty())
+ ss = {""};
- else if (s.find("/") != std::string::npos) {
+ for (auto & s : ss)
+ result.push_back(std::make_shared<InstallableAttrPath>(*this, vFile, s));
- auto path = store->toStorePath(store->followLinksToStore(s));
+ } else {
- if (store->isStorePath(path))
- result.push_back(std::make_shared<InstallableStorePath>(path));
- }
+ auto follow = [&](const std::string & s) -> std::optional<Path> {
+ try {
+ return store->followLinksToStorePath(s);
+ } catch (NotInStore &) {
+ return {};
+ }
+ };
+
+ for (auto & s : ss) {
- else if (s == "" || std::regex_match(s, attrPathRegex))
- result.push_back(std::make_shared<InstallableAttrPath>(cmd, s));
+ size_t colon;
+ std::optional<Path> storePath;
- else
- throw UsageError("don't know what to do with argument '%s'", s);
+ if (s.compare(0, 1, "(") == 0)
+ result.push_back(std::make_shared<InstallableExpr>(*this, s));
+
+ else if (hasPrefix(s, "nixpkgs.")) {
+ bool static warned;
+ warnOnce(warned, "the syntax 'nixpkgs.<attr>' is deprecated; use 'nixpkgs:<attr>' instead");
+ result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"),
+ Strings{"legacyPackages." + std::string(s, 8)}));
+ }
+
+ else if (auto flakeRef = parseFlakeRef(s, true))
+ result.push_back(std::make_shared<InstallableFlake>(*this, std::move(*flakeRef),
+ getDefaultFlakeAttrPaths()));
+
+ else if ((colon = s.rfind(':')) != std::string::npos) {
+ auto flakeRef = std::string(s, 0, colon);
+ auto attrPath = std::string(s, colon + 1);
+ result.push_back(std::make_shared<InstallableFlake>(
+ *this,
+ FlakeRef(flakeRef, true),
+ attrPath,
+ getDefaultFlakeAttrPathPrefixes()));
+ }
+
+ else if (s.find('/') != std::string::npos && (storePath = follow(s)))
+ result.push_back(std::make_shared<InstallableStorePath>(*storePath));
+
+ else
+ throw Error("unsupported argument '%s'", s);
+ }
}
return result;
}
-std::shared_ptr<Installable> parseInstallable(
- SourceExprCommand & cmd, ref<Store> store, const std::string & installable,
- bool useDefaultInstallables)
+std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
+ ref<Store> store, const std::string & installable)
{
- auto installables = parseInstallables(cmd, store, {installable}, false);
+ auto installables = parseInstallables(store, {installable});
assert(installables.size() == 1);
return installables.front();
}
@@ -284,7 +501,7 @@ Path toStorePath(ref<Store> store, RealiseMode mode,
auto paths = toStorePaths(store, mode, {installable});
if (paths.size() != 1)
- throw Error("argument '%s' should evaluate to one store path", installable->what());
+ throw Error("argument '%s' should evaluate to one store path", installable->what());
return *paths.begin();
}
@@ -315,12 +532,16 @@ PathSet toDerivations(ref<Store> store,
void InstallablesCommand::prepare()
{
- installables = parseInstallables(*this, getStore(), _installables, useDefaultInstallables());
+ if (_installables.empty() && !file && useDefaultInstallables())
+ // FIXME: commands like "nix install" should not have a
+ // default, probably.
+ _installables.push_back(".");
+ installables = parseInstallables(getStore(), _installables);
}
void InstallableCommand::prepare()
{
- installable = parseInstallable(*this, getStore(), _installable, false);
+ installable = parseInstallable(getStore(), _installable);
}
}
diff --git a/src/nix/local.mk b/src/nix/local.mk
index c09efd1fc..44a95f910 100644
--- a/src/nix/local.mk
+++ b/src/nix/local.mk
@@ -23,3 +23,5 @@ $(foreach name, \
nix-build nix-channel nix-collect-garbage nix-copy-closure nix-daemon nix-env nix-hash nix-instantiate nix-prefetch-url nix-shell nix-store, \
$(eval $(call install-symlink, nix, $(bindir)/$(name))))
$(eval $(call install-symlink, $(bindir)/nix, $(libexecdir)/nix/build-remote))
+
+$(d)/flake.cc: $(d)/flake-template.nix.gen.hh
diff --git a/src/nix/log.cc b/src/nix/log.cc
index f07ec4e93..122a3d690 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -8,15 +8,6 @@ using namespace nix;
struct CmdLog : InstallableCommand
{
- CmdLog()
- {
- }
-
- std::string name() override
- {
- return "log";
- }
-
std::string description() override
{
return "show the build log of the specified packages or paths, if available";
@@ -68,4 +59,4 @@ struct CmdLog : InstallableCommand
}
};
-static RegisterCommand r1(make_ref<CmdLog>());
+static auto r1 = registerCommand<CmdLog>("log");
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index d089be42f..9408cc9da 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -100,11 +100,6 @@ struct CmdLsStore : StoreCommand, MixLs
};
}
- std::string name() override
- {
- return "ls-store";
- }
-
std::string description() override
{
return "show information about a store path";
@@ -136,11 +131,6 @@ struct CmdLsNar : Command, MixLs
};
}
- std::string name() override
- {
- return "ls-nar";
- }
-
std::string description() override
{
return "show information about the contents of a NAR file";
@@ -152,5 +142,5 @@ struct CmdLsNar : Command, MixLs
}
};
-static RegisterCommand r1(make_ref<CmdLsStore>());
-static RegisterCommand r2(make_ref<CmdLsNar>());
+static auto r1 = registerCommand<CmdLsStore>("ls-store");
+static auto r2 = registerCommand<CmdLsNar>("ls-nar");
diff --git a/src/nix/main.cc b/src/nix/main.cc
index a80fd0ea6..eedf8656e 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -103,10 +103,20 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
"--help-config' for a list of configuration settings.\n";
}
+ void printHelp(const string & programName, std::ostream & out) override
+ {
+ MultiCommand::printHelp(programName, out);
+
+#if 0
+ out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-<COMMAND>'.\n";
+#endif
+
+ std::cout << "\nNote: this program is EXPERIMENTAL and subject to change.\n";
+ }
+
void showHelpAndExit()
{
printHelp(programName, std::cout);
- std::cout << "\nNote: this program is EXPERIMENTAL and subject to change.\n";
throw Exit();
}
};
@@ -133,6 +143,7 @@ void mainWrapped(int argc, char * * argv)
verbosity = lvlWarn;
settings.verboseBuild = false;
+ evalSettings.pureEval = true;
NixArgs args;
diff --git a/src/nix/optimise-store.cc b/src/nix/optimise-store.cc
index 725fb75a1..fed012b04 100644
--- a/src/nix/optimise-store.cc
+++ b/src/nix/optimise-store.cc
@@ -8,15 +8,6 @@ using namespace nix;
struct CmdOptimiseStore : StoreCommand
{
- CmdOptimiseStore()
- {
- }
-
- std::string name() override
- {
- return "optimise-store";
- }
-
std::string description() override
{
return "replace identical files in the store by hard links";
@@ -38,4 +29,4 @@ struct CmdOptimiseStore : StoreCommand
}
};
-static RegisterCommand r1(make_ref<CmdOptimiseStore>());
+static auto r1 = registerCommand<CmdOptimiseStore>("optimise-store");
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index dea5f0557..2cb718f12 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -24,11 +24,6 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
mkFlag(0, "sigs", "show signatures", &showSigs);
}
- std::string name() override
- {
- return "path-info";
- }
-
std::string description() override
{
return "query information about store paths";
@@ -130,4 +125,4 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
}
};
-static RegisterCommand r1(make_ref<CmdPathInfo>());
+static auto r1 = registerCommand<CmdPathInfo>("path-info");
diff --git a/src/nix/ping-store.cc b/src/nix/ping-store.cc
index 310942574..3a2e542a3 100644
--- a/src/nix/ping-store.cc
+++ b/src/nix/ping-store.cc
@@ -6,11 +6,6 @@ using namespace nix;
struct CmdPingStore : StoreCommand
{
- std::string name() override
- {
- return "ping-store";
- }
-
std::string description() override
{
return "test whether a store can be opened";
@@ -32,4 +27,4 @@ struct CmdPingStore : StoreCommand
}
};
-static RegisterCommand r1(make_ref<CmdPingStore>());
+static auto r1 = registerCommand<CmdPingStore>("ping-store");
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index f857b2e89..3a70a23c7 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -771,8 +771,6 @@ struct CmdRepl : StoreCommand, MixEvalArgs
expectArgs("files", &files);
}
- std::string name() override { return "repl"; }
-
std::string description() override
{
return "start an interactive environment for evaluating Nix expressions";
@@ -786,6 +784,6 @@ struct CmdRepl : StoreCommand, MixEvalArgs
}
};
-static RegisterCommand r1(make_ref<CmdRepl>());
+static auto r1 = registerCommand<CmdRepl>("repl");
}
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 35b763345..9c15b6749 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -8,6 +8,7 @@
#include "fs-accessor.hh"
#include "progress-bar.hh"
#include "affinity.hh"
+#include "eval.hh"
#if __linux__
#include <sys/mount.h>
@@ -19,7 +20,44 @@ using namespace nix;
std::string chrootHelperName = "__run_in_chroot";
-struct CmdRun : InstallablesCommand
+struct RunCommon : virtual Command
+{
+ void runProgram(ref<Store> store,
+ const std::string & program,
+ const Strings & args)
+ {
+ stopProgressBar();
+
+ restoreSignals();
+
+ restoreAffinity();
+
+ /* If this is a diverted store (i.e. its "logical" location
+ (typically /nix/store) differs from its "physical" location
+ (e.g. /home/eelco/nix/store), then run the command in a
+ chroot. For non-root users, this requires running it in new
+ mount and user namespaces. Unfortunately,
+ unshare(CLONE_NEWUSER) doesn't work in a multithreaded
+ program (which "nix" is), so we exec() a single-threaded
+ helper program (chrootHelper() below) to do the work. */
+ auto store2 = store.dynamic_pointer_cast<LocalStore>();
+
+ if (store2 && store->storeDir != store2->realStoreDir) {
+ Strings helperArgs = { chrootHelperName, store->storeDir, store2->realStoreDir, program };
+ for (auto & arg : args) helperArgs.push_back(arg);
+
+ execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
+
+ throw SysError("could not execute chroot helper");
+ }
+
+ execvp(program.c_str(), stringsToCharPtrs(args).data());
+
+ throw SysError("unable to execute '%s'", program);
+ }
+};
+
+struct CmdRun : InstallablesCommand, RunCommon
{
std::vector<std::string> command = { "bash" };
StringSet keep, unset;
@@ -61,11 +99,6 @@ struct CmdRun : InstallablesCommand
.handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); });
}
- std::string name() override
- {
- return "run";
- }
-
std::string description() override
{
return "run a shell in which the specified packages are available";
@@ -147,42 +180,65 @@ struct CmdRun : InstallablesCommand
setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
- std::string cmd = *command.begin();
Strings args;
for (auto & arg : command) args.push_back(arg);
- stopProgressBar();
+ runProgram(store, *command.begin(), args);
+ }
+};
- restoreSignals();
+static auto r1 = registerCommand<CmdRun>("run");
- restoreAffinity();
+struct CmdApp : InstallableCommand, RunCommon
+{
+ std::vector<std::string> args;
- /* If this is a diverted store (i.e. its "logical" location
- (typically /nix/store) differs from its "physical" location
- (e.g. /home/eelco/nix/store), then run the command in a
- chroot. For non-root users, this requires running it in new
- mount and user namespaces. Unfortunately,
- unshare(CLONE_NEWUSER) doesn't work in a multithreaded
- program (which "nix" is), so we exec() a single-threaded
- helper program (chrootHelper() below) to do the work. */
- auto store2 = store.dynamic_pointer_cast<LocalStore>();
+ CmdApp()
+ {
+ expectArgs("args", &args);
+ }
- if (store2 && store->storeDir != store2->realStoreDir) {
- Strings helperArgs = { chrootHelperName, store->storeDir, store2->realStoreDir, cmd };
- for (auto & arg : args) helperArgs.push_back(arg);
+ std::string description() override
+ {
+ return "run a Nix application";
+ }
- execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
+ Examples examples() override
+ {
+ return {
+ Example{
+ "To run Blender:",
+ "nix app blender-bin"
+ },
+ };
+ }
- throw SysError("could not execute chroot helper");
- }
+ Strings getDefaultFlakeAttrPaths() override
+ {
+ return {"defaultApp"};
+ }
+
+ Strings getDefaultFlakeAttrPathPrefixes() override
+ {
+ return {"apps."};
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto state = getEvalState();
+
+ auto app = installable->toApp(*state);
+
+ state->realiseContext(app.context);
- execvp(cmd.c_str(), stringsToCharPtrs(args).data());
+ Strings allArgs{app.program};
+ for (auto & i : args) allArgs.push_back(i);
- throw SysError("unable to exec '%s'", cmd);
+ runProgram(store, app.program, allArgs);
}
};
-static RegisterCommand r1(make_ref<CmdRun>());
+static auto r2 = registerCommand<CmdApp>("app");
void chrootHelper(int argc, char * * argv)
{
diff --git a/src/nix/search.cc b/src/nix/search.cc
index e086de226..70de717d1 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -52,11 +52,6 @@ struct CmdSearch : SourceExprCommand, MixJSON
.handler([&]() { writeCache = false; useCache = false; });
}
- std::string name() override
- {
- return "search";
- }
-
std::string description() override
{
return "query available packages";
@@ -257,7 +252,9 @@ struct CmdSearch : SourceExprCommand, MixJSON
auto cache = writeCache ? std::make_unique<JSONObject>(jsonCacheFile, false) : nullptr;
- doExpr(getSourceExpr(*state), "", true, cache.get());
+ // FIXME
+ throw Error("NOT IMPLEMENTED");
+ //doExpr(getSourceExpr(*state), "", true, cache.get());
} catch (std::exception &) {
/* Fun fact: catching std::ios::failure does not work
@@ -280,4 +277,4 @@ struct CmdSearch : SourceExprCommand, MixJSON
}
};
-static RegisterCommand r1(make_ref<CmdSearch>());
+static auto r1 = registerCommand<CmdSearch>("search");
diff --git a/src/nix/shell.cc b/src/nix/shell.cc
new file mode 100644
index 000000000..f42947b7c
--- /dev/null
+++ b/src/nix/shell.cc
@@ -0,0 +1,271 @@
+#include "eval.hh"
+#include "command.hh"
+#include "common-args.hh"
+#include "shared.hh"
+#include "store-api.hh"
+#include "derivations.hh"
+#include "affinity.hh"
+#include "progress-bar.hh"
+
+using namespace nix;
+
+struct BuildEnvironment
+{
+ // FIXME: figure out which vars should be exported.
+ std::map<std::string, std::string> env;
+ std::map<std::string, std::string> functions;
+};
+
+BuildEnvironment readEnvironment(const Path & path)
+{
+ BuildEnvironment res;
+
+ auto lines = tokenizeString<Strings>(readFile(path), "\n");
+
+ auto getLine =
+ [&]() {
+ if (lines.empty())
+ throw Error("shell environment '%s' ends unexpectedly", path);
+ auto line = lines.front();
+ lines.pop_front();
+ return line;
+ };
+
+ while (!lines.empty()) {
+ auto line = getLine();
+
+ auto eq = line.find('=');
+ if (eq != std::string::npos) {
+ std::string name(line, 0, eq);
+ std::string value(line, eq + 1);
+ // FIXME: parse arrays
+ res.env.insert({name, value});
+ }
+
+ else if (hasSuffix(line, " () ")) {
+ std::string name(line, 0, line.size() - 4);
+ // FIXME: validate name
+ auto l = getLine();
+ if (l != "{ ") throw Error("shell environment '%s' has unexpected line '%s'", path, l);
+ std::string body;
+ while ((l = getLine()) != "}") {
+ body += l;
+ body += '\n';
+ }
+ res.functions.insert({name, body});
+ }
+
+ else throw Error("shell environment '%s' has unexpected line '%s'", path, line);
+ }
+
+ return res;
+}
+
+/* Given an existing derivation, return the shell environment as
+ initialised by stdenv's setup script. We do this by building a
+ modified derivation with the same dependencies and nearly the same
+ initial environment variables, that just writes the resulting
+ environment to a file and exits. */
+BuildEnvironment getDerivationEnvironment(ref<Store> store, Derivation drv)
+{
+ auto builder = baseNameOf(drv.builder);
+ if (builder != "bash")
+ throw Error("'nix shell' only works on derivations that use 'bash' as their builder");
+
+ drv.args = {"-c", "set -e; if [[ -n $stdenv ]]; then source $stdenv/setup; fi; set > $out"};
+
+ /* Remove derivation checks. */
+ drv.env.erase("allowedReferences");
+ drv.env.erase("allowedRequisites");
+ drv.env.erase("disallowedReferences");
+ drv.env.erase("disallowedRequisites");
+
+ // FIXME: handle structured attrs
+
+ /* Rehash and write the derivation. FIXME: would be nice to use
+ 'buildDerivation', but that's privileged. */
+ auto drvName = drv.env["name"] + "-env";
+ for (auto & output : drv.outputs)
+ drv.env.erase(output.first);
+ drv.env["out"] = "";
+ drv.env["outputs"] = "out";
+ drv.outputs["out"] = DerivationOutput("", "", "");
+ Hash h = hashDerivationModulo(*store, drv);
+ Path shellOutPath = store->makeOutputPath("out", h, drvName);
+ drv.outputs["out"].path = shellOutPath;
+ drv.env["out"] = shellOutPath;
+ Path shellDrvPath2 = writeDerivation(store, drv, drvName);
+
+ /* Build the derivation. */
+ store->buildPaths({shellDrvPath2});
+
+ assert(store->isValidPath(shellOutPath));
+
+ return readEnvironment(shellOutPath);
+}
+
+struct Common : InstallableCommand
+{
+ /*
+ std::set<string> keepVars{
+ "DISPLAY",
+ "HOME",
+ "IN_NIX_SHELL",
+ "LOGNAME",
+ "NIX_BUILD_SHELL",
+ "PAGER",
+ "PATH",
+ "TERM",
+ "TZ",
+ "USER",
+ };
+ */
+
+ std::set<string> ignoreVars{
+ "BASHOPTS",
+ "EUID",
+ "HOME", // FIXME: don't ignore in pure mode?
+ "NIX_BUILD_TOP",
+ "NIX_ENFORCE_PURITY",
+ "PPID",
+ "PWD",
+ "SHELLOPTS",
+ "SHLVL",
+ "SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt
+ "TEMP",
+ "TEMPDIR",
+ "TERM",
+ "TMP",
+ "TMPDIR",
+ "TZ",
+ "UID",
+ };
+
+ void makeRcScript(const BuildEnvironment & buildEnvironment, std::ostream & out)
+ {
+ out << "export IN_NIX_SHELL=1\n";
+ out << "nix_saved_PATH=\"$PATH\"\n";
+
+ for (auto & i : buildEnvironment.env) {
+ // FIXME: shellEscape
+ // FIXME: figure out what to export
+ // FIXME: handle arrays
+ if (!ignoreVars.count(i.first) && !hasPrefix(i.first, "BASH_"))
+ out << fmt("export %s=%s\n", i.first, i.second);
+ }
+
+ out << "PATH=\"$PATH:$nix_saved_PATH\"\n";
+
+ for (auto & i : buildEnvironment.functions) {
+ out << fmt("%s () {\n%s\n}\n", i.first, i.second);
+ }
+
+ // FIXME: set outputs
+
+ out << "export NIX_BUILD_TOP=\"$(mktemp -d --tmpdir nix-shell.XXXXXX)\"\n";
+ for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"})
+ out << fmt("export %s=\"$NIX_BUILD_TOP\"\n", i);
+
+ out << "eval \"$shellHook\"\n";
+ }
+
+ Strings getDefaultFlakeAttrPaths() override
+ {
+ return {"devShell", "defaultPackage"};
+ }
+};
+
+struct CmdDevShell : Common
+{
+ std::string description() override
+ {
+ return "run a bash shell that provides the build environment of a derivation";
+ }
+
+ Examples examples() override
+ {
+ return {
+ Example{
+ "To get the build environment of GNU hello:",
+ "nix dev-shell nixpkgs:hello"
+ },
+ Example{
+ "To get the build environment of the default package of flake in the current directory:",
+ "nix dev-shell"
+ },
+ };
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto drvs = toDerivations(store, {installable});
+
+ if (drvs.size() != 1)
+ throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations",
+ installable->what(), drvs.size());
+
+ auto & drvPath = *drvs.begin();
+
+ auto buildEnvironment = getDerivationEnvironment(store, store->derivationFromPath(drvPath));
+
+ auto [rcFileFd, rcFilePath] = createTempFile("nix-shell");
+
+ std::ostringstream ss;
+ makeRcScript(buildEnvironment, ss);
+
+ ss << fmt("rm -f '%s'\n", rcFilePath);
+
+ writeFull(rcFileFd.get(), ss.str());
+
+ stopProgressBar();
+
+ auto shell = getEnv("SHELL", "bash");
+
+ auto args = Strings{baseNameOf(shell), "--rcfile", rcFilePath};
+
+ restoreAffinity();
+ restoreSignals();
+
+ execvp(shell.c_str(), stringsToCharPtrs(args).data());
+
+ throw SysError("executing shell '%s'", shell);
+ }
+};
+
+struct CmdPrintDevEnv : Common
+{
+ std::string description() override
+ {
+ return "print shell code that can be sourced by bash to reproduce the build environment of a derivation";
+ }
+
+ Examples examples() override
+ {
+ return {
+ Example{
+ "To apply the build environment of GNU hello to the current shell:",
+ ". <(nix print-dev-env nixpkgs:hello)"
+ },
+ };
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto drvs = toDerivations(store, {installable});
+
+ if (drvs.size() != 1)
+ throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations",
+ installable->what(), drvs.size());
+
+ auto & drvPath = *drvs.begin();
+
+ auto buildEnvironment = getDerivationEnvironment(store, store->derivationFromPath(drvPath));
+
+ stopProgressBar();
+
+ makeRcScript(buildEnvironment, std::cout);
+ }
+};
+
+static auto r1 = registerCommand<CmdPrintDevEnv>("print-dev-env");
+static auto r2 = registerCommand<CmdDevShell>("dev-shell");
diff --git a/src/nix/show-config.cc b/src/nix/show-config.cc
index 86638b50d..87544f937 100644
--- a/src/nix/show-config.cc
+++ b/src/nix/show-config.cc
@@ -8,15 +8,6 @@ using namespace nix;
struct CmdShowConfig : Command, MixJSON
{
- CmdShowConfig()
- {
- }
-
- std::string name() override
- {
- return "show-config";
- }
-
std::string description() override
{
return "show the Nix configuration";
@@ -37,4 +28,4 @@ struct CmdShowConfig : Command, MixJSON
}
};
-static RegisterCommand r1(make_ref<CmdShowConfig>());
+static auto r1 = registerCommand<CmdShowConfig>("show-config");
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index ee94fded3..6065adc4d 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -22,11 +22,6 @@ struct CmdShowDerivation : InstallablesCommand
.set(&recursive, true);
}
- std::string name() override
- {
- return "show-derivation";
- }
-
std::string description() override
{
return "show the contents of a store derivation";
@@ -116,4 +111,4 @@ struct CmdShowDerivation : InstallablesCommand
}
};
-static RegisterCommand r1(make_ref<CmdShowDerivation>());
+static auto r1 = registerCommand<CmdShowDerivation>("show-derivation");
diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc
index b1825c412..23bc83ad0 100644
--- a/src/nix/sigs.cc
+++ b/src/nix/sigs.cc
@@ -22,11 +22,6 @@ struct CmdCopySigs : StorePathsCommand
.handler([&](std::vector<std::string> ss) { substituterUris.push_back(ss[0]); });
}
- std::string name() override
- {
- return "copy-sigs";
- }
-
std::string description() override
{
return "copy path signatures from substituters (like binary caches)";
@@ -93,7 +88,7 @@ struct CmdCopySigs : StorePathsCommand
}
};
-static RegisterCommand r1(make_ref<CmdCopySigs>());
+static auto r1 = registerCommand<CmdCopySigs>("copy-sigs");
struct CmdSignPaths : StorePathsCommand
{
@@ -109,11 +104,6 @@ struct CmdSignPaths : StorePathsCommand
.dest(&secretKeyFile);
}
- std::string name() override
- {
- return "sign-paths";
- }
-
std::string description() override
{
return "sign the specified paths";
@@ -146,4 +136,4 @@ struct CmdSignPaths : StorePathsCommand
}
};
-static RegisterCommand r3(make_ref<CmdSignPaths>());
+static auto r2 = registerCommand<CmdSignPaths>("sign-paths");
diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc
index 35c44a70c..13d8504a6 100644
--- a/src/nix/upgrade-nix.cc
+++ b/src/nix/upgrade-nix.cc
@@ -30,11 +30,6 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
.dest(&storePathsUrl);
}
- std::string name() override
- {
- return "upgrade-nix";
- }
-
std::string description() override
{
return "upgrade Nix to the latest stable version";
@@ -157,4 +152,4 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
}
};
-static RegisterCommand r1(make_ref<CmdUpgradeNix>());
+static auto r1 = registerCommand<CmdUpgradeNix>("upgrade-nix");
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index 7ef571561..f55766eda 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -29,11 +29,6 @@ struct CmdVerify : StorePathsCommand
mkIntFlag('n', "sigs-needed", "require that each path has at least N valid signatures", &sigsNeeded);
}
- std::string name() override
- {
- return "verify";
- }
-
std::string description() override
{
return "verify the integrity of store paths";
@@ -175,4 +170,4 @@ struct CmdVerify : StorePathsCommand
}
};
-static RegisterCommand r1(make_ref<CmdVerify>());
+static auto r1 = registerCommand<CmdVerify>("verify");
diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index 325a2be0a..3d13a77e4 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -44,11 +44,6 @@ struct CmdWhyDepends : SourceExprCommand
.set(&all, true);
}
- std::string name() override
- {
- return "why-depends";
- }
-
std::string description() override
{
return "show why a package has another package in its closure";
@@ -74,9 +69,9 @@ struct CmdWhyDepends : SourceExprCommand
void run(ref<Store> store) override
{
- auto package = parseInstallable(*this, store, _package, false);
+ auto package = parseInstallable(store, _package);
auto packagePath = toStorePath(store, Build, package);
- auto dependency = parseInstallable(*this, store, _dependency, false);
+ auto dependency = parseInstallable(store, _dependency);
auto dependencyPath = toStorePath(store, NoBuild, dependency);
auto dependencyPathHash = storePathToHash(dependencyPath);
@@ -264,4 +259,4 @@ struct CmdWhyDepends : SourceExprCommand
}
};
-static RegisterCommand r1(make_ref<CmdWhyDepends>());
+static auto r1 = registerCommand<CmdWhyDepends>("why-depends");