aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/app.cc59
-rw-r--r--src/nix/build.cc10
-rw-r--r--src/nix/bundle.cc18
-rw-r--r--src/nix/daemon.cc55
-rw-r--r--src/nix/develop.cc22
-rw-r--r--src/nix/diff-closures.cc2
-rw-r--r--src/nix/edit.cc1
-rw-r--r--src/nix/eval.cc6
-rw-r--r--src/nix/flake-update.md2
-rw-r--r--src/nix/flake.cc188
-rw-r--r--src/nix/flake.md73
-rw-r--r--src/nix/log.cc2
-rw-r--r--src/nix/main.cc2
-rw-r--r--src/nix/nix.md29
-rw-r--r--src/nix/path-info.md4
-rw-r--r--src/nix/ping-store.cc24
-rw-r--r--src/nix/prefetch.cc16
-rw-r--r--src/nix/profile-list.md6
-rw-r--r--src/nix/profile-upgrade.md6
-rw-r--r--src/nix/profile.cc79
-rw-r--r--src/nix/profile.md3
-rw-r--r--src/nix/registry.cc8
-rw-r--r--src/nix/repl.cc95
-rw-r--r--src/nix/run.cc13
-rw-r--r--src/nix/run.hh3
-rw-r--r--src/nix/search.cc4
-rw-r--r--src/nix/show-config.cc31
-rw-r--r--src/nix/show-derivation.cc52
-rw-r--r--src/nix/show-derivation.md6
-rw-r--r--src/nix/store-copy-log.cc8
-rw-r--r--src/nix/store-copy-log.md4
-rw-r--r--src/nix/upgrade-nix.cc2
-rw-r--r--src/nix/verify.cc6
-rw-r--r--src/nix/why-depends.cc26
34 files changed, 560 insertions, 305 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 5658f2a52..5cd65136f 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -1,4 +1,5 @@
#include "installables.hh"
+#include "installable-derived-path.hh"
#include "store-api.hh"
#include "eval-inline.hh"
#include "eval-cache.hh"
@@ -8,31 +9,6 @@
namespace nix {
-struct InstallableDerivedPath : Installable
-{
- ref<Store> store;
- const DerivedPath derivedPath;
-
- InstallableDerivedPath(ref<Store> store, const DerivedPath & derivedPath)
- : store(store)
- , derivedPath(derivedPath)
- {
- }
-
-
- std::string what() const override { return derivedPath.to_string(*store); }
-
- DerivedPaths toDerivedPaths() override
- {
- return {derivedPath};
- }
-
- std::optional<StorePath> getStorePath() override
- {
- return std::nullopt;
- }
-};
-
/**
* Return the rewrites that are needed to resolve a string whose context is
* included in `dependencies`.
@@ -80,9 +56,29 @@ UnresolvedApp Installable::toApp(EvalState & state)
if (type == "app") {
auto [program, context] = cursor->getAttr("program")->getStringWithContext();
- std::vector<StorePathWithOutputs> context2;
- for (auto & [path, name] : context)
- context2.push_back({path, {name}});
+ std::vector<DerivedPath> context2;
+ for (auto & c : context) {
+ context2.emplace_back(std::visit(overloaded {
+ [&](const NixStringContextElem::DrvDeep & d) -> DerivedPath {
+ /* We want all outputs of the drv */
+ return DerivedPath::Built {
+ .drvPath = d.drvPath,
+ .outputs = OutputsSpec::All {},
+ };
+ },
+ [&](const NixStringContextElem::Built & b) -> DerivedPath {
+ return DerivedPath::Built {
+ .drvPath = b.drvPath,
+ .outputs = OutputsSpec::Names { b.output },
+ };
+ },
+ [&](const NixStringContextElem::Opaque & o) -> DerivedPath {
+ return DerivedPath::Opaque {
+ .path = o.path,
+ };
+ },
+ }, c.raw()));
+ }
return UnresolvedApp{App {
.context = std::move(context2),
@@ -106,7 +102,10 @@ UnresolvedApp Installable::toApp(EvalState & state)
: DrvName(name).name;
auto program = outPath + "/bin/" + mainProgram;
return UnresolvedApp { App {
- .context = { { drvPath, {outputName} } },
+ .context = { DerivedPath::Built {
+ .drvPath = drvPath,
+ .outputs = OutputsSpec::Names { outputName },
+ } },
.program = program,
}};
}
@@ -124,7 +123,7 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store)
for (auto & ctxElt : unresolved.context)
installableContext.push_back(
- std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath()));
+ std::make_shared<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 94b169167..12b22d999 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -94,13 +94,15 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
if (dryRun) {
std::vector<DerivedPath> pathsToBuild;
- for (auto & i : installables) {
- auto b = i->toDerivedPaths();
- pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
- }
+ for (auto & i : installables)
+ for (auto & b : i->toDerivedPaths())
+ pathsToBuild.push_back(b.path);
+
printMissing(store, pathsToBuild, lvlError);
+
if (json)
logger->cout("%s", derivedPathsToJSON(pathsToBuild, store).dump());
+
return;
}
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 2e48e4c74..dcf9a6f2d 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
@@ -75,10 +76,10 @@ struct CmdBundle : InstallableCommand
auto val = installable->toValue(*evalState).first;
- auto [bundlerFlakeRef, bundlerName, outputsSpec] = parseFlakeRefWithFragmentAndOutputsSpec(bundler, absPath("."));
+ auto [bundlerFlakeRef, bundlerName, extendedOutputsSpec] = parseFlakeRefWithFragmentAndExtendedOutputsSpec(bundler, absPath("."));
const flake::LockFlags lockFlags{ .writeLockFile = false };
InstallableFlake bundler{this,
- evalState, std::move(bundlerFlakeRef), bundlerName, outputsSpec,
+ evalState, std::move(bundlerFlakeRef), bundlerName, extendedOutputsSpec,
{"bundlers." + settings.thisSystem.get() + ".default",
"defaultBundler." + settings.thisSystem.get()
},
@@ -97,15 +98,20 @@ struct CmdBundle : InstallableCommand
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
PathSet context2;
- auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2);
+ auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");
auto attr2 = vRes->attrs->get(evalState->sOutPath);
if (!attr2)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
- auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2);
+ auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2, "");
- store->buildPaths({ DerivedPath::Built { drvPath } });
+ store->buildPaths({
+ DerivedPath::Built {
+ .drvPath = drvPath,
+ .outputs = OutputsSpec::All { },
+ },
+ });
auto outPathS = store->printStorePath(outPath);
@@ -113,7 +119,7 @@ struct CmdBundle : InstallableCommand
auto * attr = vRes->attrs->get(evalState->sName);
if (!attr)
throw Error("attribute 'name' missing");
- outLink = evalState->forceStringNoCtx(*attr->value, attr->pos);
+ outLink = evalState->forceStringNoCtx(*attr->value, attr->pos, "");
}
// TODO: will crash if not a localFSStore?
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index 940923d3b..a22bccba1 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -34,6 +34,43 @@
using namespace nix;
using namespace nix::daemon;
+struct AuthorizationSettings : Config {
+
+ Setting<Strings> trustedUsers{
+ this, {"root"}, "trusted-users",
+ R"(
+ A list of names of users (separated by whitespace) that have
+ additional rights when connecting to the Nix daemon, such as the
+ ability to specify additional binary caches, or to import unsigned
+ NARs. You can also specify groups by prefixing them with `@`; for
+ instance, `@wheel` means all users in the `wheel` group. The default
+ is `root`.
+
+ > **Warning**
+ >
+ > Adding a user to `trusted-users` is essentially equivalent to
+ > giving that user root access to the system. For example, the user
+ > can set `sandbox-paths` and thereby obtain read access to
+ > directories that are otherwise inacessible to them.
+ )"};
+
+ /* ?Who we trust to use the daemon in safe ways */
+ Setting<Strings> allowedUsers{
+ this, {"*"}, "allowed-users",
+ R"(
+ A list of names of users (separated by whitespace) that are allowed
+ to connect to the Nix daemon. As with the `trusted-users` option,
+ you can specify groups by prefixing them with `@`. Also, you can
+ allow all users by specifying `*`. The default is `*`.
+
+ Note that trusted users are always allowed to connect.
+ )"};
+};
+
+AuthorizationSettings authorizationSettings;
+
+static GlobalConfig::Register rSettings(&authorizationSettings);
+
#ifndef __linux__
#define SPLICE_F_MOVE 0
static ssize_t splice(int fd_in, void *off_in, int fd_out, void *off_out, size_t len, unsigned int flags)
@@ -203,8 +240,8 @@ static void daemonLoop()
struct group * gr = peer.gidKnown ? getgrgid(peer.gid) : 0;
std::string group = gr ? gr->gr_name : std::to_string(peer.gid);
- Strings trustedUsers = settings.trustedUsers;
- Strings allowedUsers = settings.allowedUsers;
+ Strings trustedUsers = authorizationSettings.trustedUsers;
+ Strings allowedUsers = authorizationSettings.allowedUsers;
if (matchUser(user, group, trustedUsers))
trusted = Trusted;
@@ -241,15 +278,7 @@ static void daemonLoop()
// Handle the connection.
FdSource from(remote.get());
FdSink to(remote.get());
- processConnection(openUncachedStore(), from, to, trusted, NotRecursive, [&](Store & store) {
-#if 0
- /* Prevent users from doing something very dangerous. */
- if (geteuid() == 0 &&
- querySetting("build-users-group", "") == "")
- throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!");
-#endif
- store.createUser(user, peer.uid);
- });
+ processConnection(openUncachedStore(), from, to, trusted, NotRecursive);
exit(0);
}, options);
@@ -257,7 +286,7 @@ static void daemonLoop()
} catch (Interrupted & e) {
return;
} catch (Error & error) {
- ErrorInfo ei = error.info();
+ auto ei = error.info();
// FIXME: add to trace?
ei.msg = hintfmt("error processing connection: %1%", ei.msg.str());
logError(ei);
@@ -302,7 +331,7 @@ static void runDaemon(bool stdio)
/* Auth hook is empty because in this mode we blindly trust the
standard streams. Limiting access to those is explicitly
not `nix-daemon`'s responsibility. */
- processConnection(openUncachedStore(), from, to, Trusted, NotRecursive, [&](Store & _){});
+ processConnection(openUncachedStore(), from, to, Trusted, NotRecursive);
}
} else
daemonLoop();
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 4de109754..9d07a7a85 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -1,9 +1,10 @@
#include "eval.hh"
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
-#include "path-with-outputs.hh"
+#include "outputs-spec.hh"
#include "derivations.hh"
#include "progress-bar.hh"
#include "run.hh"
@@ -164,6 +165,14 @@ struct BuildEnvironment
{
return vars == other.vars && bashFunctions == other.bashFunctions;
}
+
+ std::string getSystem() const
+ {
+ if (auto v = get(vars, "system"))
+ return getString(*v);
+ else
+ return settings.thisSystem;
+ }
};
const static std::string getEnvSh =
@@ -192,10 +201,12 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
drv.env.erase("allowedRequisites");
drv.env.erase("disallowedReferences");
drv.env.erase("disallowedRequisites");
+ drv.env.erase("name");
/* Rehash and write the derivation. FIXME: would be nice to use
'buildDerivation', but that's privileged. */
drv.name += "-env";
+ drv.env.emplace("name", drv.name);
drv.inputSrcs.insert(std::move(getEnvShPath));
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
for (auto & output : drv.outputs) {
@@ -222,7 +233,12 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
auto shellDrvPath = writeDerivation(*evalStore, drv);
/* Build the derivation. */
- store->buildPaths({DerivedPath::Built{shellDrvPath}}, bmNormal, evalStore);
+ store->buildPaths(
+ { DerivedPath::Built {
+ .drvPath = shellDrvPath,
+ .outputs = OutputsSpec::All { },
+ }},
+ bmNormal, evalStore);
for (auto & [_0, optPath] : evalStore->queryPartialDerivationOutputMap(shellDrvPath)) {
assert(optPath);
@@ -568,7 +584,7 @@ struct CmdDevelop : Common, MixEnvironment
}
}
- runProgramInStore(store, shell, args);
+ runProgramInStore(store, shell, args, buildEnvironment.getSystem());
}
};
diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc
index 0621d662c..3489cc132 100644
--- a/src/nix/diff-closures.cc
+++ b/src/nix/diff-closures.cc
@@ -106,7 +106,7 @@ void printClosureDiff(
using namespace nix;
-struct CmdDiffClosures : SourceExprCommand
+struct CmdDiffClosures : SourceExprCommand, MixOperateOnOptions
{
std::string _before, _after;
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index 76a134b1f..dfe75fbdf 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -3,6 +3,7 @@
#include "eval.hh"
#include "attr-path.hh"
#include "progress-bar.hh"
+#include "editor-for.hh"
#include <unistd.h>
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index ba82b5772..a579213fd 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -11,13 +11,13 @@
using namespace nix;
-struct CmdEval : MixJSON, InstallableCommand
+struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
{
bool raw = false;
std::optional<std::string> apply;
std::optional<Path> writeTo;
- CmdEval() : InstallableCommand(true /* supportReadOnlyMode */)
+ CmdEval() : InstallableCommand()
{
addFlag({
.longName = "raw",
@@ -112,7 +112,7 @@ struct CmdEval : MixJSON, InstallableCommand
else if (raw) {
stopProgressBar();
- std::cout << *state->coerceToString(noPos, *v, context);
+ std::cout << *state->coerceToString(noPos, *v, context, "while generating the eval command output");
}
else if (json) {
diff --git a/src/nix/flake-update.md b/src/nix/flake-update.md
index 2ee8a707d..8c6042d94 100644
--- a/src/nix/flake-update.md
+++ b/src/nix/flake-update.md
@@ -16,7 +16,7 @@ R""(
# Description
This command recreates the lock file of a flake (`flake.lock`), thus
-updating the lock for every mutable input (like `nixpkgs`) to its
+updating the lock for every unlocked input (like `nixpkgs`) to its
current version. This is equivalent to passing `--recreate-lock-file`
to any command that operates on a flake. That is,
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 336f6723a..053a9c9e1 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "eval.hh"
@@ -7,7 +8,7 @@
#include "get-drvs.hh"
#include "store-api.hh"
#include "derivations.hh"
-#include "path-with-outputs.hh"
+#include "outputs-spec.hh"
#include "attr-path.hh"
#include "fetchers.hh"
#include "registry.hh"
@@ -126,12 +127,12 @@ static void enumerateOutputs(EvalState & state, Value & vFlake,
std::function<void(const std::string & name, Value & vProvide, const PosIdx pos)> callback)
{
auto pos = vFlake.determinePos(noPos);
- state.forceAttrs(vFlake, pos);
+ state.forceAttrs(vFlake, pos, "while evaluating a flake to get its outputs");
auto aOutputs = vFlake.attrs->get(state.symbols.create("outputs"));
assert(aOutputs);
- state.forceAttrs(*aOutputs->value, pos);
+ state.forceAttrs(*aOutputs->value, pos, "while evaluating the outputs of a flake");
auto sHydraJobs = state.symbols.create("hydraJobs");
@@ -215,7 +216,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
if (!lockedFlake.lockFile.root->inputs.empty())
logger->cout(ANSI_BOLD "Inputs:" ANSI_NORMAL);
- std::unordered_set<std::shared_ptr<Node>> visited;
+ std::set<ref<Node>> visited;
std::function<void(const Node & node, const std::string & prefix)> recurse;
@@ -227,7 +228,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
if (auto lockedNode = std::get_if<0>(&input.second)) {
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
prefix + (last ? treeLast : treeConn), input.first,
- *lockedNode ? (*lockedNode)->lockedRef : flake.lockedRef);
+ (*lockedNode)->lockedRef);
bool firstVisit = visited.insert(*lockedNode).second;
@@ -348,7 +349,7 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME
auto app = App(*state, v);
for (auto & i : app.context) {
- auto [drvPathS, outputName] = decodeContext(i);
+ auto [drvPathS, outputName] = NixStringContextElem::parse(i);
store->parseStorePath(drvPathS);
}
#endif
@@ -381,23 +382,6 @@ struct CmdFlakeCheck : FlakeCommand
auto checkModule = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
- if (v.isLambda()) {
- if (!v.lambda.fun->hasFormals() || !v.lambda.fun->formals->ellipsis)
- throw Error("module must match an open attribute set ('{ config, ... }')");
- } else if (v.type() == nAttrs) {
- for (auto & attr : *v.attrs)
- try {
- state->forceValue(*attr.value, attr.pos);
- } catch (Error & e) {
- e.addTrace(
- state->positions[attr.pos],
- hintfmt("while evaluating the option '%s'", state->symbols[attr.name]));
- throw;
- }
- } else
- throw Error("module must be a function or an attribute set");
- // FIXME: if we have a 'nixpkgs' input, use it to
- // check the module.
} catch (Error & e) {
e.addTrace(resolve(pos), hintfmt("while checking the NixOS module '%s'", attrPath));
reportError(e);
@@ -408,13 +392,13 @@ struct CmdFlakeCheck : FlakeCommand
checkHydraJobs = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
- state->forceAttrs(v, pos);
+ state->forceAttrs(v, pos, "");
if (state->isDerivation(v))
throw Error("jobset should not be a derivation at top-level");
for (auto & attr : *v.attrs) {
- state->forceAttrs(*attr.value, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos, "");
auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]);
if (state->isDerivation(*attr.value)) {
Activity act(*logger, lvlChatty, actUnknown,
@@ -436,7 +420,7 @@ struct CmdFlakeCheck : FlakeCommand
fmt("checking NixOS configuration '%s'", attrPath));
Bindings & bindings(*state->allocBindings(0));
auto vToplevel = findAlongAttrPath(*state, "config.system.build.toplevel", bindings, v).first;
- state->forceAttrs(*vToplevel, pos);
+ state->forceValue(*vToplevel, pos);
if (!state->isDerivation(*vToplevel))
throw Error("attribute 'config.system.build.toplevel' is not a derivation");
} catch (Error & e) {
@@ -450,12 +434,12 @@ struct CmdFlakeCheck : FlakeCommand
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking template '%s'", attrPath));
- state->forceAttrs(v, pos);
+ state->forceAttrs(v, pos, "");
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
if (attr->name == state->symbols.create("path")) {
PathSet context;
- auto path = state->coerceToPath(attr->pos, *attr->value, context);
+ auto path = state->coerceToPath(attr->pos, *attr->value, context, "");
if (!store->isInStore(path))
throw Error("template '%s' has a bad 'path' attribute");
// TODO: recursively check the flake in 'path'.
@@ -464,7 +448,7 @@ struct CmdFlakeCheck : FlakeCommand
throw Error("template '%s' lacks attribute 'path'", attrPath);
if (auto attr = v.attrs->get(state->symbols.create("description")))
- state->forceStringNoCtx(*attr->value, attr->pos);
+ state->forceStringNoCtx(*attr->value, attr->pos, "");
else
throw Error("template '%s' lacks attribute 'description'", attrPath);
@@ -521,23 +505,27 @@ struct CmdFlakeCheck : FlakeCommand
warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement);
if (name == "checks") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- state->forceAttrs(*attr.value, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos, "");
for (auto & attr2 : *attr.value->attrs) {
auto drvPath = checkDerivation(
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
*attr2.value, attr2.pos);
- if (drvPath && attr_name == settings.thisSystem.get())
- drvPaths.push_back(DerivedPath::Built{*drvPath});
+ if (drvPath && attr_name == settings.thisSystem.get()) {
+ drvPaths.push_back(DerivedPath::Built {
+ .drvPath = *drvPath,
+ .outputs = OutputsSpec::All { },
+ });
+ }
}
}
}
else if (name == "formatter") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
@@ -548,11 +536,11 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "packages" || name == "devShells") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- state->forceAttrs(*attr.value, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos, "");
for (auto & attr2 : *attr.value->attrs)
checkDerivation(
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
@@ -561,11 +549,11 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "apps") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- state->forceAttrs(*attr.value, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos, "");
for (auto & attr2 : *attr.value->attrs)
checkApp(
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
@@ -574,7 +562,7 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "defaultPackage" || name == "devShell") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
@@ -585,7 +573,7 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "defaultApp") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
@@ -596,7 +584,7 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "legacyPackages") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
checkSystemName(state->symbols[attr.name], attr.pos);
// FIXME: do getDerivations?
@@ -607,7 +595,7 @@ struct CmdFlakeCheck : FlakeCommand
checkOverlay(name, vOutput, pos);
else if (name == "overlays") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs)
checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]),
*attr.value, attr.pos);
@@ -617,14 +605,14 @@ struct CmdFlakeCheck : FlakeCommand
checkModule(name, vOutput, pos);
else if (name == "nixosModules") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs)
checkModule(fmt("%s.%s", name, state->symbols[attr.name]),
*attr.value, attr.pos);
}
else if (name == "nixosConfigurations") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs)
checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]),
*attr.value, attr.pos);
@@ -637,14 +625,14 @@ struct CmdFlakeCheck : FlakeCommand
checkTemplate(name, vOutput, pos);
else if (name == "templates") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs)
checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]),
*attr.value, attr.pos);
}
else if (name == "defaultBundler") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
@@ -655,11 +643,11 @@ struct CmdFlakeCheck : FlakeCommand
}
else if (name == "bundlers") {
- state->forceAttrs(vOutput, pos);
+ state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- state->forceAttrs(*attr.value, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos, "");
for (auto & attr2 : *attr.value->attrs) {
checkBundler(
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
@@ -668,6 +656,19 @@ struct CmdFlakeCheck : FlakeCommand
}
}
+ else if (
+ name == "lib"
+ || name == "darwinConfigurations"
+ || name == "darwinModules"
+ || name == "flakeModule"
+ || name == "flakeModules"
+ || name == "herculesCI"
+ || name == "homeConfigurations"
+ || name == "nixopsConfigurations"
+ )
+ // Known but unchecked community attribute
+ ;
+
else
warn("unknown flake output '%s'", name);
@@ -966,6 +967,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
struct CmdFlakeShow : FlakeCommand, MixJSON
{
bool showLegacy = false;
+ bool showAllSystems = false;
CmdFlakeShow()
{
@@ -974,6 +976,11 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
.description = "Show the contents of the `legacyPackages` output.",
.handler = {&showLegacy, true}
});
+ addFlag({
+ .longName = "all-systems",
+ .description = "Show the contents of outputs for all systems.",
+ .handler = {&showAllSystems, true}
+ });
}
std::string description() override
@@ -994,6 +1001,62 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
auto state = getEvalState();
auto flake = std::make_shared<LockedFlake>(lockFlake());
+ auto localSystem = std::string(settings.thisSystem.get());
+
+ std::function<bool(
+ eval_cache::AttrCursor & visitor,
+ const std::vector<Symbol> &attrPath,
+ const Symbol &attr)> hasContent;
+
+ // For frameworks it's important that structures are as lazy as possible
+ // to prevent infinite recursions, performance issues and errors that
+ // aren't related to the thing to evaluate. As a consequence, they have
+ // to emit more attributes than strictly (sic) necessary.
+ // However, these attributes with empty values are not useful to the user
+ // so we omit them.
+ hasContent = [&](
+ eval_cache::AttrCursor & visitor,
+ const std::vector<Symbol> &attrPath,
+ const Symbol &attr) -> bool
+ {
+ auto attrPath2(attrPath);
+ attrPath2.push_back(attr);
+ auto attrPathS = state->symbols.resolve(attrPath2);
+ const auto & attrName = state->symbols[attr];
+
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ return false;
+ }
+
+ // If we don't recognize it, it's probably content
+ return true;
+ };
std::function<nlohmann::json(
eval_cache::AttrCursor & visitor,
@@ -1020,7 +1083,12 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
{
if (!json)
logger->cout("%s", headerPrefix);
- auto attrs = visitor.getAttrs();
+ std::vector<Symbol> attrs;
+ for (const auto &attr : visitor.getAttrs()) {
+ if (hasContent(visitor, attrPath, attr))
+ attrs.push_back(attr);
+ }
+
for (const auto & [i, attr] : enumerate(attrs)) {
const auto & attrName = state->symbols[attr];
bool last = i + 1 == attrs.size();
@@ -1084,10 +1152,18 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|| (attrPath.size() == 3 && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells"))
)
{
- if (visitor.isDerivation())
- showDerivation();
- else
- throw Error("expected a derivation");
+ if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
+ if (!json)
+ logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
+ else {
+ logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
+ }
+ } else {
+ if (visitor.isDerivation())
+ showDerivation();
+ else
+ throw Error("expected a derivation");
+ }
}
else if (attrPath.size() > 0 && attrPathS[0] == "hydraJobs") {
@@ -1106,6 +1182,12 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
else {
logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPathS)));
}
+ } else if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
+ if (!json)
+ logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
+ else {
+ logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
+ }
} else {
if (visitor.isDerivation())
showDerivation();
diff --git a/src/nix/flake.md b/src/nix/flake.md
index a1ab43281..810e9ebea 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -18,51 +18,56 @@ values such as packages or NixOS modules provided by the flake).
Flake references (*flakerefs*) are a way to specify the location of a
flake. These have two different forms:
-* An attribute set representation, e.g.
- ```nix
- {
- type = "github";
- owner = "NixOS";
- repo = "nixpkgs";
- }
- ```
+## Attribute set representation
- The only required attribute is `type`. The supported types are
- listed below.
+Example:
-* A URL-like syntax, e.g.
+```nix
+{
+ type = "github";
+ owner = "NixOS";
+ repo = "nixpkgs";
+}
+```
- ```
- github:NixOS/nixpkgs
- ```
+The only required attribute is `type`. The supported types are
+listed below.
- These are used on the command line as a more convenient alternative
- to the attribute set representation. For instance, in the command
+## URL-like syntax
- ```console
- # nix build github:NixOS/nixpkgs#hello
- ```
+Example:
- `github:NixOS/nixpkgs` is a flake reference (while `hello` is an
- output attribute). They are also allowed in the `inputs` attribute
- of a flake, e.g.
+```
+github:NixOS/nixpkgs
+```
- ```nix
- inputs.nixpkgs.url = github:NixOS/nixpkgs;
- ```
+These are used on the command line as a more convenient alternative
+to the attribute set representation. For instance, in the command
- is equivalent to
+```console
+# nix build github:NixOS/nixpkgs#hello
+```
- ```nix
- inputs.nixpkgs = {
- type = "github";
- owner = "NixOS";
- repo = "nixpkgs";
- };
- ```
+`github:NixOS/nixpkgs` is a flake reference (while `hello` is an
+output attribute). They are also allowed in the `inputs` attribute
+of a flake, e.g.
+
+```nix
+inputs.nixpkgs.url = github:NixOS/nixpkgs;
+```
+
+is equivalent to
+
+```nix
+inputs.nixpkgs = {
+ type = "github";
+ owner = "NixOS";
+ repo = "nixpkgs";
+};
+```
-## Examples
+### Examples
Here are some examples of flake references in their URL-like representation:
diff --git a/src/nix/log.cc b/src/nix/log.cc
index 72d02ef11..a0598ca13 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -49,7 +49,7 @@ struct CmdLog : InstallableCommand
[&](const DerivedPath::Built & bfd) {
return logSub.getBuildLog(bfd.drvPath);
},
- }, b.raw());
+ }, b.path.raw());
if (!log) continue;
stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 2c6309c81..d3d2f5b16 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -199,7 +199,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
if (!attr)
throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand));
- auto markdown = state.forceString(*attr->value);
+ auto markdown = state.forceString(*attr->value, noPos, "while evaluating the lowdown help text");
RunPager pager;
std::cout << renderMarkdownToTerminal(markdown) << "\n";
diff --git a/src/nix/nix.md b/src/nix/nix.md
index d48682a94..db60c59ff 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -115,12 +115,11 @@ the Nix store. Here are the recognised types of installables:
* **Store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv`
- Store derivations are store paths with extension `.drv` and are a
- low-level representation of a build-time dependency graph used
- internally by Nix. By default, if you pass a store derivation to a
- `nix` subcommand, it will operate on the *output paths* of the
- derivation. For example, `nix path-info` prints information about
- the output paths:
+ 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.
+
+ [output path]: ../../glossary.md#gloss-output-path
+
+ For example, `nix path-info` prints information about the output paths:
```console
# nix path-info --json /nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv
@@ -164,6 +163,13 @@ operate are determined as follows:
```
+ and likewise, using a store path to a "drv" file to specify the derivation:
+
+ ```console
+ # nix build '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev,static'
+ …
+ ```
+
* You can also specify that *all* outputs should be used using the
syntax *installable*`^*`. For example, the following shows the size
of all outputs of the `glibc` package in the binary cache:
@@ -177,6 +183,12 @@ operate are determined as follows:
/nix/store/q6580lr01jpcsqs4r5arlh4ki2c1m9rv-glibc-2.33-123-dev 44200560
```
+ and likewise, using a store path to a "drv" file to specify the derivation:
+
+ ```console
+ # nix path-info -S '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*'
+ …
+ ```
* If you didn't specify the desired outputs, but the derivation has an
attribute `meta.outputsToInstall`, Nix will use those outputs. For
example, since the package `nixpkgs#libxml2` has this attribute:
@@ -189,6 +201,11 @@ operate are determined as follows:
a command like `nix shell nixpkgs#libxml2` will provide only those
two outputs by default.
+ Note that a [store derivation] (given by its `.drv` file store path) doesn't have
+ any attributes like `meta`, and thus this case doesn't apply to it.
+
+ [store derivation]: ../../glossary.md#gloss-store-derivation
+
* Otherwise, Nix will use all outputs of the derivation.
# Nix stores
diff --git a/src/nix/path-info.md b/src/nix/path-info.md
index 7a1714ba4..b30898ac0 100644
--- a/src/nix/path-info.md
+++ b/src/nix/path-info.md
@@ -68,7 +68,9 @@ R""(
]
```
-* Print the path of the store derivation produced by `nixpkgs#hello`:
+* Print the path of the [store derivation] produced by `nixpkgs#hello`:
+
+ [store derivation]: ../../glossary.md#gloss-store-derivation
```console
# nix path-info --derivation nixpkgs#hello
diff --git a/src/nix/ping-store.cc b/src/nix/ping-store.cc
index 3c3b7bb45..5c44510ab 100644
--- a/src/nix/ping-store.cc
+++ b/src/nix/ping-store.cc
@@ -1,10 +1,13 @@
#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "finally.hh"
+
+#include <nlohmann/json.hpp>
using namespace nix;
-struct CmdPingStore : StoreCommand
+struct CmdPingStore : StoreCommand, MixJSON
{
std::string description() override
{
@@ -20,10 +23,21 @@ struct CmdPingStore : StoreCommand
void run(ref<Store> store) override
{
- notice("Store URL: %s", store->getUri());
- store->connect();
- if (auto version = store->getVersion())
- notice("Version: %s", *version);
+ if (!json) {
+ notice("Store URL: %s", store->getUri());
+ store->connect();
+ if (auto version = store->getVersion())
+ notice("Version: %s", *version);
+ } else {
+ nlohmann::json res;
+ Finally printRes([&]() {
+ logger->cout("%s", res);
+ });
+ res["url"] = store->getUri();
+ store->connect();
+ if (auto version = store->getVersion())
+ res["version"] = *version;
+ }
}
};
diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc
index ce3288dc1..fc3823406 100644
--- a/src/nix/prefetch.cc
+++ b/src/nix/prefetch.cc
@@ -28,17 +28,17 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url)
Value vMirrors;
// FIXME: use nixpkgs flake
state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors);
- state.forceAttrs(vMirrors, noPos);
+ state.forceAttrs(vMirrors, noPos, "while evaluating the set of all mirrors");
auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
if (mirrorList == vMirrors.attrs->end())
throw Error("unknown mirror name '%s'", mirrorName);
- state.forceList(*mirrorList->value, noPos);
+ state.forceList(*mirrorList->value, noPos, "while evaluating one mirror configuration");
if (mirrorList->value->listSize() < 1)
throw Error("mirror URL '%s' did not expand to anything", url);
- std::string mirror(state.forceString(*mirrorList->value->listElems()[0]));
+ std::string mirror(state.forceString(*mirrorList->value->listElems()[0], noPos, "while evaluating the first available mirror"));
return mirror + (hasSuffix(mirror, "/") ? "" : "/") + s.substr(p + 1);
}
@@ -196,29 +196,29 @@ static int main_nix_prefetch_url(int argc, char * * argv)
Value vRoot;
state->evalFile(path, vRoot);
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
- state->forceAttrs(v, noPos);
+ state->forceAttrs(v, noPos, "while evaluating the source attribute to prefetch");
/* Extract the URL. */
auto * attr = v.attrs->get(state->symbols.create("urls"));
if (!attr)
throw Error("attribute 'urls' missing");
- state->forceList(*attr->value, noPos);
+ state->forceList(*attr->value, noPos, "while evaluating the urls to prefetch");
if (attr->value->listSize() < 1)
throw Error("'urls' list is empty");
- url = state->forceString(*attr->value->listElems()[0]);
+ url = state->forceString(*attr->value->listElems()[0], noPos, "while evaluating the first url from the urls list");
/* Extract the hash mode. */
auto attr2 = v.attrs->get(state->symbols.create("outputHashMode"));
if (!attr2)
printInfo("warning: this does not look like a fetchurl call");
else
- unpack = state->forceString(*attr2->value) == "recursive";
+ unpack = state->forceString(*attr2->value, noPos, "while evaluating the outputHashMode of the source to prefetch") == "recursive";
/* Extract the name. */
if (!name) {
auto attr3 = v.attrs->get(state->symbols.create("name"));
if (!attr3)
- name = state->forceString(*attr3->value);
+ name = state->forceString(*attr3->value, noPos, "while evaluating the name of the source to prefetch");
}
}
diff --git a/src/nix/profile-list.md b/src/nix/profile-list.md
index bdab9a208..fa786162f 100644
--- a/src/nix/profile-list.md
+++ b/src/nix/profile-list.md
@@ -20,11 +20,11 @@ following fields:
* An integer that can be used to unambiguously identify the package in
invocations of `nix profile remove` and `nix profile upgrade`.
-* The original ("mutable") flake reference and output attribute path
+* The original ("unlocked") flake reference and output attribute path
used at installation time.
-* The immutable flake reference to which the mutable flake reference
- was resolved.
+* The locked flake reference to which the unlocked flake reference was
+ resolved.
* The store path(s) of the package.
diff --git a/src/nix/profile-upgrade.md b/src/nix/profile-upgrade.md
index e06e74abe..39cca428b 100644
--- a/src/nix/profile-upgrade.md
+++ b/src/nix/profile-upgrade.md
@@ -2,7 +2,7 @@ R""(
# Examples
-* Upgrade all packages that were installed using a mutable flake
+* Upgrade all packages that were installed using an unlocked flake
reference:
```console
@@ -32,9 +32,9 @@ the package was installed.
> **Warning**
>
-> This only works if you used a *mutable* flake reference at
+> This only works if you used an *unlocked* flake reference at
> installation time, e.g. `nixpkgs#hello`. It does not work if you
-> used an *immutable* flake reference
+> used a *locked* flake reference
> (e.g. `github:NixOS/nixpkgs/13d0c311e3ae923a00f734b43fd1d35b47d8943a#hello`),
> since in that case the "latest version" is always the same.
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 11910523d..208542a5c 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
@@ -22,7 +23,7 @@ struct ProfileElementSource
// FIXME: record original attrpath.
FlakeRef resolvedRef;
std::string attrPath;
- OutputsSpec outputs;
+ ExtendedOutputsSpec outputs;
bool operator < (const ProfileElementSource & other) const
{
@@ -32,17 +33,19 @@ struct ProfileElementSource
}
};
+const int defaultPriority = 5;
+
struct ProfileElement
{
StorePathSet storePaths;
std::optional<ProfileElementSource> source;
bool active = true;
- int priority = 5;
+ int priority = defaultPriority;
std::string describe() const
{
if (source)
- return fmt("%s#%s%s", source->originalRef, source->attrPath, printOutputsSpec(source->outputs));
+ return fmt("%s#%s%s", source->originalRef, source->attrPath, source->outputs.to_string());
StringSet names;
for (auto & path : storePaths)
names.insert(DrvName(path.name()).name);
@@ -124,7 +127,7 @@ struct ProfileManifest
parseFlakeRef(e[sOriginalUrl]),
parseFlakeRef(e[sUrl]),
e["attrPath"],
- e["outputs"].get<OutputsSpec>()
+ e["outputs"].get<ExtendedOutputsSpec>()
};
}
elements.emplace_back(std::move(element));
@@ -251,13 +254,20 @@ struct ProfileManifest
}
};
-static std::map<Installable *, BuiltPaths>
+static std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>>
builtPathsPerInstallable(
const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> & builtPaths)
{
- std::map<Installable *, BuiltPaths> res;
- for (auto & [installable, builtPath] : builtPaths)
- res[installable.get()].push_back(builtPath.path);
+ std::map<Installable *, std::pair<BuiltPaths, ExtraPathInfo>> res;
+ for (auto & [installable, builtPath] : builtPaths) {
+ auto & r = res[installable.get()];
+ /* Note that there could be conflicting info
+ (e.g. meta.priority fields) if the installable returned
+ multiple derivations. So pick one arbitrarily. FIXME:
+ print a warning? */
+ r.first.push_back(builtPath.path);
+ r.second = builtPath.info;
+ }
return res;
}
@@ -297,28 +307,25 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
for (auto & installable : installables) {
ProfileElement element;
+ auto & [res, info] = builtPaths[installable.get()];
-
- if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
- // FIXME: make build() return this?
- auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
+ if (info.originalRef && info.resolvedRef && info.attrPath && info.extendedOutputsSpec) {
element.source = ProfileElementSource {
- installable2->flakeRef,
- resolvedRef,
- attrPath,
- installable2->outputsSpec
+ .originalRef = *info.originalRef,
+ .resolvedRef = *info.resolvedRef,
+ .attrPath = *info.attrPath,
+ .outputs = *info.extendedOutputsSpec,
};
-
- if(drv.priority) {
- element.priority = *drv.priority;
- }
}
- if(priority) { // if --priority was specified we want to override the priority of the installable
- element.priority = *priority;
- };
+ // If --priority was specified we want to override the
+ // priority of the installable.
+ element.priority =
+ priority
+ ? *priority
+ : info.priority.value_or(defaultPriority);
- element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
+ element.updateStorePaths(getEvalStore(), store, res);
manifest.elements.push_back(std::move(element));
}
@@ -476,18 +483,22 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
Strings{},
lockFlags);
- auto [attrPath, resolvedRef, drv] = installable->toDerivation();
+ auto derivedPaths = installable->toDerivedPaths();
+ if (derivedPaths.empty()) continue;
+ auto & info = derivedPaths[0].info;
+
+ assert(info.resolvedRef && info.attrPath);
- if (element.source->resolvedRef == resolvedRef) continue;
+ if (element.source->resolvedRef == info.resolvedRef) continue;
printInfo("upgrading '%s' from flake '%s' to '%s'",
- element.source->attrPath, element.source->resolvedRef, resolvedRef);
+ element.source->attrPath, element.source->resolvedRef, *info.resolvedRef);
element.source = ProfileElementSource {
- installable->flakeRef,
- resolvedRef,
- attrPath,
- installable->outputsSpec
+ .originalRef = installable->flakeRef,
+ .resolvedRef = *info.resolvedRef,
+ .attrPath = *info.attrPath,
+ .outputs = installable->extendedOutputsSpec,
};
installables.push_back(installable);
@@ -515,7 +526,7 @@ 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()]);
+ element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()].first);
}
updateProfile(manifest.build(store));
@@ -543,8 +554,8 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
logger->cout("%d %s %s %s", i,
- element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-",
- element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-",
+ element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath + element.source->outputs.to_string() : "-",
+ element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath + element.source->outputs.to_string() : "-",
concatStringsSep(" ", store->printStorePathSet(element.storePaths)));
}
}
diff --git a/src/nix/profile.md b/src/nix/profile.md
index be3c5ba1a..273e02280 100644
--- a/src/nix/profile.md
+++ b/src/nix/profile.md
@@ -88,8 +88,7 @@ has the following fields:
the user at the time of installation (e.g. `nixpkgs`). This is also
the flake reference that will be used by `nix profile upgrade`.
-* `uri`: The immutable flake reference to which `originalUrl`
- resolved.
+* `uri`: The locked flake reference to which `originalUrl` resolved.
* `attrPath`: The flake output attribute that provided this
package. Note that this is not necessarily the attribute that the
diff --git a/src/nix/registry.cc b/src/nix/registry.cc
index c496f94f8..b5bdfba95 100644
--- a/src/nix/registry.cc
+++ b/src/nix/registry.cc
@@ -183,14 +183,12 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand
void run(nix::ref<nix::Store> store) override
{
- if (locked.empty()) {
- locked = url;
- }
+ if (locked.empty()) locked = url;
auto registry = getRegistry();
auto ref = parseFlakeRef(url);
- auto locked_ref = parseFlakeRef(locked);
+ auto lockedRef = parseFlakeRef(locked);
registry->remove(ref.input);
- auto [tree, resolved] = locked_ref.resolve(store).input.fetch(store);
+ auto [tree, resolved] = lockedRef.resolve(store).input.fetch(store);
fetchers::Attrs extraAttrs;
if (ref.subdir != "") extraAttrs["dir"] = ref.subdir;
registry->add(ref.input, resolved, extraAttrs);
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
new file mode 100644
index 000000000..679bdea77
--- /dev/null
+++ b/src/nix/repl.cc
@@ -0,0 +1,95 @@
+#include "eval.hh"
+#include "globals.hh"
+#include "command.hh"
+#include "repl.hh"
+
+namespace nix {
+
+struct CmdRepl : InstallablesCommand
+{
+ 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
+ {
+ return {""};
+ }
+
+ bool useDefaultInstallables() override
+ {
+ return file.has_value() or expr.has_value();
+ }
+
+ bool forceImpureByDefault() override
+ {
+ return true;
+ }
+
+ std::string description() override
+ {
+ return "start an interactive environment for evaluating Nix expressions";
+ }
+
+ std::string doc() override
+ {
+ return
+ #include "repl.md"
+ ;
+ }
+
+ void run(ref<Store> store) override
+ {
+ auto state = getEvalState();
+ auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
+ auto installables = load();
+ AbstractNixRepl::AnnotatedValues values;
+ for (auto & installable: installables){
+ auto what = installable->what();
+ if (file){
+ auto [val, pos] = installable->toValue(*state);
+ auto what = installable->what();
+ state->forceValue(*val, pos);
+ auto autoArgs = getAutoArgs(*state);
+ auto valPost = state->allocValue();
+ state->autoCallFunction(*autoArgs, *val, *valPost);
+ state->forceValue(*valPost, pos);
+ values.push_back( {valPost, what });
+ } else {
+ auto [val, pos] = installable->toValue(*state);
+ values.push_back( {val, what} );
+ }
+ }
+ return values;
+ };
+ auto repl = AbstractNixRepl::create(
+ searchPath,
+ openStore(),
+ state,
+ getValues
+ );
+ repl->autoArgs = getAutoArgs(*repl->state);
+ repl->initEnv();
+ repl->mainLoop();
+ }
+};
+
+static auto rCmdRepl = registerCommand<CmdRepl>("repl");
+
+}
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 45d2dfd0d..6fca68047 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -9,6 +9,7 @@
#include "fs-accessor.hh"
#include "progress-bar.hh"
#include "eval.hh"
+#include "build/personality.hh"
#if __linux__
#include <sys/mount.h>
@@ -24,7 +25,8 @@ namespace nix {
void runProgramInStore(ref<Store> store,
const std::string & program,
- const Strings & args)
+ const Strings & args,
+ std::optional<std::string_view> system)
{
stopProgressBar();
@@ -44,7 +46,7 @@ void runProgramInStore(ref<Store> store,
throw Error("store '%s' is not a local store so it does not support command execution", store->getUri());
if (store->storeDir != store2->getRealStoreDir()) {
- Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
+ Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), std::string(system.value_or("")), program };
for (auto & arg : args) helperArgs.push_back(arg);
execv(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data());
@@ -52,6 +54,9 @@ void runProgramInStore(ref<Store> store,
throw SysError("could not execute chroot helper");
}
+ if (system)
+ setPersonality(*system);
+
execvp(program.c_str(), stringsToCharPtrs(args).data());
throw SysError("unable to execute '%s'", program);
@@ -199,6 +204,7 @@ void chrootHelper(int argc, char * * argv)
int p = 1;
std::string storeDir = argv[p++];
std::string realStoreDir = argv[p++];
+ std::string system = argv[p++];
std::string cmd = argv[p++];
Strings args;
while (p < argc)
@@ -262,6 +268,9 @@ void chrootHelper(int argc, char * * argv)
writeFile("/proc/self/uid_map", fmt("%d %d %d", uid, uid, 1));
writeFile("/proc/self/gid_map", fmt("%d %d %d", gid, gid, 1));
+ if (system != "")
+ setPersonality(system);
+
execvp(cmd.c_str(), stringsToCharPtrs(args).data());
throw SysError("unable to exec '%s'", cmd);
diff --git a/src/nix/run.hh b/src/nix/run.hh
index 6180a87dd..fed360158 100644
--- a/src/nix/run.hh
+++ b/src/nix/run.hh
@@ -6,6 +6,7 @@ namespace nix {
void runProgramInStore(ref<Store> store,
const std::string & program,
- const Strings & args);
+ const Strings & args,
+ std::optional<std::string_view> system = std::nullopt);
}
diff --git a/src/nix/search.cc b/src/nix/search.cc
index d2a31607d..4fa1e7837 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -56,8 +56,8 @@ struct CmdSearch : InstallableCommand, MixJSON
Strings getDefaultFlakeAttrPaths() override
{
return {
- "packages." + settings.thisSystem.get() + ".",
- "legacyPackages." + settings.thisSystem.get() + "."
+ "packages." + settings.thisSystem.get(),
+ "legacyPackages." + settings.thisSystem.get()
};
}
diff --git a/src/nix/show-config.cc b/src/nix/show-config.cc
index 29944e748..3530584f9 100644
--- a/src/nix/show-config.cc
+++ b/src/nix/show-config.cc
@@ -9,15 +9,44 @@ using namespace nix;
struct CmdShowConfig : Command, MixJSON
{
+ std::optional<std::string> name;
+
+ CmdShowConfig() {
+ expectArgs({
+ .label = {"name"},
+ .optional = true,
+ .handler = {&name},
+ });
+ }
+
std::string description() override
{
- return "show the Nix configuration";
+ return "show the Nix configuration or the value of a specific setting";
}
Category category() override { return catUtility; }
void run() override
{
+ if (name) {
+ if (json) {
+ throw UsageError("'--json' is not supported when specifying a setting name");
+ }
+
+ std::map<std::string, Config::SettingInfo> settings;
+ globalConfig.getSettings(settings);
+ auto setting = settings.find(*name);
+
+ if (setting == settings.end()) {
+ throw Error("could not find setting '%1%'", *name);
+ } else {
+ const auto & value = setting->second.value;
+ logger->cout("%s", value);
+ }
+
+ return;
+ }
+
if (json) {
// FIXME: use appropriate JSON types (bool, ints, etc).
logger->cout("%s", globalConfig.toJSON().dump());
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index af2e676a4..d1a516cad 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -54,56 +54,8 @@ struct CmdShowDerivation : InstallablesCommand
for (auto & drvPath : drvPaths) {
if (!drvPath.isDerivation()) continue;
- json& drvObj = jsonRoot[store->printStorePath(drvPath)];
-
- auto drv = store->readDerivation(drvPath);
-
- {
- json& outputsObj = drvObj["outputs"];
- outputsObj = json::object();
- for (auto & [_outputName, output] : drv.outputs) {
- auto & outputName = _outputName; // work around clang bug
- auto& outputObj = outputsObj[outputName];
- outputObj = json::object();
- std::visit(overloaded {
- [&](const DerivationOutput::InputAddressed & doi) {
- outputObj["path"] = store->printStorePath(doi.path);
- },
- [&](const DerivationOutput::CAFixed & dof) {
- outputObj["path"] = store->printStorePath(dof.path(*store, drv.name, outputName));
- outputObj["hashAlgo"] = dof.hash.printMethodAlgo();
- outputObj["hash"] = dof.hash.hash.to_string(Base16, false);
- },
- [&](const DerivationOutput::CAFloating & dof) {
- outputObj["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType);
- },
- [&](const DerivationOutput::Deferred &) {},
- [&](const DerivationOutput::Impure & doi) {
- outputObj["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType);
- outputObj["impure"] = true;
- },
- }, output.raw());
- }
- }
-
- {
- auto& inputsList = drvObj["inputSrcs"];
- inputsList = json::array();
- for (auto & input : drv.inputSrcs)
- inputsList.emplace_back(store->printStorePath(input));
- }
-
- {
- auto& inputDrvsObj = drvObj["inputDrvs"];
- inputDrvsObj = json::object();
- for (auto & input : drv.inputDrvs)
- inputDrvsObj[store->printStorePath(input.first)] = input.second;
- }
-
- drvObj["system"] = drv.platform;
- drvObj["builder"] = drv.builder;
- drvObj["args"] = drv.args;
- drvObj["env"] = drv.env;
+ jsonRoot[store->printStorePath(drvPath)] =
+ store->readDerivation(drvPath).toJSON(*store);
}
std::cout << jsonRoot.dump(2) << std::endl;
}
diff --git a/src/nix/show-derivation.md b/src/nix/show-derivation.md
index aa863899c..2cd93aa62 100644
--- a/src/nix/show-derivation.md
+++ b/src/nix/show-derivation.md
@@ -2,9 +2,11 @@ R""(
# Examples
-* Show the store derivation that results from evaluating the Hello
+* Show the [store derivation] that results from evaluating the Hello
package:
+ [store derivation]: ../../glossary.md#gloss-store-derivation
+
```console
# nix show-derivation nixpkgs#hello
{
@@ -37,7 +39,7 @@ R""(
# Description
This command prints on standard output a JSON representation of the
-store derivations to which *installables* evaluate. Store derivations
+[store derivation]s to which *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/store-copy-log.cc b/src/nix/store-copy-log.cc
index 2e288f743..d5fab5f2f 100644
--- a/src/nix/store-copy-log.cc
+++ b/src/nix/store-copy-log.cc
@@ -33,13 +33,7 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
auto dstStore = getDstStore();
auto & dstLogStore = require<LogStore>(*dstStore);
- StorePathSet drvPaths;
-
- for (auto & i : installables)
- for (auto & drvPath : i->toDrvPaths(getEvalStore()))
- drvPaths.insert(drvPath);
-
- for (auto & drvPath : drvPaths) {
+ for (auto & drvPath : Installable::toDerivations(getEvalStore(), installables, true)) {
if (auto log = srcLogStore.getBuildLog(drvPath))
dstLogStore.addBuildLog(drvPath, *log);
else
diff --git a/src/nix/store-copy-log.md b/src/nix/store-copy-log.md
index 19ae57079..0937250f2 100644
--- a/src/nix/store-copy-log.md
+++ b/src/nix/store-copy-log.md
@@ -18,7 +18,9 @@ R""(
(The flag `--substituters ''` avoids querying
`https://cache.nixos.org` for the log.)
-* To copy the log for a specific store derivation via SSH:
+* To copy the log for a specific [store derivation] via SSH:
+
+ [store derivation]: ../../glossary.md#gloss-store-derivation
```console
# nix store copy-log --to ssh-ng://machine /nix/store/ilgm50plpmcgjhcp33z6n4qbnpqfhxym-glibc-2.33-59.drv
diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc
index 2d2453395..17796d6b8 100644
--- a/src/nix/upgrade-nix.cc
+++ b/src/nix/upgrade-nix.cc
@@ -144,7 +144,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
Bindings & bindings(*state->allocBindings(0));
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first;
- return store->parseStorePath(state->forceString(*v2));
+ return store->parseStorePath(state->forceString(*v2, noPos, "while evaluating the path tho latest nix version"));
}
};
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index efa2434dc..0b306cc11 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -81,14 +81,14 @@ struct CmdVerify : StorePathsCommand
ThreadPool pool;
- auto doPath = [&](const Path & storePath) {
+ auto doPath = [&](const StorePath & storePath) {
try {
checkInterrupt();
MaintainCount<std::atomic<size_t>> mcActive(active);
update();
- auto info = store->queryPathInfo(store->parseStorePath(storePath));
+ auto info = store->queryPathInfo(storePath);
// Note: info->path can be different from storePath
// for binary cache stores when using --all (since we
@@ -173,7 +173,7 @@ struct CmdVerify : StorePathsCommand
};
for (auto & storePath : storePaths)
- pool.enqueue(std::bind(doPath, store->printStorePath(storePath)));
+ pool.enqueue(std::bind(doPath, storePath));
pool.process();
diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index 723017497..a3a9dc698 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -27,7 +27,7 @@ static std::string filterPrintable(const std::string & s)
return res;
}
-struct CmdWhyDepends : SourceExprCommand
+struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
{
std::string _package, _dependency;
bool all = false;
@@ -95,23 +95,13 @@ struct CmdWhyDepends : SourceExprCommand
* to build.
*/
auto dependency = parseInstallable(store, _dependency);
- auto derivedDependency = dependency->toDerivedPath();
- auto optDependencyPath = std::visit(overloaded {
- [](const DerivedPath::Opaque & nodrv) -> std::optional<StorePath> {
- return { nodrv.path };
- },
- [&](const DerivedPath::Built & hasdrv) -> std::optional<StorePath> {
- if (hasdrv.outputs.size() != 1) {
- throw Error("argument '%s' should evaluate to one store path", dependency->what());
- }
- auto outputMap = store->queryPartialDerivationOutputMap(hasdrv.drvPath);
- auto maybePath = outputMap.find(*hasdrv.outputs.begin());
- if (maybePath == outputMap.end()) {
- throw Error("unexpected end of iterator");
- }
- return maybePath->second;
- },
- }, derivedDependency.raw());
+ auto optDependencyPath = [&]() -> std::optional<StorePath> {
+ try {
+ return {Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency)};
+ } catch (MissingRealisation &) {
+ return std::nullopt;
+ }
+ }();
StorePathSet closure;
store->computeFSClosure({packagePath}, closure, false, false);