aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
authorBen Radford <benradf@users.noreply.github.com>2023-07-11 09:38:34 +0100
committerBen Radford <benradf@users.noreply.github.com>2023-07-11 09:38:34 +0100
commit25b20b4ad23d05d9a1e9daf105d33b7b68e4435b (patch)
tree18a5255ce272403ccfd34ab0aaad7135aed50a02 /src/nix
parent754ced4a3f6d3d8865ba78a2e503776d7bd6c04f (diff)
parent4a880c3cc085841a1537040405bc142fefffd7ff (diff)
Merge remote-tracking branch 'origin/master' into best-effort-supplementary-groups
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/app.cc3
-rw-r--r--src/nix/build.md2
-rw-r--r--src/nix/copy.md2
-rw-r--r--src/nix/daemon.cc33
-rw-r--r--src/nix/develop.md2
-rw-r--r--src/nix/eval.md2
-rw-r--r--src/nix/flake-check.md2
-rw-r--r--src/nix/flake.cc133
-rw-r--r--src/nix/flake.md19
-rw-r--r--src/nix/main.cc41
-rw-r--r--src/nix/nar-ls.md4
-rw-r--r--src/nix/nix.md7
-rw-r--r--src/nix/path-info.md8
-rw-r--r--src/nix/profile-list.md46
-rw-r--r--src/nix/profile.cc98
-rw-r--r--src/nix/search.md4
-rw-r--r--src/nix/shell.md8
-rw-r--r--src/nix/store-ls.md4
-rw-r--r--src/nix/upgrade-nix.cc2
-rw-r--r--src/nix/upgrade-nix.md2
-rw-r--r--src/nix/verify.md2
21 files changed, 282 insertions, 142 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc
index fd4569bb4..e678b54f0 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -7,6 +7,7 @@
#include "names.hh"
#include "command.hh"
#include "derivations.hh"
+#include "downstream-placeholder.hh"
namespace nix {
@@ -23,7 +24,7 @@ StringPairs resolveRewrites(
if (auto drvDep = std::get_if<BuiltPathBuilt>(&dep.path))
for (auto & [ outputName, outputPath ] : drvDep->outputs)
res.emplace(
- downstreamPlaceholder(store, drvDep->drvPath, outputName),
+ DownstreamPlaceholder::unknownCaOutput(drvDep->drvPath, outputName).render(),
store.printStorePath(outputPath)
);
return res;
diff --git a/src/nix/build.md b/src/nix/build.md
index ee414dc86..0fbb39cc3 100644
--- a/src/nix/build.md
+++ b/src/nix/build.md
@@ -44,7 +44,7 @@ R""(
`release.nix`:
```console
- # nix build -f release.nix build.x86_64-linux
+ # nix build --file release.nix build.x86_64-linux
```
* Build a NixOS system configuration from a flake, and make a profile
diff --git a/src/nix/copy.md b/src/nix/copy.md
index 25e0ddadc..199006436 100644
--- a/src/nix/copy.md
+++ b/src/nix/copy.md
@@ -15,7 +15,7 @@ R""(
SSH:
```console
- # nix copy -s --to ssh://server /run/current-system
+ # nix copy --substitute-on-destination --to ssh://server /run/current-system
```
The `-s` flag causes the remote machine to try to substitute missing
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index c1a91c63d..1511f9e6e 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -4,6 +4,7 @@
#include "shared.hh"
#include "local-store.hh"
#include "remote-store.hh"
+#include "remote-store-connection.hh"
#include "util.hh"
#include "serialise.hh"
#include "archive.hh"
@@ -24,6 +25,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <sys/select.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
@@ -54,19 +56,16 @@ 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`.
+ A list of user names, separated by whitespace.
+ These users will have additional rights when connecting to the Nix daemon, such as the ability to specify additional [substituters](#conf-substituters), or to import unsigned [NARs](@docroot@/glossary.md#gloss-nar).
+
+ You can also specify groups by prefixing names with `@`.
+ For instance, `@wheel` means all users in the `wheel` group.
> **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.
+ > Adding a user to `trusted-users` is essentially equivalent to giving that user root access to the system.
+ > For example, the user can access or replace store path contents that are critical for system security.
)"};
/**
@@ -75,12 +74,16 @@ struct AuthorizationSettings : Config {
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 `*`.
+ A list user names, separated by whitespace.
+ These users are allowed to connect to the Nix daemon.
+
+ You can specify groups by prefixing names with `@`.
+ For instance, `@wheel` means all users in the `wheel` group.
+ Also, you can allow all users by specifying `*`.
- Note that trusted users are always allowed to connect.
+ > **Note**
+ >
+ > Trusted users (set in [`trusted-users`](#conf-trusted-users)) can always connect to the Nix daemon.
)"};
};
diff --git a/src/nix/develop.md b/src/nix/develop.md
index c49b39669..1b5a8aeba 100644
--- a/src/nix/develop.md
+++ b/src/nix/develop.md
@@ -69,7 +69,7 @@ R""(
* Run a series of script commands:
```console
- # nix develop --command bash -c "mkdir build && cmake .. && make"
+ # nix develop --command bash --command "mkdir build && cmake .. && make"
```
# Description
diff --git a/src/nix/eval.md b/src/nix/eval.md
index 3b510737a..48d5aa597 100644
--- a/src/nix/eval.md
+++ b/src/nix/eval.md
@@ -18,7 +18,7 @@ R""(
* Evaluate a Nix expression from a file:
```console
- # nix eval -f ./my-nixpkgs hello.name
+ # nix eval --file ./my-nixpkgs hello.name
```
* Get the current version of the `nixpkgs` flake:
diff --git a/src/nix/flake-check.md b/src/nix/flake-check.md
index 07031c909..c8307f8d8 100644
--- a/src/nix/flake-check.md
+++ b/src/nix/flake-check.md
@@ -68,6 +68,6 @@ The following flake output attributes must be
In addition, the `hydraJobs` output is evaluated in the same way as
Hydra's `hydra-eval-jobs` (i.e. as a arbitrarily deeply nested
attribute set of derivations). Similarly, the
-`legacyPackages`.*system* output is evaluated like `nix-env -qa`.
+`legacyPackages`.*system* output is evaluated like `nix-env --query --available `.
)""
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 3db655aeb..b5f5d0cac 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -179,6 +179,8 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
j["locked"] = fetchers::attrsToJSON(flake.lockedRef.toAttrs());
if (auto rev = flake.lockedRef.input.getRev())
j["revision"] = rev->to_string(Base16, false);
+ if (auto dirtyRev = fetchers::maybeGetStrAttr(flake.lockedRef.toAttrs(), "dirtyRev"))
+ j["dirtyRevision"] = *dirtyRev;
if (auto revCount = flake.lockedRef.input.getRevCount())
j["revCount"] = *revCount;
if (auto lastModified = flake.lockedRef.input.getLastModified())
@@ -204,6 +206,10 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
logger->cout(
ANSI_BOLD "Revision:" ANSI_NORMAL " %s",
rev->to_string(Base16, false));
+ if (auto dirtyRev = fetchers::maybeGetStrAttr(flake.lockedRef.toAttrs(), "dirtyRev"))
+ logger->cout(
+ ANSI_BOLD "Revision:" ANSI_NORMAL " %s",
+ *dirtyRev);
if (auto revCount = flake.lockedRef.input.getRevCount())
logger->cout(
ANSI_BOLD "Revisions:" ANSI_NORMAL " %s",
@@ -259,6 +265,7 @@ struct CmdFlakeInfo : CmdFlakeMetadata
struct CmdFlakeCheck : FlakeCommand
{
bool build = true;
+ bool checkAllSystems = false;
CmdFlakeCheck()
{
@@ -267,6 +274,11 @@ struct CmdFlakeCheck : FlakeCommand
.description = "Do not build checks.",
.handler = {&build, false}
});
+ addFlag({
+ .longName = "all-systems",
+ .description = "Check the outputs for all systems.",
+ .handler = {&checkAllSystems, true}
+ });
}
std::string description() override
@@ -292,6 +304,7 @@ struct CmdFlakeCheck : FlakeCommand
lockFlags.applyNixConfig = true;
auto flake = lockFlake();
+ auto localSystem = std::string(settings.thisSystem.get());
bool hasErrors = false;
auto reportError = [&](const Error & e) {
@@ -307,6 +320,8 @@ struct CmdFlakeCheck : FlakeCommand
}
};
+ std::set<std::string> omittedSystems;
+
// FIXME: rewrite to use EvalCache.
auto resolve = [&] (PosIdx p) {
@@ -327,6 +342,15 @@ struct CmdFlakeCheck : FlakeCommand
reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos)));
};
+ auto checkSystemType = [&](const std::string & system, const PosIdx pos) {
+ if (!checkAllSystems && system != localSystem) {
+ omittedSystems.insert(system);
+ return false;
+ } else {
+ return true;
+ }
+ };
+
auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional<StorePath> {
try {
auto drvInfo = getDerivation(*state, v, false);
@@ -362,8 +386,10 @@ struct CmdFlakeCheck : FlakeCommand
auto checkOverlay = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
- if (!v.isLambda()
- || v.lambda.fun->hasFormals()
+ if (!v.isLambda()) {
+ throw Error("overlay is not a function, but %s instead", showType(v));
+ }
+ if (v.lambda.fun->hasFormals()
|| !argHasName(v.lambda.fun->arg, "final"))
throw Error("overlay does not take an argument named 'final'");
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
@@ -509,16 +535,18 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, 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 = *drvPath,
- .outputs = OutputsSpec::All { },
- });
+ if (checkSystemType(attr_name, 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 = *drvPath,
+ .outputs = OutputsSpec::All { },
+ });
+ }
}
}
}
@@ -529,9 +557,11 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- checkApp(
- fmt("%s.%s", name, attr_name),
- *attr.value, attr.pos);
+ if (checkSystemType(attr_name, attr.pos)) {
+ checkApp(
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
+ };
}
}
@@ -540,11 +570,13 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, 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]),
- *attr2.value, attr2.pos);
+ if (checkSystemType(attr_name, 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]),
+ *attr2.value, attr2.pos);
+ };
}
}
@@ -553,11 +585,13 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, 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]),
- *attr2.value, attr2.pos);
+ if (checkSystemType(attr_name, 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]),
+ *attr2.value, attr2.pos);
+ };
}
}
@@ -566,9 +600,11 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- checkDerivation(
- fmt("%s.%s", name, attr_name),
- *attr.value, attr.pos);
+ if (checkSystemType(attr_name, attr.pos)) {
+ checkDerivation(
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
+ };
}
}
@@ -577,9 +613,11 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- checkApp(
- fmt("%s.%s", name, attr_name),
- *attr.value, attr.pos);
+ if (checkSystemType(attr_name, attr.pos) ) {
+ checkApp(
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
+ };
}
}
@@ -587,6 +625,7 @@ struct CmdFlakeCheck : FlakeCommand
state->forceAttrs(vOutput, pos, "");
for (auto & attr : *vOutput.attrs) {
checkSystemName(state->symbols[attr.name], attr.pos);
+ checkSystemType(state->symbols[attr.name], attr.pos);
// FIXME: do getDerivations?
}
}
@@ -636,9 +675,11 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, attr.pos);
- checkBundler(
- fmt("%s.%s", name, attr_name),
- *attr.value, attr.pos);
+ if (checkSystemType(attr_name, attr.pos)) {
+ checkBundler(
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
+ };
}
}
@@ -647,12 +688,14 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *vOutput.attrs) {
const auto & attr_name = state->symbols[attr.name];
checkSystemName(attr_name, 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]),
- *attr2.value, attr2.pos);
- }
+ if (checkSystemType(attr_name, 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]),
+ *attr2.value, attr2.pos);
+ }
+ };
}
}
@@ -685,7 +728,15 @@ struct CmdFlakeCheck : FlakeCommand
}
if (hasErrors)
throw Error("some errors were encountered during the evaluation");
- }
+
+ if (!omittedSystems.empty()) {
+ warn(
+ "The check omitted these incompatible systems: %s\n"
+ "Use '--all-systems' to check all.",
+ concatStringsSep(", ", omittedSystems)
+ );
+ };
+ };
};
static Strings defaultTemplateAttrPathsPrefixes{"templates."};
diff --git a/src/nix/flake.md b/src/nix/flake.md
index 456fd0ea1..92f477917 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -71,8 +71,6 @@ inputs.nixpkgs = {
Here are some examples of flake references in their URL-like representation:
-* `.`: The flake in the current directory.
-* `/home/alice/src/patchelf`: A flake in some other directory.
* `nixpkgs`: The `nixpkgs` entry in the flake registry.
* `nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293`: The `nixpkgs`
entry in the flake registry, with its Git revision overridden to a
@@ -93,6 +91,23 @@ Here are some examples of flake references in their URL-like representation:
* `https://github.com/NixOS/patchelf/archive/master.tar.gz`: A tarball
flake.
+## Path-like syntax
+
+Flakes corresponding to a local path can also be referred to by a direct path reference, either `/absolute/path/to/the/flake` or `./relative/path/to/the/flake` (note that the leading `./` is mandatory for relative paths to avoid any ambiguity).
+
+The semantic of such a path is as follows:
+
+* If the directory is part of a Git repository, then the input will be treated as a `git+file:` URL, otherwise it will be treated as a `path:` url;
+* If the directory doesn't contain a `flake.nix` file, then Nix will search for such a file upwards in the file system hierarchy until it finds any of:
+ 1. The Git repository root, or
+ 2. The filesystem root (/), or
+ 3. A folder on a different mount point.
+
+### Examples
+
+* `.`: The flake to which the current directory belongs to.
+* `/home/alice/src/patchelf`: A flake in some other directory.
+
## Flake reference attributes
The following generic flake reference attributes are supported:
diff --git a/src/nix/main.cc b/src/nix/main.cc
index ce0bed2a3..650c79d14 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -352,7 +352,7 @@ void mainWrapped(int argc, char * * argv)
return;
}
- if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
+ if (argc == 2 && std::string(argv[1]) == "__dump-language") {
experimentalFeatureSettings.experimentalFeatures = {
Xp::Flakes,
Xp::FetchClosure,
@@ -360,17 +360,34 @@ void mainWrapped(int argc, char * * argv)
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object();
- auto builtins = state.baseEnv.values[0]->attrs;
- for (auto & builtin : *builtins) {
- auto b = nlohmann::json::object();
- if (!builtin.value->isPrimOp()) continue;
- auto primOp = builtin.value->primOp;
- if (!primOp->doc) continue;
- b["arity"] = primOp->arity;
- b["args"] = primOp->args;
- b["doc"] = trim(stripIndentation(primOp->doc));
- res[state.symbols[builtin.name]] = std::move(b);
- }
+ res["builtins"] = ({
+ auto builtinsJson = nlohmann::json::object();
+ auto builtins = state.baseEnv.values[0]->attrs;
+ for (auto & builtin : *builtins) {
+ auto b = nlohmann::json::object();
+ if (!builtin.value->isPrimOp()) continue;
+ auto primOp = builtin.value->primOp;
+ if (!primOp->doc) continue;
+ b["arity"] = primOp->arity;
+ b["args"] = primOp->args;
+ b["doc"] = trim(stripIndentation(primOp->doc));
+ b["experimental-feature"] = primOp->experimentalFeature;
+ builtinsJson[state.symbols[builtin.name]] = std::move(b);
+ }
+ std::move(builtinsJson);
+ });
+ res["constants"] = ({
+ auto constantsJson = nlohmann::json::object();
+ for (auto & [name, info] : state.constantInfos) {
+ auto c = nlohmann::json::object();
+ if (!info.doc) continue;
+ c["doc"] = trim(stripIndentation(info.doc));
+ c["type"] = showType(info.type, false);
+ c["impure-only"] = info.impureOnly;
+ constantsJson[name] = std::move(c);
+ }
+ std::move(constantsJson);
+ });
logger->cout("%s", res);
return;
}
diff --git a/src/nix/nar-ls.md b/src/nix/nar-ls.md
index d373f9715..5a03c5d82 100644
--- a/src/nix/nar-ls.md
+++ b/src/nix/nar-ls.md
@@ -5,7 +5,7 @@ R""(
* To list a specific file in a NAR:
```console
- # nix nar ls -l ./hello.nar /bin/hello
+ # nix nar ls --long ./hello.nar /bin/hello
-r-xr-xr-x 38184 hello
```
@@ -13,7 +13,7 @@ R""(
format:
```console
- # nix nar ls --json -R ./hello.nar /bin
+ # nix nar ls --json --recursive ./hello.nar /bin
{"type":"directory","entries":{"hello":{"type":"regular","size":38184,"executable":true,"narOffset":400}}}
```
diff --git a/src/nix/nix.md b/src/nix/nix.md
index 1ef6c7fcd..e0f459d6b 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -63,7 +63,7 @@ The following types of installable are supported by most commands:
- [Nix file](#nix-file), optionally qualified by an attribute path
- [Nix expression](#nix-expression), optionally qualified by an attribute path
-For most commands, if no installable is specified, `.` as assumed.
+For most commands, if no installable is specified, `.` is assumed.
That is, Nix will operate on the default flake output attribute of the flake in the current directory.
### Flake output attribute
@@ -102,6 +102,7 @@ way:
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
@@ -197,7 +198,7 @@ operate are determined as follows:
of all outputs of the `glibc` package in the binary cache:
```console
- # nix path-info -S --eval-store auto --store https://cache.nixos.org 'nixpkgs#glibc^*'
+ # nix path-info --closure-size --eval-store auto --store https://cache.nixos.org 'nixpkgs#glibc^*'
/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123 33208200
/nix/store/851dp95qqiisjifi639r0zzg5l465ny4-glibc-2.33-123-bin 36142896
/nix/store/kdgs3q6r7xdff1p7a9hnjr43xw2404z7-glibc-2.33-123-debug 155787312
@@ -208,7 +209,7 @@ operate are determined as follows:
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^*'
+ # nix path-info --closure-size '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*'
```
* If you didn't specify the desired outputs, but the derivation has an
diff --git a/src/nix/path-info.md b/src/nix/path-info.md
index 6ad23a02e..2dda866d0 100644
--- a/src/nix/path-info.md
+++ b/src/nix/path-info.md
@@ -13,7 +13,7 @@ R""(
closure, sorted by size:
```console
- # nix path-info -rS /run/current-system | sort -nk2
+ # nix path-info --recursive --closure-size /run/current-system | sort -nk2
/nix/store/hl5xwp9kdrd1zkm0idm3kkby9q66z404-empty 96
/nix/store/27324qvqhnxj3rncazmxc4mwy79kz8ha-nameservers 112
@@ -25,7 +25,7 @@ R""(
readable sizes:
```console
- # nix path-info -rsSh nixpkgs#rustc
+ # nix path-info --recursive --size --closure-size --human-readable nixpkgs#rustc
/nix/store/01rrgsg5zk3cds0xgdsq40zpk6g51dz9-ncurses-6.2-dev 386.7K 69.1M
/nix/store/0q783wnvixpqz6dxjp16nw296avgczam-libpfm-4.11.0 5.9M 37.4M
@@ -34,7 +34,7 @@ R""(
* Check the existence of a path in a binary cache:
```console
- # nix path-info -r /nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1 --store https://cache.nixos.org/
+ # nix path-info --recursive /nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1 --store https://cache.nixos.org/
path '/nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1' is not valid
```
@@ -57,7 +57,7 @@ R""(
size:
```console
- # nix path-info --json --all -S \
+ # nix path-info --json --all --closure-size \
| jq 'map(select(.closureSize > 1e9)) | sort_by(.closureSize) | map([.path, .closureSize])'
[
…,
diff --git a/src/nix/profile-list.md b/src/nix/profile-list.md
index fa786162f..5d7fcc0ec 100644
--- a/src/nix/profile-list.md
+++ b/src/nix/profile-list.md
@@ -6,26 +6,48 @@ R""(
```console
# nix profile list
- 0 flake:nixpkgs#legacyPackages.x86_64-linux.spotify github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.spotify /nix/store/akpdsid105phbbvknjsdh7hl4v3fhjkr-spotify-1.1.46.916.g416cacf1
- 1 flake:nixpkgs#legacyPackages.x86_64-linux.zoom-us github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.zoom-us /nix/store/89pmjmbih5qpi7accgacd17ybpgp4xfm-zoom-us-5.4.53350.1027
- 2 flake:blender-bin#packages.x86_64-linux.default github:edolstra/nix-warez/d09d7eea893dcb162e89bc67f6dc1ced14abfc27?dir=blender#packages.x86_64-linux.default /nix/store/zfgralhqjnam662kqsgq6isjw8lhrflz-blender-bin-2.91.0
+ Index: 0
+ Flake attribute: legacyPackages.x86_64-linux.gdb
+ Original flake URL: flake:nixpkgs
+ Locked flake URL: github:NixOS/nixpkgs/7b38b03d76ab71bdc8dc325e3f6338d984cc35ca
+ Store paths: /nix/store/indzcw5wvlhx6vwk7k4iq29q15chvr3d-gdb-11.1
+
+ Index: 1
+ Flake attribute: packages.x86_64-linux.default
+ Original flake URL: flake:blender-bin
+ Locked flake URL: github:edolstra/nix-warez/91f2ffee657bf834e4475865ae336e2379282d34?dir=blender
+ Store paths: /nix/store/i798sxl3j40wpdi1rgf391id1b5klw7g-blender-bin-3.1.2
```
+ Note that you can unambiguously rebuild a package from a profile
+ through its locked flake URL and flake attribute, e.g.
+
+ ```console
+ # nix build github:edolstra/nix-warez/91f2ffee657bf834e4475865ae336e2379282d34?dir=blender#packages.x86_64-linux.default
+ ```
+
+ will build the package with index 1 shown above.
+
# Description
This command shows what packages are currently installed in a
-profile. The output consists of one line per package, with the
-following fields:
+profile. For each installed package, it shows the following
+information:
+
+* `Index`: An integer that can be used to unambiguously identify the
+ package in invocations of `nix profile remove` and `nix profile
+ upgrade`.
-* An integer that can be used to unambiguously identify the package in
- invocations of `nix profile remove` and `nix profile upgrade`.
+* `Flake attribute`: The flake output attribute path that provides the
+ package (e.g. `packages.x86_64-linux.hello`).
-* The original ("unlocked") flake reference and output attribute path
- used at installation time.
+* `Original flake URL`: The original ("unlocked") flake reference
+ specified by the user when the package was first installed via `nix
+ profile install`.
-* The locked flake reference to which the unlocked flake reference was
- resolved.
+* `Locked flake URL`: The locked flake reference to which the original
+ flake reference was resolved.
-* The store path(s) of the package.
+* `Store paths`: The store path(s) of the package.
)""
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index fd63b3519..b833b5192 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -21,7 +21,7 @@ struct ProfileElementSource
{
FlakeRef originalRef;
// FIXME: record original attrpath.
- FlakeRef resolvedRef;
+ FlakeRef lockedRef;
std::string attrPath;
ExtendedOutputsSpec outputs;
@@ -31,6 +31,11 @@ struct ProfileElementSource
std::tuple(originalRef.to_string(), attrPath, outputs) <
std::tuple(other.originalRef.to_string(), other.attrPath, other.outputs);
}
+
+ std::string to_string() const
+ {
+ return fmt("%s#%s%s", originalRef, attrPath, outputs.to_string());
+ }
};
const int defaultPriority = 5;
@@ -42,16 +47,30 @@ struct ProfileElement
bool active = true;
int priority = defaultPriority;
- std::string describe() const
+ std::string identifier() const
{
if (source)
- return fmt("%s#%s%s", source->originalRef, source->attrPath, source->outputs.to_string());
+ return source->to_string();
StringSet names;
for (auto & path : storePaths)
names.insert(DrvName(path.name()).name);
return concatStringsSep(", ", names);
}
+ /**
+ * Return a string representing an installable corresponding to the current
+ * element, either a flakeref or a plain store path
+ */
+ std::set<std::string> toInstallables(Store & store)
+ {
+ if (source)
+ return {source->to_string()};
+ StringSet rawPaths;
+ for (auto & path : storePaths)
+ rawPaths.insert(store.printStorePath(path));
+ return rawPaths;
+ }
+
std::string versions() const
{
StringSet versions;
@@ -62,7 +81,7 @@ struct ProfileElement
bool operator < (const ProfileElement & other) const
{
- return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
+ return std::tuple(identifier(), storePaths) < std::tuple(other.identifier(), other.storePaths);
}
void updateStorePaths(
@@ -149,7 +168,7 @@ struct ProfileManifest
}
}
- std::string toJSON(Store & store) const
+ nlohmann::json toJSON(Store & store) const
{
auto array = nlohmann::json::array();
for (auto & element : elements) {
@@ -162,7 +181,7 @@ struct ProfileManifest
obj["priority"] = element.priority;
if (element.source) {
obj["originalUrl"] = element.source->originalRef.to_string();
- obj["url"] = element.source->resolvedRef.to_string();
+ obj["url"] = element.source->lockedRef.to_string();
obj["attrPath"] = element.source->attrPath;
obj["outputs"] = element.source->outputs;
}
@@ -171,7 +190,7 @@ struct ProfileManifest
nlohmann::json json;
json["version"] = 2;
json["elements"] = array;
- return json.dump();
+ return json;
}
StorePath build(ref<Store> store)
@@ -191,7 +210,7 @@ struct ProfileManifest
buildProfile(tempDir, std::move(pkgs));
- writeFile(tempDir + "/manifest.json", toJSON(*store));
+ writeFile(tempDir + "/manifest.json", toJSON(*store).dump());
/* Add the symlink tree to the store. */
StringSink sink;
@@ -237,13 +256,13 @@ struct ProfileManifest
bool changes = false;
while (i != prevElems.end() || j != curElems.end()) {
- if (j != curElems.end() && (i == prevElems.end() || i->describe() > j->describe())) {
- logger->cout("%s%s: ∅ -> %s", indent, j->describe(), j->versions());
+ if (j != curElems.end() && (i == prevElems.end() || i->identifier() > j->identifier())) {
+ logger->cout("%s%s: ∅ -> %s", indent, j->identifier(), j->versions());
changes = true;
++j;
}
- else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) {
- logger->cout("%s%s: %s -> ∅", indent, i->describe(), i->versions());
+ else if (i != prevElems.end() && (j == curElems.end() || i->identifier() < j->identifier())) {
+ logger->cout("%s%s: %s -> ∅", indent, i->identifier(), i->versions());
changes = true;
++i;
}
@@ -251,7 +270,7 @@ struct ProfileManifest
auto v1 = i->versions();
auto v2 = j->versions();
if (v1 != v2) {
- logger->cout("%s%s: %s -> %s", indent, i->describe(), v1, v2);
+ logger->cout("%s%s: %s -> %s", indent, i->identifier(), v1, v2);
changes = true;
}
++i;
@@ -330,7 +349,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
if (auto * info2 = dynamic_cast<ExtraPathInfoFlake *>(&*info)) {
element.source = ProfileElementSource {
.originalRef = info2->flake.originalRef,
- .resolvedRef = info2->flake.resolvedRef,
+ .lockedRef = info2->flake.lockedRef,
.attrPath = info2->value.attrPath,
.outputs = info2->value.extendedOutputsSpec,
};
@@ -363,10 +382,10 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
auto profileElement = *it;
for (auto & storePath : profileElement.storePaths) {
if (conflictError.fileA.starts_with(store->printStorePath(storePath))) {
- return std::pair(conflictError.fileA, profileElement.source->originalRef);
+ return std::pair(conflictError.fileA, profileElement.toInstallables(*store));
}
if (conflictError.fileB.starts_with(store->printStorePath(storePath))) {
- return std::pair(conflictError.fileB, profileElement.source->originalRef);
+ return std::pair(conflictError.fileB, profileElement.toInstallables(*store));
}
}
}
@@ -375,9 +394,9 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
// 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());
+ auto [originalConflictingFilePath, originalConflictingRefs] = 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());
+ auto [newConflictingFilePath, newConflictingRefs] = findRefByFilePath(manifest.elements.rbegin(), manifest.elements.rend());
throw Error(
"An existing package already provides the following file:\n"
@@ -403,8 +422,8 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
" nix profile install %4% --priority %7%\n",
originalConflictingFilePath,
newConflictingFilePath,
- originalConflictingRef.to_string(),
- newConflictingRef.to_string(),
+ concatStringsSep(" ", originalConflictingRefs),
+ concatStringsSep(" ", newConflictingRefs),
conflictError.priority,
conflictError.priority - 1,
conflictError.priority + 1
@@ -491,7 +510,7 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem
if (!matches(*store, element, i, matchers)) {
newManifest.elements.push_back(std::move(element));
} else {
- notice("removing '%s'", element.describe());
+ notice("removing '%s'", element.identifier());
}
}
@@ -569,14 +588,14 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
assert(infop);
auto & info = *infop;
- if (element.source->resolvedRef == info.flake.resolvedRef) continue;
+ if (element.source->lockedRef == info.flake.lockedRef) continue;
printInfo("upgrading '%s' from flake '%s' to '%s'",
- element.source->attrPath, element.source->resolvedRef, info.flake.resolvedRef);
+ element.source->attrPath, element.source->lockedRef, info.flake.lockedRef);
element.source = ProfileElementSource {
.originalRef = installable->flakeRef,
- .resolvedRef = info.flake.resolvedRef,
+ .lockedRef = info.flake.lockedRef,
.attrPath = info.value.attrPath,
.outputs = installable->extendedOutputsSpec,
};
@@ -616,7 +635,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
}
};
-struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultProfile
+struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultProfile, MixJSON
{
std::string description() override
{
@@ -634,12 +653,22 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
{
ProfileManifest manifest(*getEvalState(), *profile);
- 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 + 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)));
+ if (json) {
+ std::cout << manifest.toJSON(*store).dump() << "\n";
+ } else {
+ for (size_t i = 0; i < manifest.elements.size(); ++i) {
+ auto & element(manifest.elements[i]);
+ if (i) logger->cout("");
+ logger->cout("Index: " ANSI_BOLD "%s" ANSI_NORMAL "%s",
+ i,
+ element.active ? "" : " " ANSI_RED "(inactive)" ANSI_NORMAL);
+ if (element.source) {
+ logger->cout("Flake attribute: %s%s", element.source->attrPath, element.source->outputs.to_string());
+ logger->cout("Original flake URL: %s", element.source->originalRef.to_string());
+ logger->cout("Locked flake URL: %s", element.source->lockedRef.to_string());
+ }
+ logger->cout("Store paths: %s", concatStringsSep(" ", store->printStorePathSet(element.storePaths)));
+ }
}
}
};
@@ -787,9 +816,10 @@ struct CmdProfileWipeHistory : virtual StoreCommand, MixDefaultProfile, MixDryRu
void run(ref<Store> store) override
{
- if (minAge)
- deleteGenerationsOlderThan(*profile, *minAge, dryRun);
- else
+ if (minAge) {
+ auto t = parseOlderThanTimeSpec(*minAge);
+ deleteGenerationsOlderThan(*profile, t, dryRun);
+ } else
deleteOldGenerations(*profile, dryRun);
}
};
diff --git a/src/nix/search.md b/src/nix/search.md
index 4caa90654..0c5d22549 100644
--- a/src/nix/search.md
+++ b/src/nix/search.md
@@ -52,12 +52,12 @@ R""(
* Search for packages containing `neovim` but hide ones containing either `gui` or `python`:
```console
- # nix search nixpkgs neovim -e 'python|gui'
+ # nix search nixpkgs neovim --exclude 'python|gui'
```
or
```console
- # nix search nixpkgs neovim -e 'python' -e 'gui'
+ # nix search nixpkgs neovim --exclude 'python' --exclude 'gui'
```
# Description
diff --git a/src/nix/shell.md b/src/nix/shell.md
index 13a389103..1668104b1 100644
--- a/src/nix/shell.md
+++ b/src/nix/shell.md
@@ -19,26 +19,26 @@ R""(
* Run GNU Hello:
```console
- # nix shell nixpkgs#hello -c hello --greeting 'Hi everybody!'
+ # nix shell nixpkgs#hello --command hello --greeting 'Hi everybody!'
Hi everybody!
```
* Run multiple commands in a shell environment:
```console
- # nix shell nixpkgs#gnumake -c sh -c "cd src && make"
+ # nix shell nixpkgs#gnumake --command sh --command "cd src && make"
```
* Run GNU Hello in a chroot store:
```console
- # nix shell --store ~/my-nix nixpkgs#hello -c hello
+ # nix shell --store ~/my-nix nixpkgs#hello --command hello
```
* Start a shell providing GNU Hello in a chroot store:
```console
- # nix shell --store ~/my-nix nixpkgs#hello nixpkgs#bashInteractive -c bash
+ # nix shell --store ~/my-nix nixpkgs#hello nixpkgs#bashInteractive --command bash
```
Note that it's necessary to specify `bash` explicitly because your
diff --git a/src/nix/store-ls.md b/src/nix/store-ls.md
index 836efce42..14c4627c9 100644
--- a/src/nix/store-ls.md
+++ b/src/nix/store-ls.md
@@ -5,7 +5,7 @@ R""(
* To list the contents of a store path in a binary cache:
```console
- # nix store ls --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
+ # nix store ls --store https://cache.nixos.org/ --long --recursive /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
dr-xr-xr-x 0 ./bin
-r-xr-xr-x 38184 ./bin/hello
dr-xr-xr-x 0 ./share
@@ -15,7 +15,7 @@ R""(
* To show information about a specific file in a binary cache:
```console
- # nix store ls --store https://cache.nixos.org/ -l /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10/bin/hello
+ # nix store ls --store https://cache.nixos.org/ --long /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10/bin/hello
-r-xr-xr-x 38184 hello
```
diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc
index 3997c98bf..d05c23fb7 100644
--- a/src/nix/upgrade-nix.cc
+++ b/src/nix/upgrade-nix.cc
@@ -146,7 +146,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
auto req = FileTransferRequest(storePathsUrl);
auto res = getFileTransfer()->download(req);
- auto state = std::make_unique<EvalState>(Strings(), store);
+ auto state = std::make_unique<EvalState>(SearchPath{}, store);
auto v = state->allocValue();
state->eval(state->parseExprFromString(res.data, state->rootPath(CanonPath("/no-such-path"))), *v);
Bindings & bindings(*state->allocBindings(0));
diff --git a/src/nix/upgrade-nix.md b/src/nix/upgrade-nix.md
index 08757aebd..cce88c397 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 ~alice/.local/state/nix/profiles/profile
+ # nix upgrade-nix --profile ~alice/.local/state/nix/profiles/profile
```
# Description
diff --git a/src/nix/verify.md b/src/nix/verify.md
index cc1122c02..e1d55eab4 100644
--- a/src/nix/verify.md
+++ b/src/nix/verify.md
@@ -12,7 +12,7 @@ R""(
signatures:
```console
- # nix store verify -r -n2 --no-contents $(type -p firefox)
+ # nix store verify --recursive --sigs-needed 2 --no-contents $(type -p firefox)
```
* Verify a store path in the binary cache `https://cache.nixos.org/`: