aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/app.cc7
-rw-r--r--src/nix/build.cc49
-rw-r--r--src/nix/build.md2
-rw-r--r--src/nix/bundle.cc7
-rw-r--r--src/nix/bundle.md2
-rw-r--r--src/nix/cat.cc2
-rw-r--r--src/nix/copy.cc2
-rw-r--r--src/nix/daemon.cc6
-rw-r--r--src/nix/describe-stores.cc44
-rw-r--r--src/nix/develop.cc27
-rw-r--r--src/nix/develop.md2
-rw-r--r--src/nix/diff-closures.cc2
-rw-r--r--src/nix/doctor.cc2
-rw-r--r--src/nix/edit.cc6
-rw-r--r--src/nix/eval.cc12
-rw-r--r--src/nix/eval.md2
-rw-r--r--src/nix/flake.cc60
-rw-r--r--src/nix/flake.md12
-rw-r--r--src/nix/fmt.cc6
-rw-r--r--src/nix/hash.cc39
-rw-r--r--src/nix/help-stores.md46
-rw-r--r--src/nix/log.cc4
-rw-r--r--src/nix/log.md3
-rw-r--r--src/nix/ls.cc2
-rw-r--r--src/nix/main.cc98
-rw-r--r--src/nix/make-content-addressed.cc3
-rw-r--r--src/nix/make-content-addressed.md4
-rw-r--r--src/nix/nar.cc1
-rw-r--r--src/nix/nix.md173
-rw-r--r--src/nix/path-info.md2
-rw-r--r--src/nix/prefetch.cc4
-rw-r--r--src/nix/print-dev-env.md2
-rw-r--r--src/nix/profile-install.md2
-rw-r--r--src/nix/profile.cc136
-rw-r--r--src/nix/profile.md20
-rw-r--r--src/nix/realisation.cc15
-rw-r--r--src/nix/registry.cc3
-rw-r--r--src/nix/repl.cc53
-rw-r--r--src/nix/run.cc8
-rw-r--r--src/nix/run.md2
-rw-r--r--src/nix/search.cc11
-rw-r--r--src/nix/search.md6
-rw-r--r--src/nix/shell.md2
-rw-r--r--src/nix/show-derivation.cc4
-rw-r--r--src/nix/show-derivation.md2
-rw-r--r--src/nix/sigs.cc7
-rw-r--r--src/nix/store-copy-log.cc4
-rw-r--r--src/nix/store-delete.cc2
-rw-r--r--src/nix/store-delete.md2
-rw-r--r--src/nix/store-dump-path.md2
-rw-r--r--src/nix/store-repair.cc2
-rw-r--r--src/nix/store-repair.md2
-rw-r--r--src/nix/store.cc1
-rw-r--r--src/nix/upgrade-nix.md2
-rw-r--r--src/nix/verify.md2
55 files changed, 542 insertions, 381 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 5cd65136f..fd4569bb4 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -1,5 +1,6 @@
#include "installables.hh"
#include "installable-derived-path.hh"
+#include "installable-value.hh"
#include "store-api.hh"
#include "eval-inline.hh"
#include "eval-cache.hh"
@@ -40,7 +41,7 @@ std::string resolveString(
return rewriteStrings(toResolve, rewrites);
}
-UnresolvedApp Installable::toApp(EvalState & state)
+UnresolvedApp InstallableValue::toApp(EvalState & state)
{
auto cursor = getCursor(state);
auto attrPath = cursor->getAttrPath();
@@ -119,11 +120,11 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store)
{
auto res = unresolved;
- std::vector<std::shared_ptr<Installable>> installableContext;
+ Installables installableContext;
for (auto & ctxElt : unresolved.context)
installableContext.push_back(
- std::make_shared<InstallableDerivedPath>(store, DerivedPath { ctxElt }));
+ make_ref<InstallableDerivedPath>(store, DerivedPath { ctxElt }));
auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext);
res.program = resolveString(*store, unresolved.program, builtContext);
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 12b22d999..4e133e288 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -1,4 +1,3 @@
-#include "eval.hh"
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
@@ -41,6 +40,29 @@ nlohmann::json builtPathsWithResultToJSON(const std::vector<BuiltPathWithResult>
return res;
}
+// TODO deduplicate with other code also setting such out links.
+static void createOutLinks(const Path& outLink, const std::vector<BuiltPathWithResult>& buildables, LocalFSStore& store2)
+{
+ for (const auto & [_i, buildable] : enumerate(buildables)) {
+ auto i = _i;
+ std::visit(overloaded {
+ [&](const BuiltPath::Opaque & bo) {
+ std::string symlink = outLink;
+ if (i) symlink += fmt("-%d", i);
+ store2.addPermRoot(bo.path, absPath(symlink));
+ },
+ [&](const BuiltPath::Built & bfd) {
+ for (auto & output : bfd.outputs) {
+ std::string symlink = outLink;
+ if (i) symlink += fmt("-%d", i);
+ if (output.first != "out") symlink += fmt("-%s", output.first);
+ store2.addPermRoot(output.second, absPath(symlink));
+ }
+ },
+ }, buildable.path.raw());
+ }
+}
+
struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
{
Path outLink = "result";
@@ -89,7 +111,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, Installables && installables) override
{
if (dryRun) {
std::vector<DerivedPath> pathsToBuild;
@@ -115,35 +137,18 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
if (outLink != "")
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
- for (const auto & [_i, buildable] : enumerate(buildables)) {
- auto i = _i;
- std::visit(overloaded {
- [&](const BuiltPath::Opaque & bo) {
- std::string symlink = outLink;
- if (i) symlink += fmt("-%d", i);
- store2->addPermRoot(bo.path, absPath(symlink));
- },
- [&](const BuiltPath::Built & bfd) {
- for (auto & output : bfd.outputs) {
- std::string symlink = outLink;
- if (i) symlink += fmt("-%d", i);
- if (output.first != "out") symlink += fmt("-%s", output.first);
- store2->addPermRoot(output.second, absPath(symlink));
- }
- },
- }, buildable.path.raw());
- }
+ createOutLinks(outLink, buildables, *store2);
if (printOutputPaths) {
stopProgressBar();
for (auto & buildable : buildables) {
std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) {
- std::cout << store->printStorePath(bo.path) << std::endl;
+ logger->cout(store->printStorePath(bo.path));
},
[&](const BuiltPath::Built & bfd) {
for (auto & output : bfd.outputs) {
- std::cout << store->printStorePath(output.second) << std::endl;
+ logger->cout(store->printStorePath(output.second));
}
},
}, buildable.path.raw());
diff --git a/src/nix/build.md b/src/nix/build.md
index 6a79f308c..ee414dc86 100644
--- a/src/nix/build.md
+++ b/src/nix/build.md
@@ -82,7 +82,7 @@ R""(
# Description
-`nix build` builds the specified *installables*. Installables that
+`nix build` builds the specified *installables*. [Installables](./nix.md#installables) that
resolve to derivations are built (or substituted if possible). Store
path installables are substituted.
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index dcf9a6f2d..57c355f0c 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -1,14 +1,15 @@
-#include "command.hh"
#include "installable-flake.hh"
+#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
#include "fs-accessor.hh"
+#include "eval-inline.hh"
using namespace nix;
-struct CmdBundle : InstallableCommand
+struct CmdBundle : InstallableValueCommand
{
std::string bundler = "github:NixOS/bundlers";
std::optional<Path> outLink;
@@ -70,7 +71,7 @@ struct CmdBundle : InstallableCommand
return res;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
auto evalState = getEvalState();
diff --git a/src/nix/bundle.md b/src/nix/bundle.md
index a18161a3c..89458aaaa 100644
--- a/src/nix/bundle.md
+++ b/src/nix/bundle.md
@@ -29,7 +29,7 @@ R""(
# Description
-`nix bundle`, by default, packs the closure of the *installable* into a single
+`nix bundle`, by default, packs the closure of the [*installable*](./nix.md#installables) into a single
self-extracting executable. See the [`bundlers`
homepage](https://github.com/NixOS/bundlers) for more details.
diff --git a/src/nix/cat.cc b/src/nix/cat.cc
index 6420a0f79..60aa66ce0 100644
--- a/src/nix/cat.cc
+++ b/src/nix/cat.cc
@@ -17,7 +17,7 @@ struct MixCat : virtual Args
if (st.type != FSAccessor::Type::tRegular)
throw Error("path '%1%' is not a regular file", path);
- std::cout << accessor->readFile(path);
+ writeFull(STDOUT_FILENO, accessor->readFile(path));
}
};
diff --git a/src/nix/copy.cc b/src/nix/copy.cc
index 8730a9a5c..151d28277 100644
--- a/src/nix/copy.cc
+++ b/src/nix/copy.cc
@@ -10,8 +10,6 @@ struct CmdCopy : virtual CopyCommand, virtual BuiltPathsCommand
SubstituteFlag substitute = NoSubstitute;
- using BuiltPathsCommand::run;
-
CmdCopy()
: BuiltPathsCommand(true)
{
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index a22bccba1..7e4a7ba86 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -249,9 +249,9 @@ static void daemonLoop()
if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
throw Error("user '%1%' is not allowed to connect to the Nix daemon", user);
- printInfo(format((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
- % (peer.pidKnown ? std::to_string(peer.pid) : "<unknown>")
- % (peer.uidKnown ? user : "<unknown>"));
+ printInfo((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""),
+ peer.pidKnown ? std::to_string(peer.pid) : "<unknown>",
+ peer.uidKnown ? user : "<unknown>");
// Fork a child to handle the connection.
ProcessOptions options;
diff --git a/src/nix/describe-stores.cc b/src/nix/describe-stores.cc
deleted file mode 100644
index 1dd384c0e..000000000
--- a/src/nix/describe-stores.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "command.hh"
-#include "common-args.hh"
-#include "shared.hh"
-#include "store-api.hh"
-
-#include <nlohmann/json.hpp>
-
-using namespace nix;
-
-struct CmdDescribeStores : Command, MixJSON
-{
- std::string description() override
- {
- return "show registered store types and their available options";
- }
-
- Category category() override { return catUtility; }
-
- void run() override
- {
- auto res = nlohmann::json::object();
- for (auto & implem : *Implementations::registered) {
- auto storeConfig = implem.getConfig();
- auto storeName = storeConfig->name();
- res[storeName] = storeConfig->toJSON();
- }
- if (json) {
- std::cout << res;
- } else {
- for (auto & [storeName, storeConfig] : res.items()) {
- std::cout << "## " << storeName << std::endl << std::endl;
- for (auto & [optionName, optionDesc] : storeConfig.items()) {
- std::cout << "### " << optionName << std::endl << std::endl;
- std::cout << optionDesc["description"].get<std::string>() << std::endl;
- std::cout << "default: " << optionDesc["defaultValue"] << std::endl <<std::endl;
- if (!optionDesc["aliases"].empty())
- std::cout << "aliases: " << optionDesc["aliases"] << std::endl << std::endl;
- }
- }
- }
- }
-};
-
-static auto rDescribeStore = registerCommand<CmdDescribeStores>("describe-stores");
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 9d07a7a85..9e2dcff61 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -1,6 +1,6 @@
#include "eval.hh"
-#include "command.hh"
#include "installable-flake.hh"
+#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
@@ -208,7 +208,7 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
drv.name += "-env";
drv.env.emplace("name", drv.name);
drv.inputSrcs.insert(std::move(getEnvShPath));
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
for (auto & output : drv.outputs) {
output.second = DerivationOutput::Deferred {},
drv.env[output.first] = hashPlaceholder(output.first);
@@ -252,7 +252,7 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
throw Error("get-env.sh failed to produce an environment");
}
-struct Common : InstallableCommand, MixProfile
+struct Common : InstallableValueCommand, MixProfile
{
std::set<std::string> ignoreVars{
"BASHOPTS",
@@ -313,7 +313,7 @@ struct Common : InstallableCommand, MixProfile
buildEnvironment.toBash(out, ignoreVars);
for (auto & var : savedVars)
- out << fmt("%s=\"$%s:$nix_saved_%s\"\n", var, var, var);
+ out << fmt("%s=\"$%s${nix_saved_%s:+:$nix_saved_%s}\"\n", var, var, var, var);
out << "export NIX_BUILD_TOP=\"$(mktemp -d -t nix-shell.XXXXXX)\"\n";
for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"})
@@ -374,7 +374,7 @@ struct Common : InstallableCommand, MixProfile
return res;
}
- StorePath getShellOutPath(ref<Store> store)
+ StorePath getShellOutPath(ref<Store> store, ref<InstallableValue> installable)
{
auto path = installable->getStorePath();
if (path && hasSuffix(path->to_string(), "-env"))
@@ -392,9 +392,10 @@ struct Common : InstallableCommand, MixProfile
}
}
- std::pair<BuildEnvironment, std::string> getBuildEnvironment(ref<Store> store)
+ std::pair<BuildEnvironment, std::string>
+ getBuildEnvironment(ref<Store> store, ref<InstallableValue> installable)
{
- auto shellOutPath = getShellOutPath(store);
+ auto shellOutPath = getShellOutPath(store, installable);
auto strPath = store->printStorePath(shellOutPath);
@@ -480,9 +481,9 @@ struct CmdDevelop : Common, MixEnvironment
;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
- auto [buildEnvironment, gcroot] = getBuildEnvironment(store);
+ auto [buildEnvironment, gcroot] = getBuildEnvironment(store, installable);
auto [rcFileFd, rcFilePath] = createTempFile("nix-shell");
@@ -537,7 +538,7 @@ struct CmdDevelop : Common, MixEnvironment
nixpkgsLockFlags.inputOverrides = {};
nixpkgsLockFlags.inputUpdates = {};
- auto bashInstallable = std::make_shared<InstallableFlake>(
+ auto bashInstallable = make_ref<InstallableFlake>(
this,
state,
installable->nixpkgsFlakeRef(),
@@ -573,7 +574,7 @@ struct CmdDevelop : Common, MixEnvironment
// Need to chdir since phases assume in flake directory
if (phase) {
// chdir if installable is a flake of type git+file or path
- auto installableFlake = std::dynamic_pointer_cast<InstallableFlake>(installable);
+ auto installableFlake = installable.dynamic_pointer_cast<InstallableFlake>();
if (installableFlake) {
auto sourcePath = installableFlake->getLockedFlake()->flake.resolvedRef.input.getSourcePath();
if (sourcePath) {
@@ -604,9 +605,9 @@ struct CmdPrintDevEnv : Common, MixJSON
Category category() override { return catUtility; }
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
- auto buildEnvironment = getBuildEnvironment(store).first;
+ auto buildEnvironment = getBuildEnvironment(store, installable).first;
stopProgressBar();
diff --git a/src/nix/develop.md b/src/nix/develop.md
index 4e8542d1b..c49b39669 100644
--- a/src/nix/develop.md
+++ b/src/nix/develop.md
@@ -76,7 +76,7 @@ R""(
`nix develop` starts a `bash` shell that provides an interactive build
environment nearly identical to what Nix would use to build
-*installable*. Inside this shell, environment variables and shell
+[*installable*](./nix.md#installables). Inside this shell, environment variables and shell
functions are set up so that you can interactively and incrementally
build your package.
diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc
index 3489cc132..c7c37b66f 100644
--- a/src/nix/diff-closures.cc
+++ b/src/nix/diff-closures.cc
@@ -97,7 +97,7 @@ void printClosureDiff(
items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added)));
if (showDelta)
items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0));
- std::cout << fmt("%s%s: %s\n", indent, name, concatStringsSep(", ", items));
+ logger->cout("%s%s: %s", indent, name, concatStringsSep(", ", items));
}
}
}
diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc
index ea87e3d87..7da4549a1 100644
--- a/src/nix/doctor.cc
+++ b/src/nix/doctor.cc
@@ -18,7 +18,7 @@ std::string formatProtocol(unsigned int proto)
if (proto) {
auto major = GET_PROTOCOL_MAJOR(proto) >> 8;
auto minor = GET_PROTOCOL_MINOR(proto);
- return (format("%1%.%2%") % major % minor).str();
+ return fmt("%1%.%2%", major, minor);
}
return "unknown";
}
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index dfe75fbdf..66629fab0 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -1,4 +1,4 @@
-#include "command.hh"
+#include "command-installable-value.hh"
#include "shared.hh"
#include "eval.hh"
#include "attr-path.hh"
@@ -9,7 +9,7 @@
using namespace nix;
-struct CmdEdit : InstallableCommand
+struct CmdEdit : InstallableValueCommand
{
std::string description() override
{
@@ -25,7 +25,7 @@ struct CmdEdit : InstallableCommand
Category category() override { return catSecondary; }
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
auto state = getEvalState();
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index a579213fd..43db5150c 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -1,4 +1,4 @@
-#include "command.hh"
+#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
@@ -11,13 +11,13 @@
using namespace nix;
-struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
+struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
{
bool raw = false;
std::optional<std::string> apply;
std::optional<Path> writeTo;
- CmdEval() : InstallableCommand()
+ CmdEval() : InstallableValueCommand()
{
addFlag({
.longName = "raw",
@@ -54,7 +54,7 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
Category category() override { return catSecondary; }
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
if (raw && json)
throw UsageError("--raw and --json are mutually exclusive");
@@ -112,11 +112,11 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
else if (raw) {
stopProgressBar();
- std::cout << *state->coerceToString(noPos, *v, context, "while generating the eval command output");
+ writeFull(STDOUT_FILENO, *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
}
else if (json) {
- std::cout << printValueAsJSON(*state, true, *v, pos, context, false).dump() << std::endl;
+ logger->cout("%s", printValueAsJSON(*state, true, *v, pos, context, false));
}
else {
diff --git a/src/nix/eval.md b/src/nix/eval.md
index 61334cde1..3b510737a 100644
--- a/src/nix/eval.md
+++ b/src/nix/eval.md
@@ -50,7 +50,7 @@ R""(
# Description
-This command evaluates the Nix expression *installable* and prints the
+This command evaluates the given Nix expression and prints the
result on standard output.
# Output format
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 053a9c9e1..cd4ee5921 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -952,7 +952,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
{"path", store->printStorePath(flake.flake.sourceInfo->storePath)},
{"inputs", traverse(*flake.lockFile.root)},
};
- std::cout << jsonRoot.dump() << std::endl;
+ logger->cout("%s", jsonRoot);
} else {
traverse(*flake.lockFile.root);
}
@@ -1026,36 +1026,43 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
auto visitor2 = visitor.getAttr(attrName);
- if ((attrPathS[0] == "apps"
- || attrPathS[0] == "checks"
- || attrPathS[0] == "devShells"
- || attrPathS[0] == "legacyPackages"
- || attrPathS[0] == "packages")
- && (attrPathS.size() == 1 || attrPathS.size() == 2)) {
- for (const auto &subAttr : visitor2->getAttrs()) {
- if (hasContent(*visitor2, attrPath2, subAttr)) {
- return true;
+ try {
+ if ((attrPathS[0] == "apps"
+ || attrPathS[0] == "checks"
+ || attrPathS[0] == "devShells"
+ || attrPathS[0] == "legacyPackages"
+ || attrPathS[0] == "packages")
+ && (attrPathS.size() == 1 || attrPathS.size() == 2)) {
+ for (const auto &subAttr : visitor2->getAttrs()) {
+ if (hasContent(*visitor2, attrPath2, subAttr)) {
+ return true;
+ }
}
+ return false;
}
- return false;
- }
- if ((attrPathS.size() == 1)
- && (attrPathS[0] == "formatter"
- || attrPathS[0] == "nixosConfigurations"
- || attrPathS[0] == "nixosModules"
- || attrPathS[0] == "overlays"
- )) {
- for (const auto &subAttr : visitor2->getAttrs()) {
- if (hasContent(*visitor2, attrPath2, subAttr)) {
- return true;
+ if ((attrPathS.size() == 1)
+ && (attrPathS[0] == "formatter"
+ || attrPathS[0] == "nixosConfigurations"
+ || attrPathS[0] == "nixosModules"
+ || attrPathS[0] == "overlays"
+ )) {
+ for (const auto &subAttr : visitor2->getAttrs()) {
+ if (hasContent(*visitor2, attrPath2, subAttr)) {
+ return true;
+ }
}
+ return false;
}
- return false;
- }
- // If we don't recognize it, it's probably content
- return true;
+ // If we don't recognize it, it's probably content
+ return true;
+ } catch (EvalError & e) {
+ // Some attrs may contain errors, eg. legacyPackages of
+ // nixpkgs. We still want to recurse into it, instead of
+ // skipping it at all.
+ return true;
+ }
};
std::function<nlohmann::json(
@@ -1328,8 +1335,7 @@ struct CmdFlake : NixMultiCommand
{
if (!command)
throw UsageError("'nix flake' requires a sub-command.");
- settings.requireExperimentalFeature(Xp::Flakes);
- command->second->prepare();
+ experimentalFeatureSettings.require(Xp::Flakes);
command->second->run();
}
};
diff --git a/src/nix/flake.md b/src/nix/flake.md
index 810e9ebea..cd9f656e3 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -54,7 +54,7 @@ output attribute). They are also allowed in the `inputs` attribute
of a flake, e.g.
```nix
-inputs.nixpkgs.url = github:NixOS/nixpkgs;
+inputs.nixpkgs.url = "github:NixOS/nixpkgs";
```
is equivalent to
@@ -275,14 +275,14 @@ Currently the `type` attribute can be one of the following:
# Flake format
As an example, here is a simple `flake.nix` that depends on the
-Nixpkgs flake and provides a single package (i.e. an installable
-derivation):
+Nixpkgs flake and provides a single package (i.e. an
+[installable](./nix.md#installables) derivation):
```nix
{
description = "A flake for building Hello World";
- inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-20.03;
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-20.03";
outputs = { self, nixpkgs }: {
@@ -317,6 +317,8 @@ The following attributes are supported in `flake.nix`:
also contains some metadata about the inputs. These are:
* `outPath`: The path in the Nix store of the flake's source tree.
+ This way, the attribute set can be passed to `import` as if it was a path,
+ as in the example above (`import nixpkgs`).
* `rev`: The commit hash of the flake's repository, if applicable.
@@ -374,7 +376,7 @@ inputs.nixpkgs = {
Alternatively, you can use the URL-like syntax:
```nix
-inputs.import-cargo.url = github:edolstra/import-cargo;
+inputs.import-cargo.url = "github:edolstra/import-cargo";
inputs.nixpkgs.url = "nixpkgs";
```
diff --git a/src/nix/fmt.cc b/src/nix/fmt.cc
index 6f6a4a632..c85eacded 100644
--- a/src/nix/fmt.cc
+++ b/src/nix/fmt.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-value.hh"
#include "run.hh"
using namespace nix;
@@ -31,8 +32,9 @@ struct CmdFmt : SourceExprCommand {
auto evalState = getEvalState();
auto evalStore = getEvalStore();
- auto installable = parseInstallable(store, ".");
- auto app = installable->toApp(*evalState).resolve(evalStore, store);
+ auto installable_ = parseInstallable(store, ".");
+ auto & installable = InstallableValue::require(*installable_);
+ auto app = installable.toApp(*evalState).resolve(evalStore, store);
Strings programArgs{app.program};
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index 60d9593a7..9feca9345 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -151,7 +151,6 @@ struct CmdHash : NixMultiCommand
{
if (!command)
throw UsageError("'nix hash' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
@@ -161,11 +160,11 @@ static auto rCmdHash = registerCommand<CmdHash>("hash");
/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
{
- HashType ht = htMD5;
+ std::optional<HashType> ht;
bool flat = false;
- bool base32 = false;
+ Base base = Base16;
bool truncate = false;
- enum { opHash, opTo32, opTo16 } op = opHash;
+ enum { opHash, opTo } op = opHash;
std::vector<std::string> ss;
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
@@ -174,14 +173,31 @@ static int compatNixHash(int argc, char * * argv)
else if (*arg == "--version")
printVersion("nix-hash");
else if (*arg == "--flat") flat = true;
- else if (*arg == "--base32") base32 = true;
+ else if (*arg == "--base16") base = Base16;
+ else if (*arg == "--base32") base = Base32;
+ else if (*arg == "--base64") base = Base64;
+ else if (*arg == "--sri") base = SRI;
else if (*arg == "--truncate") truncate = true;
else if (*arg == "--type") {
std::string s = getArg(*arg, arg, end);
ht = parseHashType(s);
}
- else if (*arg == "--to-base16") op = opTo16;
- else if (*arg == "--to-base32") op = opTo32;
+ else if (*arg == "--to-base16") {
+ op = opTo;
+ base = Base16;
+ }
+ else if (*arg == "--to-base32") {
+ op = opTo;
+ base = Base32;
+ }
+ else if (*arg == "--to-base64") {
+ op = opTo;
+ base = Base64;
+ }
+ else if (*arg == "--to-sri") {
+ op = opTo;
+ base = SRI;
+ }
else if (*arg != "" && arg->at(0) == '-')
return false;
else
@@ -191,17 +207,18 @@ static int compatNixHash(int argc, char * * argv)
if (op == opHash) {
CmdHashBase cmd(flat ? FileIngestionMethod::Flat : FileIngestionMethod::Recursive);
- cmd.ht = ht;
- cmd.base = base32 ? Base32 : Base16;
+ if (!ht.has_value()) ht = htMD5;
+ cmd.ht = ht.value();
+ cmd.base = base;
cmd.truncate = truncate;
cmd.paths = ss;
cmd.run();
}
else {
- CmdToBase cmd(op == opTo32 ? Base32 : Base16);
+ CmdToBase cmd(base);
cmd.args = ss;
- cmd.ht = ht;
+ if (ht.has_value()) cmd.ht = ht;
cmd.run();
}
diff --git a/src/nix/help-stores.md b/src/nix/help-stores.md
new file mode 100644
index 000000000..47ba9b94d
--- /dev/null
+++ b/src/nix/help-stores.md
@@ -0,0 +1,46 @@
+R"(
+
+Nix supports different types of stores. These are described below.
+
+## Store URL format
+
+Stores are specified using a URL-like syntax. For example, the command
+
+```console
+# nix path-info --store https://cache.nixos.org/ --json \
+ /nix/store/a7gvj343m05j2s32xcnwr35v31ynlypr-coreutils-9.1
+```
+
+fetches information about a store path in the HTTP binary cache
+located at https://cache.nixos.org/, which is a type of store.
+
+Store URLs can specify **store settings** using URL query strings,
+i.e. by appending `?name1=value1&name2=value2&...` to the URL. For
+instance,
+
+```
+--store ssh://machine.example.org?ssh-key=/path/to/my/key
+```
+
+tells Nix to access the store on a remote machine via the SSH
+protocol, using `/path/to/my/key` as the SSH private key. The
+supported settings for each store type are documented below.
+
+The special store URL `auto` causes Nix to automatically select a
+store as follows:
+
+* Use the [local store](#local-store) `/nix/store` if `/nix/var/nix`
+ is writable by the current user.
+
+* Otherwise, if `/nix/var/nix/daemon-socket/socket` exists, [connect
+ to the Nix daemon listening on that socket](#local-daemon-store).
+
+* Otherwise, on Linux only, use the [local chroot store](#local-store)
+ `~/.local/share/nix/root`, which will be created automatically if it
+ does not exist.
+
+* Otherwise, use the [local store](#local-store) `/nix/store`.
+
+@stores@
+
+)"
diff --git a/src/nix/log.cc b/src/nix/log.cc
index a0598ca13..aaf829764 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -23,7 +23,7 @@ struct CmdLog : InstallableCommand
Category category() override { return catSecondary; }
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<Installable> installable) override
{
settings.readOnlyMode = true;
@@ -53,7 +53,7 @@ struct CmdLog : InstallableCommand
if (!log) continue;
stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
- std::cout << *log;
+ writeFull(STDOUT_FILENO, *log);
return;
}
diff --git a/src/nix/log.md b/src/nix/log.md
index 1c76226a3..01e9801df 100644
--- a/src/nix/log.md
+++ b/src/nix/log.md
@@ -22,8 +22,7 @@ R""(
# Description
-This command prints the log of a previous build of the derivation
-*installable* on standard output.
+This command prints the log of a previous build of the [*installable*](./nix.md#installables) on standard output.
Nix looks for build logs in two places:
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index e964b01b3..c990a303c 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -93,7 +93,7 @@ struct MixLs : virtual Args, MixJSON
if (json) {
if (showDirectory)
throw UsageError("'--directory' is useless with '--json'");
- std::cout << listNar(accessor, path, recursive);
+ logger->cout("%s", listNar(accessor, path, recursive));
} else
listText(accessor);
}
diff --git a/src/nix/main.cc b/src/nix/main.cc
index d3d2f5b16..54c920b4e 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -54,17 +54,17 @@ static bool haveInternet()
std::string programPath;
-struct HelpRequested { };
-
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{
bool useNet = true;
bool refresh = false;
+ bool helpRequested = false;
bool showVersion = false;
NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix")
{
categories.clear();
+ categories[catHelp] = "Help commands";
categories[Command::catDefault] = "Main commands";
categories[catSecondary] = "Infrequently used commands";
categories[catUtility] = "Utility/scripting commands";
@@ -74,7 +74,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
.longName = "help",
.description = "Show usage information.",
.category = miscCategory,
- .handler = {[&]() { throw HelpRequested(); }},
+ .handler = {[this]() { this->helpRequested = true; }},
});
addFlag({
@@ -164,11 +164,29 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{
commands = RegisterCommand::getCommandsFor({});
}
+
+ std::string dumpCli()
+ {
+ auto res = nlohmann::json::object();
+
+ res["args"] = toJSON();
+
+ auto stores = nlohmann::json::object();
+ for (auto & implem : *Implementations::registered) {
+ auto storeConfig = implem.getConfig();
+ auto storeName = storeConfig->name();
+ stores[storeName]["doc"] = storeConfig->doc();
+ stores[storeName]["settings"] = storeConfig->toJSON();
+ }
+ res["stores"] = std::move(stores);
+
+ return res.dump();
+ }
};
/* Render the help for the specified subcommand to stdout using
lowdown. */
-static void showHelp(std::vector<std::string> subcommand, MultiCommand & toplevel)
+static void showHelp(std::vector<std::string> subcommand, NixArgs & toplevel)
{
auto mdName = subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand));
@@ -189,11 +207,11 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
, "/"),
*vUtils);
- auto attrs = state.buildBindings(16);
- attrs.alloc("toplevel").mkString(toplevel.toJSON().dump());
+ auto vDump = state.allocValue();
+ vDump->mkString(toplevel.dumpCli());
auto vRes = state.allocValue();
- state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
+ state.callFunction(*vGenerateManpage, *vDump, *vRes, noPos);
auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
if (!attr)
@@ -205,6 +223,14 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
std::cout << renderMarkdownToTerminal(markdown) << "\n";
}
+static NixArgs & getNixArgs(Command & cmd)
+{
+ assert(cmd.parent);
+ MultiCommand * toplevel = cmd.parent;
+ while (toplevel->parent) toplevel = toplevel->parent;
+ return dynamic_cast<NixArgs &>(*toplevel);
+}
+
struct CmdHelp : Command
{
std::vector<std::string> subcommand;
@@ -229,17 +255,43 @@ struct CmdHelp : Command
;
}
+ Category category() override { return catHelp; }
+
void run() override
{
assert(parent);
MultiCommand * toplevel = parent;
while (toplevel->parent) toplevel = toplevel->parent;
- showHelp(subcommand, *toplevel);
+ showHelp(subcommand, getNixArgs(*this));
}
};
static auto rCmdHelp = registerCommand<CmdHelp>("help");
+struct CmdHelpStores : Command
+{
+ std::string description() override
+ {
+ return "show help about store types and their settings";
+ }
+
+ std::string doc() override
+ {
+ return
+ #include "help-stores.md"
+ ;
+ }
+
+ Category category() override { return catHelp; }
+
+ void run() override
+ {
+ showHelp({"help-stores"}, getNixArgs(*this));
+ }
+};
+
+static auto rCmdHelpStores = registerCommand<CmdHelpStores>("help-stores");
+
void mainWrapped(int argc, char * * argv)
{
savedArgv = argv;
@@ -291,13 +343,16 @@ void mainWrapped(int argc, char * * argv)
NixArgs args;
- if (argc == 2 && std::string(argv[1]) == "__dump-args") {
- std::cout << args.toJSON().dump() << "\n";
+ if (argc == 2 && std::string(argv[1]) == "__dump-cli") {
+ logger->cout(args.dumpCli());
return;
}
if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
- settings.experimentalFeatures = {Xp::Flakes, Xp::FetchClosure};
+ experimentalFeatureSettings.experimentalFeatures = {
+ Xp::Flakes,
+ Xp::FetchClosure,
+ };
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object();
@@ -312,7 +367,7 @@ void mainWrapped(int argc, char * * argv)
b["doc"] = trim(stripIndentation(primOp->doc));
res[state.symbols[builtin.name]] = std::move(b);
}
- std::cout << res.dump() << "\n";
+ logger->cout("%s", res);
return;
}
@@ -321,20 +376,24 @@ void mainWrapped(int argc, char * * argv)
if (completions) {
switch (completionType) {
case ctNormal:
- std::cout << "normal\n"; break;
+ logger->cout("normal"); break;
case ctFilenames:
- std::cout << "filenames\n"; break;
+ logger->cout("filenames"); break;
case ctAttrs:
- std::cout << "attrs\n"; break;
+ logger->cout("attrs"); break;
}
for (auto & s : *completions)
- std::cout << s.completion << "\t" << trim(s.description) << "\n";
+ logger->cout(s.completion + "\t" + trim(s.description));
}
});
try {
args.parseCmdline(argvToStrings(argc, argv));
- } catch (HelpRequested &) {
+ } catch (UsageError &) {
+ if (!args.helpRequested && !completions) throw;
+ }
+
+ if (args.helpRequested) {
std::vector<std::string> subcommand;
MultiCommand * command = &args;
while (command) {
@@ -346,8 +405,6 @@ void mainWrapped(int argc, char * * argv)
}
showHelp(subcommand, args);
return;
- } catch (UsageError &) {
- if (!completions) throw;
}
if (completions) {
@@ -366,7 +423,7 @@ void mainWrapped(int argc, char * * argv)
if (args.command->first != "repl"
&& args.command->first != "doctor"
&& args.command->first != "upgrade-nix")
- settings.requireExperimentalFeature(Xp::NixCommand);
+ experimentalFeatureSettings.require(Xp::NixCommand);
if (args.useNet && !haveInternet()) {
warn("you don't have Internet access; disabling some network-dependent features");
@@ -394,7 +451,6 @@ void mainWrapped(int argc, char * * argv)
if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) {
evalSettings.pureEval = false;
}
- args.command->second->prepare();
args.command->second->run();
}
diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc
index d86b90fc7..d9c988a9f 100644
--- a/src/nix/make-content-addressed.cc
+++ b/src/nix/make-content-addressed.cc
@@ -28,7 +28,6 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
;
}
- using StorePathsCommand::run;
void run(ref<Store> srcStore, StorePaths && storePaths) override
{
auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
@@ -45,7 +44,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
}
auto json = json::object();
json["rewrites"] = jsonRewrites;
- std::cout << json.dump();
+ logger->cout("%s", json);
} else {
for (auto & path : storePaths) {
auto i = remappings.find(path);
diff --git a/src/nix/make-content-addressed.md b/src/nix/make-content-addressed.md
index 32eecc880..b1f7da525 100644
--- a/src/nix/make-content-addressed.md
+++ b/src/nix/make-content-addressed.md
@@ -35,7 +35,9 @@ R""(
# Description
This command converts the closure of the store paths specified by
-*installables* to content-addressed form. Nix store paths are usually
+[*installables*](./nix.md#installables) to content-addressed form.
+
+Nix store paths are usually
*input-addressed*, meaning that the hash part of the store path is
computed from the contents of the derivation (i.e., the build-time
dependency graph). Input-addressed paths need to be signed by a
diff --git a/src/nix/nar.cc b/src/nix/nar.cc
index dbb043d9b..9815410cf 100644
--- a/src/nix/nar.cc
+++ b/src/nix/nar.cc
@@ -25,7 +25,6 @@ struct CmdNar : NixMultiCommand
{
if (!command)
throw UsageError("'nix nar' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
diff --git a/src/nix/nix.md b/src/nix/nix.md
index db60c59ff..e1865b31c 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -48,102 +48,112 @@ manual](https://nixos.org/manual/nix/stable/).
# Installables
-Many `nix` subcommands operate on one or more *installables*. These are
-command line arguments that represent something that can be built in
-the Nix store. Here are the recognised types of installables:
-
-* **Flake output attributes**: `nixpkgs#hello`
-
- These have the form *flakeref*[`#`*attrpath*], where *flakeref* is a
- flake reference and *attrpath* is an optional attribute path. For
- more information on flakes, see [the `nix flake` manual
- page](./nix3-flake.md). Flake references are most commonly a flake
- identifier in the flake registry (e.g. `nixpkgs`), or a raw path
- (e.g. `/path/to/my-flake` or `.` or `../foo`), or a full URL
- (e.g. `github:nixos/nixpkgs` or `path:.`)
-
- When the flake reference is a raw path (a path without any URL
- scheme), it is interpreted as a `path:` or `git+file:` url in the following
- way:
-
- - If the path is within a Git repository, then the url will be of the form
- `git+file://[GIT_REPO_ROOT]?dir=[RELATIVE_FLAKE_DIR_PATH]`
- where `GIT_REPO_ROOT` is the path to the root of the git repository,
- and `RELATIVE_FLAKE_DIR_PATH` is the path (relative to the directory
- root) of the closest parent of the given path that contains a `flake.nix` within
- the git repository.
- If no such directory exists, then Nix will error-out.
-
- Note that the search will only include files indexed by git. In particular, files
- which are matched by `.gitignore` or have never been `git add`-ed will not be
- available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
-
- For example, if `/foo/bar` is a git repository with the following structure:
- ```
- .
- └── baz
- ├── blah
- │  └── file.txt
- └── flake.nix
- ```
+Many `nix` subcommands operate on one or more *installables*.
+These are command line arguments that represent something that can be realised in the Nix store.
- Then `/foo/bar/baz/blah` will resolve to `git+file:///foo/bar?dir=baz`
+The following types of installable are supported by most commands:
- - If the supplied path is not a git repository, then the url will have the form
- `path:FLAKE_DIR_PATH` where `FLAKE_DIR_PATH` is the closest parent
- of the supplied path that contains a `flake.nix` file (within the same file-system).
- If no such directory exists, then Nix will error-out.
-
- For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to
- `path:/foo/bar`
+- [Flake output attribute](#flake-output-attribute)
+- [Store path](#store-path)
+- [Nix file](#nix-file), optionally qualified by an attribute path
+- [Nix expression](#nix-expression), optionally qualified by an attribute path
- If *attrpath* is omitted, Nix tries some default values; for most
- subcommands, the default is `packages.`*system*`.default`
- (e.g. `packages.x86_64-linux.default`), but some subcommands have
- other defaults. If *attrpath* *is* specified, *attrpath* is
- interpreted as relative to one or more prefixes; for most
- subcommands, these are `packages.`*system*,
- `legacyPackages.*system*` and the empty prefix. Thus, on
- `x86_64-linux` `nix build nixpkgs#hello` will try to build the
- attributes `packages.x86_64-linux.hello`,
- `legacyPackages.x86_64-linux.hello` and `hello`.
+For most commands, if no installable is specified, `.` as assumed.
+That is, Nix will operate on the default flake output attribute of the flake in the current directory.
-* **Store paths**: `/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10`
+### Flake output attribute
- These are paths inside the Nix store, or symlinks that resolve to a
- path in the Nix store.
+Example: `nixpkgs#hello`
-* **Store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv`
+These have the form *flakeref*[`#`*attrpath*], where *flakeref* is a
+[flake reference](./nix3-flake.md#flake-references) and *attrpath* is an optional attribute path. For
+more information on flakes, see [the `nix flake` manual
+page](./nix3-flake.md). Flake references are most commonly a flake
+identifier in the flake registry (e.g. `nixpkgs`), or a raw path
+(e.g. `/path/to/my-flake` or `.` or `../foo`), or a full URL
+(e.g. `github:nixos/nixpkgs` or `path:.`)
- By default, if you pass a [store derivation] path to a `nix` subcommand, the command will operate on the [output path]s of the derivation.
+When the flake reference is a raw path (a path without any URL
+scheme), it is interpreted as a `path:` or `git+file:` url in the following
+way:
- [output path]: ../../glossary.md#gloss-output-path
+- If the path is within a Git repository, then the url will be of the form
+ `git+file://[GIT_REPO_ROOT]?dir=[RELATIVE_FLAKE_DIR_PATH]`
+ where `GIT_REPO_ROOT` is the path to the root of the git repository,
+ and `RELATIVE_FLAKE_DIR_PATH` is the path (relative to the directory
+ root) of the closest parent of the given path that contains a `flake.nix` within
+ the git repository.
+ If no such directory exists, then Nix will error-out.
- For example, `nix path-info` prints information about the output paths:
+ Note that the search will only include files indexed by git. In particular, files
+ which are matched by `.gitignore` or have never been `git add`-ed will not be
+ available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
- ```console
- # nix path-info --json /nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv
- [{"path":"/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10",…}]
+ For example, if `/foo/bar` is a git repository with the following structure:
+ ```
+ .
+ └── baz
+ ├── blah
+ │  └── file.txt
+ └── flake.nix
```
- If you want to operate on the store derivation itself, pass the
- `--derivation` flag.
+ Then `/foo/bar/baz/blah` will resolve to `git+file:///foo/bar?dir=baz`
+
+- If the supplied path is not a git repository, then the url will have the form
+ `path:FLAKE_DIR_PATH` where `FLAKE_DIR_PATH` is the closest parent
+ of the supplied path that contains a `flake.nix` file (within the same file-system).
+ If no such directory exists, then Nix will error-out.
+
+ For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to
+ `path:/foo/bar`
+
+If *attrpath* is omitted, Nix tries some default values; for most
+subcommands, the default is `packages.`*system*`.default`
+(e.g. `packages.x86_64-linux.default`), but some subcommands have
+other defaults. If *attrpath* *is* specified, *attrpath* is
+interpreted as relative to one or more prefixes; for most
+subcommands, these are `packages.`*system*,
+`legacyPackages.*system*` and the empty prefix. Thus, on
+`x86_64-linux` `nix build nixpkgs#hello` will try to build the
+attributes `packages.x86_64-linux.hello`,
+`legacyPackages.x86_64-linux.hello` and `hello`.
+
+### Store path
+
+Example: `/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10`
+
+These are paths inside the Nix store, or symlinks that resolve to a path in the Nix store.
-* **Nix attributes**: `--file /path/to/nixpkgs hello`
+A [store derivation] is also addressed by store path.
- When the `-f` / `--file` *path* option is given, installables are
- interpreted as attribute paths referencing a value returned by
- evaluating the Nix file *path*.
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv`
-* **Nix expressions**: `--expr '(import <nixpkgs> {}).hello.overrideDerivation (prev: { name = "my-hello"; })'`.
+If you want to refer to an output path of that store derivation, add the output name preceded by a caret (`^`).
- When the `--expr` option is given, all installables are interpreted
- as Nix expressions. You may need to specify `--impure` if the
- expression references impure inputs (such as `<nixpkgs>`).
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out`
-For most commands, if no installable is specified, the default is `.`,
-i.e. Nix will operate on the default flake output attribute of the
-flake in the current directory.
+All outputs can be referred to at once with the special syntax `^*`.
+
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^*`
+
+### Nix file
+
+Example: `--file /path/to/nixpkgs hello`
+
+When the option `-f` / `--file` *path* \[*attrpath*...\] is given, installables are interpreted as the value of the expression in the Nix file at *path*.
+If attribute paths are provided, commands will operate on the corresponding values accessible at these paths.
+The Nix expression in that file, or any selected attribute, must evaluate to a derivation.
+
+### Nix expression
+
+Example: `--expr 'import <nixpkgs> {}' hello`
+
+When the option `--expr` *expression* \[*attrpath*...\] is given, installables are interpreted as the value of the of the Nix expression.
+If attribute paths are provided, commands will operate on the corresponding values accessible at these paths.
+The Nix expression, or any selected attribute, must evaluate to a derivation.
+
+You may need to specify `--impure` if the expression references impure inputs (such as `<nixpkgs>`).
## Derivation output selection
@@ -210,8 +220,7 @@ operate are determined as follows:
# Nix stores
-Most `nix` subcommands operate on a *Nix store*.
-
-TODO: list store types, options
+Most `nix` subcommands operate on a *Nix store*. These are documented
+in [`nix help-stores`](./nix3-help-stores.md).
)""
diff --git a/src/nix/path-info.md b/src/nix/path-info.md
index b30898ac0..6ad23a02e 100644
--- a/src/nix/path-info.md
+++ b/src/nix/path-info.md
@@ -80,7 +80,7 @@ R""(
# Description
This command shows information about the store paths produced by
-*installables*, or about all paths in the store if you pass `--all`.
+[*installables*](./nix.md#installables), or about all paths in the store if you pass `--all`.
By default, this command only prints the store paths. You can get
additional information by passing flags such as `--closure-size`,
diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc
index 209517b21..b06b8a320 100644
--- a/src/nix/prefetch.cc
+++ b/src/nix/prefetch.cc
@@ -240,9 +240,9 @@ static int main_nix_prefetch_url(int argc, char * * argv)
if (!printPath)
printInfo("path is '%s'", store->printStorePath(storePath));
- std::cout << printHash16or32(hash) << std::endl;
+ logger->cout(printHash16or32(hash));
if (printPath)
- std::cout << store->printStorePath(storePath) << std::endl;
+ logger->cout(store->printStorePath(storePath));
return 0;
}
diff --git a/src/nix/print-dev-env.md b/src/nix/print-dev-env.md
index 2aad491de..a8ce9d36a 100644
--- a/src/nix/print-dev-env.md
+++ b/src/nix/print-dev-env.md
@@ -40,7 +40,7 @@ R""(
This command prints a shell script that can be sourced by `bash` and
that sets the variables and shell functions defined by the build
-process of *installable*. This allows you to get a similar build
+process of [*installable*](./nix.md#installables). This allows you to get a similar build
environment in your current shell rather than in a subshell (as with
`nix develop`).
diff --git a/src/nix/profile-install.md b/src/nix/profile-install.md
index aed414963..4c0f82c09 100644
--- a/src/nix/profile-install.md
+++ b/src/nix/profile-install.md
@@ -29,6 +29,6 @@ R""(
# Description
-This command adds *installables* to a Nix profile.
+This command adds [*installables*](./nix.md#installables) to a Nix profile.
)""
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 04ac48f00..5aa87a313 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -237,12 +237,12 @@ struct ProfileManifest
while (i != prevElems.end() || j != curElems.end()) {
if (j != curElems.end() && (i == prevElems.end() || i->describe() > j->describe())) {
- std::cout << fmt("%s%s: ∅ -> %s\n", indent, j->describe(), j->versions());
+ logger->cout("%s%s: ∅ -> %s", indent, j->describe(), j->versions());
changes = true;
++j;
}
else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) {
- std::cout << fmt("%s%s: %s -> ∅\n", indent, i->describe(), i->versions());
+ logger->cout("%s%s: %s -> ∅", indent, i->describe(), i->versions());
changes = true;
++i;
}
@@ -250,7 +250,7 @@ struct ProfileManifest
auto v1 = i->versions();
auto v2 = j->versions();
if (v1 != v2) {
- std::cout << fmt("%s%s: %s -> %s\n", indent, i->describe(), v1, v2);
+ logger->cout("%s%s: %s -> %s", indent, i->describe(), v1, v2);
changes = true;
}
++i;
@@ -259,17 +259,23 @@ struct ProfileManifest
}
if (!changes)
- std::cout << fmt("%sNo changes.\n", indent);
+ logger->cout("%sNo changes.", indent);
}
};
-static std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>>
+static std::map<Installable *, std::pair<BuiltPaths, ref<ExtraPathInfo>>>
builtPathsPerInstallable(
- const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> & builtPaths)
+ const std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> & builtPaths)
{
- std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>> res;
+ std::map<Installable *, std::pair<BuiltPaths, ref<ExtraPathInfo>>> res;
for (auto & [installable, builtPath] : builtPaths) {
- auto & r = res[installable.get()];
+ auto & r = res.insert({
+ &*installable,
+ {
+ {},
+ make_ref<ExtraPathInfo>(),
+ }
+ }).first->second;
/* Note that there could be conflicting info
(e.g. meta.priority fields) if the installable returned
multiple derivations. So pick one arbitrarily. FIXME:
@@ -305,7 +311,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, Installables && installables) override
{
ProfileManifest manifest(*getEvalState(), *profile);
@@ -316,14 +322,16 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
for (auto & installable : installables) {
ProfileElement element;
- auto & [res, info] = builtPaths[installable.get()];
+ auto iter = builtPaths.find(&*installable);
+ if (iter == builtPaths.end()) continue;
+ auto & [res, info] = iter->second;
- if (info.originalRef && info.resolvedRef && info.attrPath && info.extendedOutputsSpec) {
+ if (auto * info2 = dynamic_cast<ExtraPathInfoFlake *>(&*info)) {
element.source = ProfileElementSource {
- .originalRef = *info.originalRef,
- .resolvedRef = *info.resolvedRef,
- .attrPath = *info.attrPath,
- .outputs = *info.extendedOutputsSpec,
+ .originalRef = info2->flake.originalRef,
+ .resolvedRef = info2->flake.resolvedRef,
+ .attrPath = info2->value.attrPath,
+ .outputs = info2->value.extendedOutputsSpec,
};
}
@@ -332,14 +340,75 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
element.priority =
priority
? *priority
- : info.priority.value_or(defaultPriority);
+ : ({
+ auto * info2 = dynamic_cast<ExtraPathInfoValue *>(&*info);
+ info2
+ ? info2->value.priority.value_or(defaultPriority)
+ : defaultPriority;
+ });
element.updateStorePaths(getEvalStore(), store, res);
manifest.elements.push_back(std::move(element));
}
- updateProfile(manifest.build(store));
+ try {
+ updateProfile(manifest.build(store));
+ } catch (BuildEnvFileConflictError & conflictError) {
+ // FIXME use C++20 std::ranges once macOS has it
+ // See https://github.com/NixOS/nix/compare/3efa476c5439f8f6c1968a6ba20a31d1239c2f04..1fe5d172ece51a619e879c4b86f603d9495cc102
+ auto findRefByFilePath = [&]<typename Iterator>(Iterator begin, Iterator end) {
+ for (auto it = begin; it != end; it++) {
+ auto profileElement = *it;
+ for (auto & storePath : profileElement.storePaths) {
+ if (conflictError.fileA.starts_with(store->printStorePath(storePath))) {
+ return std::pair(conflictError.fileA, profileElement.source->originalRef);
+ }
+ if (conflictError.fileB.starts_with(store->printStorePath(storePath))) {
+ return std::pair(conflictError.fileB, profileElement.source->originalRef);
+ }
+ }
+ }
+ throw conflictError;
+ };
+ // There are 2 conflicting files. We need to find out which one is from the already installed package and
+ // which one is the package that is the new package that is being installed.
+ // The first matching package is the one that was already installed (original).
+ auto [originalConflictingFilePath, originalConflictingRef] = findRefByFilePath(manifest.elements.begin(), manifest.elements.end());
+ // The last matching package is the one that was going to be installed (new).
+ auto [newConflictingFilePath, newConflictingRef] = findRefByFilePath(manifest.elements.rbegin(), manifest.elements.rend());
+
+ throw Error(
+ "An existing package already provides the following file:\n"
+ "\n"
+ " %1%\n"
+ "\n"
+ "This is the conflicting file from the new package:\n"
+ "\n"
+ " %2%\n"
+ "\n"
+ "To remove the existing package:\n"
+ "\n"
+ " nix profile remove %3%\n"
+ "\n"
+ "The new package can also be installed next to the existing one by assigning a different priority.\n"
+ "The conflicting packages have a priority of %5%.\n"
+ "To prioritise the new package:\n"
+ "\n"
+ " nix profile install %4% --priority %6%\n"
+ "\n"
+ "To prioritise the existing package:\n"
+ "\n"
+ " nix profile install %4% --priority %7%\n",
+ originalConflictingFilePath,
+ newConflictingFilePath,
+ originalConflictingRef.to_string(),
+ newConflictingRef.to_string(),
+ conflictError.priority,
+ conflictError.priority - 1,
+ conflictError.priority + 1
+ );
+ }
}
};
@@ -466,7 +535,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
auto matchers = getMatchers(store);
- std::vector<std::shared_ptr<Installable>> installables;
+ Installables installables;
std::vector<size_t> indices;
auto upgradedCount = 0;
@@ -482,7 +551,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath));
- auto installable = std::make_shared<InstallableFlake>(
+ auto installable = make_ref<InstallableFlake>(
this,
getEvalState(),
FlakeRef(element.source->originalRef),
@@ -494,19 +563,20 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
auto derivedPaths = installable->toDerivedPaths();
if (derivedPaths.empty()) continue;
- auto & info = derivedPaths[0].info;
-
- assert(info.resolvedRef && info.attrPath);
+ auto * infop = dynamic_cast<ExtraPathInfoFlake *>(&*derivedPaths[0].info);
+ // `InstallableFlake` should use `ExtraPathInfoFlake`.
+ assert(infop);
+ auto & info = *infop;
- if (element.source->resolvedRef == info.resolvedRef) continue;
+ if (element.source->resolvedRef == info.flake.resolvedRef) continue;
printInfo("upgrading '%s' from flake '%s' to '%s'",
- element.source->attrPath, element.source->resolvedRef, *info.resolvedRef);
+ element.source->attrPath, element.source->resolvedRef, info.flake.resolvedRef);
element.source = ProfileElementSource {
.originalRef = installable->flakeRef,
- .resolvedRef = *info.resolvedRef,
- .attrPath = *info.attrPath,
+ .resolvedRef = info.flake.resolvedRef,
+ .attrPath = info.value.attrPath,
.outputs = installable->extendedOutputsSpec,
};
@@ -535,7 +605,10 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
for (size_t i = 0; i < installables.size(); ++i) {
auto & installable = installables.at(i);
auto & element = manifest.elements[indices.at(i)];
- element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()].first);
+ element.updateStorePaths(
+ getEvalStore(),
+ store,
+ builtPaths.find(&*installable)->second.first);
}
updateProfile(manifest.build(store));
@@ -593,9 +666,9 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile
for (auto & gen : gens) {
if (prevGen) {
- if (!first) std::cout << "\n";
+ if (!first) logger->cout("");
first = false;
- std::cout << fmt("Version %d -> %d:\n", prevGen->number, gen.number);
+ logger->cout("Version %d -> %d:", prevGen->number, gen.number);
printClosureDiff(store,
store->followLinksToStorePath(prevGen->path),
store->followLinksToStorePath(gen.path),
@@ -631,10 +704,10 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile
for (auto & gen : gens) {
ProfileManifest manifest(*getEvalState(), gen.path);
- if (!first) std::cout << "\n";
+ if (!first) logger->cout("");
first = false;
- std::cout << fmt("Version %s%d" ANSI_NORMAL " (%s)%s:\n",
+ logger->cout("Version %s%d" ANSI_NORMAL " (%s)%s:",
gen.number == curGen ? ANSI_GREEN : ANSI_BOLD,
gen.number,
std::put_time(std::gmtime(&gen.creationTime), "%Y-%m-%d"),
@@ -751,7 +824,6 @@ struct CmdProfile : NixMultiCommand
{
if (!command)
throw UsageError("'nix profile' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
diff --git a/src/nix/profile.md b/src/nix/profile.md
index 273e02280..bf61ef4b9 100644
--- a/src/nix/profile.md
+++ b/src/nix/profile.md
@@ -12,7 +12,7 @@ them to be rolled back easily.
The default profile used by `nix profile` is `$HOME/.nix-profile`,
which, if it does not exist, is created as a symlink to
`/nix/var/nix/profiles/default` if Nix is invoked by the
-`root` user, or `/nix/var/nix/profiles/per-user/`*username* otherwise.
+`root` user, or `${XDG_STATE_HOME-$HOME/.local/state}/nix/profiles/profile` otherwise.
You can specify another profile location using `--profile` *path*.
@@ -24,11 +24,11 @@ the profile. In turn, *path*`-`*N* is a symlink to a path in the Nix
store. For example:
```console
-$ ls -l /nix/var/nix/profiles/per-user/alice/profile*
-lrwxrwxrwx 1 alice users 14 Nov 25 14:35 /nix/var/nix/profiles/per-user/alice/profile -> profile-7-link
-lrwxrwxrwx 1 alice users 51 Oct 28 16:18 /nix/var/nix/profiles/per-user/alice/profile-5-link -> /nix/store/q69xad13ghpf7ir87h0b2gd28lafjj1j-profile
-lrwxrwxrwx 1 alice users 51 Oct 29 13:20 /nix/var/nix/profiles/per-user/alice/profile-6-link -> /nix/store/6bvhpysd7vwz7k3b0pndn7ifi5xr32dg-profile
-lrwxrwxrwx 1 alice users 51 Nov 25 14:35 /nix/var/nix/profiles/per-user/alice/profile-7-link -> /nix/store/mp0x6xnsg0b8qhswy6riqvimai4gm677-profile
+$ ls -l ~alice/.local/state/nix/profiles/profile*
+lrwxrwxrwx 1 alice users 14 Nov 25 14:35 /home/alice/.local/state/nix/profiles/profile -> profile-7-link
+lrwxrwxrwx 1 alice users 51 Oct 28 16:18 /home/alice/.local/state/nix/profiles/profile-5-link -> /nix/store/q69xad13ghpf7ir87h0b2gd28lafjj1j-profile
+lrwxrwxrwx 1 alice users 51 Oct 29 13:20 /home/alice/.local/state/nix/profiles/profile-6-link -> /nix/store/6bvhpysd7vwz7k3b0pndn7ifi5xr32dg-profile
+lrwxrwxrwx 1 alice users 51 Nov 25 14:35 /home/alice/.local/state/nix/profiles/profile-7-link -> /nix/store/mp0x6xnsg0b8qhswy6riqvimai4gm677-profile
```
Each of these symlinks is a root for the Nix garbage collector.
@@ -38,20 +38,20 @@ profile is a tree of symlinks to the files of the installed packages,
e.g.
```console
-$ ll -R /nix/var/nix/profiles/per-user/eelco/profile-7-link/
-/nix/var/nix/profiles/per-user/eelco/profile-7-link/:
+$ ll -R ~eelco/.local/state/nix/profiles/profile-7-link/
+/home/eelco/.local/state/nix/profiles/profile-7-link/:
total 20
dr-xr-xr-x 2 root root 4096 Jan 1 1970 bin
-r--r--r-- 2 root root 1402 Jan 1 1970 manifest.json
dr-xr-xr-x 4 root root 4096 Jan 1 1970 share
-/nix/var/nix/profiles/per-user/eelco/profile-7-link/bin:
+/home/eelco/.local/state/nix/profiles/profile-7-link/bin:
total 20
lrwxrwxrwx 5 root root 79 Jan 1 1970 chromium -> /nix/store/ijm5k0zqisvkdwjkc77mb9qzb35xfi4m-chromium-86.0.4240.111/bin/chromium
lrwxrwxrwx 7 root root 87 Jan 1 1970 spotify -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/bin/spotify
lrwxrwxrwx 3 root root 79 Jan 1 1970 zoom-us -> /nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927/bin/zoom-us
-/nix/var/nix/profiles/per-user/eelco/profile-7-link/share/applications:
+/home/eelco/.local/state/nix/profiles/profile-7-link/share/applications:
total 12
lrwxrwxrwx 4 root root 120 Jan 1 1970 chromium-browser.desktop -> /nix/store/4cf803y4vzfm3gyk3vzhzb2327v0kl8a-chromium-unwrapped-86.0.4240.111/share/applications/chromium-browser.desktop
lrwxrwxrwx 7 root root 110 Jan 1 1970 spotify.desktop -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/share/applications/spotify.desktop
diff --git a/src/nix/realisation.cc b/src/nix/realisation.cc
index c9a7157cd..e19e93219 100644
--- a/src/nix/realisation.cc
+++ b/src/nix/realisation.cc
@@ -21,7 +21,6 @@ struct CmdRealisation : virtual NixMultiCommand
{
if (!command)
throw UsageError("'nix realisation' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
@@ -46,7 +45,7 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
void run(ref<Store> store, BuiltPaths && paths) override
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
RealisedPath::Set realisations;
for (auto & builtPath : paths) {
@@ -65,18 +64,16 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
res.push_back(currentPath);
}
- std::cout << res.dump();
+ logger->cout("%s", res);
}
else {
for (auto & path : realisations) {
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
- std::cout <<
- realisation->id.to_string() << " " <<
- store->printStorePath(realisation->outPath);
+ logger->cout("%s %s",
+ realisation->id.to_string(),
+ store->printStorePath(realisation->outPath));
} else
- std::cout << store->printStorePath(path.path());
-
- std::cout << std::endl;
+ logger->cout("%s", store->printStorePath(path.path()));
}
}
}
diff --git a/src/nix/registry.cc b/src/nix/registry.cc
index b5bdfba95..cb94bbd31 100644
--- a/src/nix/registry.cc
+++ b/src/nix/registry.cc
@@ -224,10 +224,9 @@ struct CmdRegistry : virtual NixMultiCommand
void run() override
{
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
if (!command)
throw UsageError("'nix registry' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 679bdea77..7aa8774e9 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -1,30 +1,17 @@
#include "eval.hh"
#include "globals.hh"
#include "command.hh"
+#include "installable-value.hh"
#include "repl.hh"
namespace nix {
-struct CmdRepl : InstallablesCommand
+struct CmdRepl : RawInstallablesCommand
{
CmdRepl() {
evalSettings.pureEval = false;
}
- void prepare() override
- {
- if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
- warn("future versions of Nix will require using `--file` to load a file");
- if (this->_installables.size() > 1)
- warn("more than one input file is not currently supported");
- auto filePath = this->_installables[0].data();
- file = std::optional(filePath);
- _installables.front() = _installables.back();
- _installables.pop_back();
- }
- installables = InstallablesCommand::load();
- }
-
std::vector<std::string> files;
Strings getDefaultFlakeAttrPaths() override
@@ -32,11 +19,6 @@ struct CmdRepl : InstallablesCommand
return {""};
}
- bool useDefaultInstallables() override
- {
- return file.has_value() or expr.has_value();
- }
-
bool forceImpureByDefault() override
{
return true;
@@ -54,17 +36,34 @@ struct CmdRepl : InstallablesCommand
;
}
- void run(ref<Store> store) override
+ void applyDefaultInstallables(std::vector<std::string> & rawInstallables) override
+ {
+ if (!experimentalFeatureSettings.isEnabled(Xp::ReplFlake) && !(file) && rawInstallables.size() >= 1) {
+ warn("future versions of Nix will require using `--file` to load a file");
+ if (rawInstallables.size() > 1)
+ warn("more than one input file is not currently supported");
+ auto filePath = rawInstallables[0].data();
+ file = std::optional(filePath);
+ rawInstallables.front() = rawInstallables.back();
+ rawInstallables.pop_back();
+ }
+ if (rawInstallables.empty() && (file.has_value() || expr.has_value())) {
+ rawInstallables.push_back(".");
+ }
+ }
+
+ void run(ref<Store> store, std::vector<std::string> && rawInstallables) override
{
auto state = getEvalState();
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
- auto installables = load();
+ auto installables = parseInstallables(store, rawInstallables);
AbstractNixRepl::AnnotatedValues values;
- for (auto & installable: installables){
- auto what = installable->what();
+ for (auto & installable_: installables){
+ auto & installable = InstallableValue::require(*installable_);
+ auto what = installable.what();
if (file){
- auto [val, pos] = installable->toValue(*state);
- auto what = installable->what();
+ auto [val, pos] = installable.toValue(*state);
+ auto what = installable.what();
state->forceValue(*val, pos);
auto autoArgs = getAutoArgs(*state);
auto valPost = state->allocValue();
@@ -72,7 +71,7 @@ struct CmdRepl : InstallablesCommand
state->forceValue(*valPost, pos);
values.push_back( {valPost, what });
} else {
- auto [val, pos] = installable->toValue(*state);
+ auto [val, pos] = installable.toValue(*state);
values.push_back( {val, what} );
}
}
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 6fca68047..1baf299ab 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -1,5 +1,5 @@
#include "run.hh"
-#include "command.hh"
+#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
@@ -97,7 +97,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, Installables && installables) override
{
auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
@@ -137,7 +137,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
static auto rCmdShell = registerCommand<CmdShell>("shell");
-struct CmdRun : InstallableCommand
+struct CmdRun : InstallableValueCommand
{
using InstallableCommand::run;
@@ -183,7 +183,7 @@ struct CmdRun : InstallableCommand
return res;
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
auto state = getEvalState();
diff --git a/src/nix/run.md b/src/nix/run.md
index a0f362076..250ea65aa 100644
--- a/src/nix/run.md
+++ b/src/nix/run.md
@@ -35,7 +35,7 @@ R""(
# Description
-`nix run` builds and runs *installable*, which must evaluate to an
+`nix run` builds and runs [*installable*](./nix.md#installables), which must evaluate to an
*app* or a regular Nix derivation.
If *installable* evaluates to an *app* (see below), it executes the
diff --git a/src/nix/search.cc b/src/nix/search.cc
index 4fa1e7837..c92ed1663 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -1,4 +1,4 @@
-#include "command.hh"
+#include "command-installable-value.hh"
#include "globals.hh"
#include "eval.hh"
#include "eval-inline.hh"
@@ -22,7 +22,7 @@ std::string wrap(std::string prefix, std::string s)
return concatStrings(prefix, s, ANSI_NORMAL);
}
-struct CmdSearch : InstallableCommand, MixJSON
+struct CmdSearch : InstallableValueCommand, MixJSON
{
std::vector<std::string> res;
std::vector<std::string> excludeRes;
@@ -61,7 +61,7 @@ struct CmdSearch : InstallableCommand, MixJSON
};
}
- void run(ref<Store> store) override
+ void run(ref<Store> store, ref<InstallableValue> installable) override
{
settings.readOnlyMode = true;
evalSettings.enableImportFromDerivation.setDefault(false);
@@ -196,9 +196,8 @@ struct CmdSearch : InstallableCommand, MixJSON
for (auto & cursor : installable->getCursors(*state))
visit(*cursor, cursor->getAttrPath(), true);
- if (json) {
- std::cout << jsonOut->dump() << std::endl;
- }
+ if (json)
+ logger->cout("%s", *jsonOut);
if (!json && !results)
throw Error("no results for the given search term(s)!");
diff --git a/src/nix/search.md b/src/nix/search.md
index 5a5b5ae05..4caa90654 100644
--- a/src/nix/search.md
+++ b/src/nix/search.md
@@ -62,10 +62,10 @@ R""(
# Description
-`nix search` searches *installable* (which must be evaluatable, e.g. a
-flake) for packages whose name or description matches all of the
+`nix search` searches [*installable*](./nix.md#installables) (which can be evaluated, that is, a
+flake or Nix expression, but not a store path or store derivation path) for packages whose name or description matches all of the
regular expressions *regex*. For each matching package, It prints the
-full attribute name (from the root of the installable), the version
+full attribute name (from the root of the [installable](./nix.md#installables)), the version
and the `meta.description` field, highlighting the substrings that
were matched by the regular expressions. If no regular expressions are
specified, all packages are shown.
diff --git a/src/nix/shell.md b/src/nix/shell.md
index 9fa1031f5..13a389103 100644
--- a/src/nix/shell.md
+++ b/src/nix/shell.md
@@ -48,7 +48,7 @@ R""(
# Description
`nix shell` runs a command in an environment in which the `$PATH` variable
-provides the specified *installables*. If no command is specified, it starts the
+provides the specified [*installables*](./nix.md#installable). If no command is specified, it starts the
default shell of your user account specified by `$SHELL`.
)""
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index d1a516cad..4a406ae08 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -39,7 +39,7 @@ struct CmdShowDerivation : InstallablesCommand
Category category() override { return catUtility; }
- void run(ref<Store> store) override
+ void run(ref<Store> store, Installables && installables) override
{
auto drvPaths = Installable::toDerivations(store, installables, true);
@@ -57,7 +57,7 @@ struct CmdShowDerivation : InstallablesCommand
jsonRoot[store->printStorePath(drvPath)] =
store->readDerivation(drvPath).toJSON(*store);
}
- std::cout << jsonRoot.dump(2) << std::endl;
+ logger->cout(jsonRoot.dump(2));
}
};
diff --git a/src/nix/show-derivation.md b/src/nix/show-derivation.md
index 2cd93aa62..1d37c6f5a 100644
--- a/src/nix/show-derivation.md
+++ b/src/nix/show-derivation.md
@@ -39,7 +39,7 @@ R""(
# Description
This command prints on standard output a JSON representation of the
-[store derivation]s to which *installables* evaluate. Store derivations
+[store derivation]s to which [*installables*](./nix.md#installables) evaluate. Store derivations
are used internally by Nix. They are store paths with extension `.drv`
that represent the build-time dependency graph to which a Nix
expression evaluates.
diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc
index 3d659d6d2..45cd2e1a6 100644
--- a/src/nix/sigs.cc
+++ b/src/nix/sigs.cc
@@ -45,7 +45,7 @@ struct CmdCopySigs : StorePathsCommand
//logger->setExpected(doneLabel, storePaths.size());
auto doPath = [&](const Path & storePathS) {
- //Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath);
+ //Activity act(*logger, lvlInfo, "getting signatures for '%s'", storePath);
checkInterrupt();
@@ -173,7 +173,7 @@ struct CmdKeyGenerateSecret : Command
if (!keyName)
throw UsageError("required argument '--key-name' is missing");
- std::cout << SecretKey::generate(*keyName).to_string();
+ writeFull(STDOUT_FILENO, SecretKey::generate(*keyName).to_string());
}
};
@@ -194,7 +194,7 @@ struct CmdKeyConvertSecretToPublic : Command
void run() override
{
SecretKey secretKey(drainFD(STDIN_FILENO));
- std::cout << secretKey.toPublicKey().to_string();
+ writeFull(STDOUT_FILENO, secretKey.toPublicKey().to_string());
}
};
@@ -219,7 +219,6 @@ struct CmdKey : NixMultiCommand
{
if (!command)
throw UsageError("'nix key' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc
index d5fab5f2f..a6e8aeff7 100644
--- a/src/nix/store-copy-log.cc
+++ b/src/nix/store-copy-log.cc
@@ -24,9 +24,7 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
;
}
- Category category() override { return catUtility; }
-
- void run(ref<Store> srcStore) override
+ void run(ref<Store> srcStore, Installables && installables) override
{
auto & srcLogStore = require<LogStore>(*srcStore);
diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc
index ca43f1530..6719227df 100644
--- a/src/nix/store-delete.cc
+++ b/src/nix/store-delete.cc
@@ -32,7 +32,7 @@ struct CmdStoreDelete : StorePathsCommand
;
}
- void run(ref<Store> store, std::vector<StorePath> && storePaths) override
+ void run(ref<Store> store, StorePaths && storePaths) override
{
auto & gcStore = require<GcStore>(*store);
diff --git a/src/nix/store-delete.md b/src/nix/store-delete.md
index db535f87c..431bc5f5e 100644
--- a/src/nix/store-delete.md
+++ b/src/nix/store-delete.md
@@ -10,7 +10,7 @@ R""(
# Description
-This command deletes the store paths specified by *installables*. ,
+This command deletes the store paths specified by [*installables*](./nix.md#installables),
but only if it is safe to do so; that is, when the path is not
reachable from a root of the garbage collector. This means that you
can only delete paths that would also be deleted by `nix store
diff --git a/src/nix/store-dump-path.md b/src/nix/store-dump-path.md
index 4ef563526..56e2174b6 100644
--- a/src/nix/store-dump-path.md
+++ b/src/nix/store-dump-path.md
@@ -18,6 +18,6 @@ R""(
# Description
This command generates a NAR file containing the serialisation of the
-store path *installable*. The NAR is written to standard output.
+store path [*installable*](./nix.md#installables). The NAR is written to standard output.
)""
diff --git a/src/nix/store-repair.cc b/src/nix/store-repair.cc
index 8fcb3639a..895e39685 100644
--- a/src/nix/store-repair.cc
+++ b/src/nix/store-repair.cc
@@ -17,7 +17,7 @@ struct CmdStoreRepair : StorePathsCommand
;
}
- void run(ref<Store> store, std::vector<StorePath> && storePaths) override
+ void run(ref<Store> store, StorePaths && storePaths) override
{
for (auto & path : storePaths)
store->repairPath(path);
diff --git a/src/nix/store-repair.md b/src/nix/store-repair.md
index 92d2205a9..180c577ac 100644
--- a/src/nix/store-repair.md
+++ b/src/nix/store-repair.md
@@ -17,7 +17,7 @@ R""(
# Description
This command attempts to "repair" the store paths specified by
-*installables* by redownloading them using the available
+[*installables*](./nix.md#installables) by redownloading them using the available
substituters. If no substitutes are available, then repair is not
possible.
diff --git a/src/nix/store.cc b/src/nix/store.cc
index 44e53c7c7..2879e03b3 100644
--- a/src/nix/store.cc
+++ b/src/nix/store.cc
@@ -18,7 +18,6 @@ struct CmdStore : virtual NixMultiCommand
{
if (!command)
throw UsageError("'nix store' requires a sub-command.");
- command->second->prepare();
command->second->run();
}
};
diff --git a/src/nix/upgrade-nix.md b/src/nix/upgrade-nix.md
index 084c80ba2..08757aebd 100644
--- a/src/nix/upgrade-nix.md
+++ b/src/nix/upgrade-nix.md
@@ -11,7 +11,7 @@ R""(
* Upgrade Nix in a specific profile:
```console
- # nix upgrade-nix -p /nix/var/nix/profiles/per-user/alice/profile
+ # nix upgrade-nix -p ~alice/.local/state/nix/profiles/profile
```
# Description
diff --git a/src/nix/verify.md b/src/nix/verify.md
index 1c43792e7..cc1122c02 100644
--- a/src/nix/verify.md
+++ b/src/nix/verify.md
@@ -24,7 +24,7 @@ R""(
# Description
-This command verifies the integrity of the store paths *installables*,
+This command verifies the integrity of the store paths [*installables*](./nix.md#installables),
or, if `--all` is given, the entire Nix store. For each path, it
checks that