diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index b04723b95..37966bab2 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -21,7 +21,7 @@ jobs:
fetch-depth: 0
- name: Create backport PRs
# should be kept in sync with `version`
- uses: zeebe-io/backport-action@v1.2.0
+ uses: zeebe-io/backport-action@v1.3.0
with:
# Config README: https://github.com/zeebe-io/backport-action#backport-action
github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c06c77043..0f1f6d43f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,10 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - uses: cachix/install-nix-action@v20
+ - uses: cachix/install-nix-action@v21
+ with:
+ # The sandbox would otherwise be disabled by default on Darwin
+ extra_nix_config: "sandbox = true"
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v12
if: needs.check_secrets.outputs.cachix == 'true'
@@ -58,7 +61,7 @@ jobs:
with:
fetch-depth: 0
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- - uses: cachix/install-nix-action@v20
+ - uses: cachix/install-nix-action@v21
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
- uses: cachix/cachix-action@v12
@@ -79,7 +82,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- - uses: cachix/install-nix-action@v20
+ - uses: cachix/install-nix-action@v21
with:
install_url: '${{needs.installer.outputs.installerURL}}'
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
@@ -106,7 +109,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - uses: cachix/install-nix-action@v20
+ - uses: cachix/install-nix-action@v21
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
diff --git a/.gitignore b/.gitignore
index 8ceff4ef2..7ae1071d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,8 @@ perl/Makefile.config
/src/nix/nix
+/src/nix/doc
+
# /src/nix-env/
/src/nix-env/nix-env
@@ -85,6 +87,7 @@ perl/Makefile.config
/tests/shell.drv
/tests/config.nix
/tests/ca/config.nix
+/tests/dyn-drv/config.nix
/tests/repl-result-out
# /tests/lang/
diff --git a/.version b/.version
index 752490696..d76bd2ba3 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-2.16.0
+2.17.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1b0ecaf36..57a949906 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -30,6 +30,7 @@ Check out the [security policy](https://github.com/NixOS/nix/security/policy).
You can use [labels](https://github.com/NixOS/nix/labels) to filter for relevant topics.
2. Search for related issues that cover what you're going to work on. It could help to mention there that you will work on the issue.
+ Pull requests addressing issues labeled ["idea approved"](https://github.com/NixOS/nix/labels/idea%20approved) are especially welcomed by maintainers and will receive prioritised review.
3. Check the [Nix reference manual](https://nixos.org/manual/nix/unstable/contributing/hacking.html) for information on building Nix and running its tests.
diff --git a/doc/manual/generate-builtins.nix b/doc/manual/generate-builtins.nix
index 115bb3f94..71f96153f 100644
--- a/doc/manual/generate-builtins.nix
+++ b/doc/manual/generate-builtins.nix
@@ -1,8 +1,12 @@
-builtinsDump:
+let
+ inherit (builtins) concatStringsSep attrNames;
+in
+
+builtinsInfo:
let
showBuiltin = name:
let
- inherit (builtinsDump.${name}) doc args;
+ inherit (builtinsInfo.${name}) doc args;
in
''
@@ -14,7 +18,7 @@ let
'';
- listArgs = args: builtins.concatStringsSep " " (map (s: "${s}") args);
+ listArgs = args: concatStringsSep " " (map (s: "${s}") args);
in
-with builtins; concatStringsSep "\n" (map showBuiltin (attrNames builtinsDump))
+concatStringsSep "\n" (map showBuiltin (attrNames builtinsInfo))
diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix
index d04eecf55..fb34898f3 100644
--- a/doc/manual/generate-manpage.nix
+++ b/doc/manual/generate-manpage.nix
@@ -1,10 +1,16 @@
-cliDumpStr:
+let
+ inherit (builtins)
+ attrNames attrValues fromJSON listToAttrs mapAttrs
+ concatStringsSep concatMap length lessThan replaceStrings sort;
+ inherit (import ./utils.nix) concatStrings optionalString filterAttrs trim squash unique showSettings;
+in
-with builtins;
-with import ./utils.nix;
+commandDump:
let
+ commandInfo = fromJSON commandDump;
+
showCommand = { command, details, filename, toplevel }:
let
@@ -96,7 +102,7 @@ let
${option.description}
'';
- categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues allOptions)));
+ categories = sort lessThan (unique (map (cmd: cmd.category) (attrValues allOptions)));
in concatStrings (map showCategory categories);
in squash result;
@@ -117,13 +123,11 @@ let
};
in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {});
- cliDump = builtins.fromJSON cliDumpStr;
-
manpages = processCommand {
command = "nix";
- details = cliDump.args;
+ details = commandInfo.args;
filename = "nix";
- toplevel = cliDump.args;
+ toplevel = commandInfo.args;
};
tableOfContents = let
@@ -143,6 +147,6 @@ let
${showSettings { useAnchors = false; } settings}
'';
- in concatStrings (attrValues (mapAttrs showStore cliDump.stores));
+ in concatStrings (attrValues (mapAttrs showStore commandInfo.stores));
in (listToAttrs manpages) // { "SUMMARY.md" = tableOfContents; }
diff --git a/doc/manual/local.mk b/doc/manual/local.mk
index 63e7e61e4..b4b7283ef 100644
--- a/doc/manual/local.mk
+++ b/doc/manual/local.mk
@@ -11,6 +11,7 @@ man-pages := $(foreach n, \
nix-prefetch-url.1 nix-channel.1 \
nix-hash.1 nix-copy-closure.1 \
nix.conf.5 nix-daemon.8 \
+ nix-profiles.5 \
, $(d)/$(n))
# man pages for subcommands
@@ -85,6 +86,12 @@ $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md
$(trace-gen) lowdown -sT man --nroff-nolinks -M section=5 $^.tmp -o $@
@rm $^.tmp
+$(d)/nix-profiles.5: $(d)/src/command-ref/files/profiles.md
+ @printf "Title: %s\n\n" "$$(basename $@ .5)" > $^.tmp
+ @cat $^ >> $^.tmp
+ $(trace-gen) lowdown -sT man --nroff-nolinks -M section=5 $^.tmp -o $@
+ @rm $^.tmp
+
$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md
@cp $< $@
@$(call process-includes,$@,$@)
diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js
index 69f75d3a0..5cd6fdea2 100644
--- a/doc/manual/redirects.js
+++ b/doc/manual/redirects.js
@@ -338,6 +338,9 @@ const redirects = {
"strings": "#string",
"lists": "#list",
"attribute-sets": "#attribute-set"
+ },
+ "installation/installing-binary.html": {
+ "uninstalling": "uninstall.html"
}
};
diff --git a/doc/manual/src/SUMMARY.md.in b/doc/manual/src/SUMMARY.md.in
index f783d5908..69c721b57 100644
--- a/doc/manual/src/SUMMARY.md.in
+++ b/doc/manual/src/SUMMARY.md.in
@@ -15,6 +15,7 @@
- [Multi-User Mode](installation/multi-user.md)
- [Environment Variables](installation/env-variables.md)
- [Upgrading Nix](installation/upgrading.md)
+ - [Uninstalling Nix](installation/uninstall.md)
- [Package Management](package-management/package-management.md)
- [Basic Package Management](package-management/basic-package-mgmt.md)
- [Profiles](package-management/profiles.md)
@@ -91,6 +92,11 @@
{{#include ./command-ref/new-cli/SUMMARY.md}}
- [Files](command-ref/files.md)
- [nix.conf](command-ref/conf-file.md)
+ - [Profiles](command-ref/files/profiles.md)
+ - [manifest.nix](command-ref/files/manifest.nix.md)
+ - [manifest.json](command-ref/files/manifest.json.md)
+ - [Channels](command-ref/files/channels.md)
+ - [Default Nix expression](command-ref/files/default-nix-expression.md)
- [Architecture](architecture/architecture.md)
- [Glossary](glossary.md)
- [Contributing](contributing/contributing.md)
@@ -99,6 +105,7 @@
- [CLI guideline](contributing/cli-guideline.md)
- [Release Notes](release-notes/release-notes.md)
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
+ - [Release 2.16 (2023-05-31)](release-notes/rl-2.16.md)
- [Release 2.15 (2023-04-11)](release-notes/rl-2.15.md)
- [Release 2.14 (2023-02-28)](release-notes/rl-2.14.md)
- [Release 2.13 (2023-01-17)](release-notes/rl-2.13.md)
diff --git a/doc/manual/src/advanced-topics/diff-hook.md b/doc/manual/src/advanced-topics/diff-hook.md
index 4a742c160..207aad3b8 100644
--- a/doc/manual/src/advanced-topics/diff-hook.md
+++ b/doc/manual/src/advanced-topics/diff-hook.md
@@ -48,13 +48,13 @@ If the build passes and is deterministic, Nix will exit with a status
code of 0:
```console
-$ nix-build ./deterministic.nix -A stable
+$ nix-build ./deterministic.nix --attr stable
this derivation will be built:
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
-$ nix-build ./deterministic.nix -A stable --check
+$ nix-build ./deterministic.nix --attr stable --check
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
```
@@ -63,13 +63,13 @@ If the build is not deterministic, Nix will exit with a status code of
1:
```console
-$ nix-build ./deterministic.nix -A unstable
+$ nix-build ./deterministic.nix --attr unstable
this derivation will be built:
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
-$ nix-build ./deterministic.nix -A unstable --check
+$ nix-build ./deterministic.nix --attr unstable --check
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
@@ -89,7 +89,7 @@ Using `--check` with `--keep-failed` will cause Nix to keep the second
build's output in a special, `.check` path:
```console
-$ nix-build ./deterministic.nix -A unstable --check --keep-failed
+$ nix-build ./deterministic.nix --attr unstable --check --keep-failed
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
diff --git a/doc/manual/src/advanced-topics/distributed-builds.md b/doc/manual/src/advanced-topics/distributed-builds.md
index fefd10100..73a113d35 100644
--- a/doc/manual/src/advanced-topics/distributed-builds.md
+++ b/doc/manual/src/advanced-topics/distributed-builds.md
@@ -38,11 +38,9 @@ contains Nix.
> **Warning**
>
-> If you are building via the Nix daemon, it is the Nix daemon user
-> account (that is, `root`) that should have SSH access to the remote
-> machine. If you can’t or don’t want to configure `root` to be able to
-> access to remote machine, you can use a private Nix store instead by
-> passing e.g. `--store ~/my-nix`.
+> If you are building via the Nix daemon, it is the Nix daemon user account (that is, `root`) that should have SSH access to a user (not necessarily `root`) on the remote machine.
+>
+> If you can’t or don’t want to configure `root` to be able to access the remote machine, you can use a private Nix store instead by passing e.g. `--store ~/my-nix` when running a Nix command from the local machine.
The list of remote machines can be specified on the command line or in
the Nix configuration file. The former is convenient for testing. For
diff --git a/doc/manual/src/advanced-topics/post-build-hook.md b/doc/manual/src/advanced-topics/post-build-hook.md
index 1479cc3a4..a251dec48 100644
--- a/doc/manual/src/advanced-topics/post-build-hook.md
+++ b/doc/manual/src/advanced-topics/post-build-hook.md
@@ -90,7 +90,7 @@ Then, restart the `nix-daemon`.
Build any derivation, for example:
```console
-$ nix-build -E '(import {}).writeText "example" (builtins.toString builtins.currentTime)'
+$ nix-build --expr '(import {}).writeText "example" (builtins.toString builtins.currentTime)'
this derivation will be built:
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
diff --git a/doc/manual/src/command-ref/env-common.md b/doc/manual/src/command-ref/env-common.md
index bf00be84f..b4a9bb2a9 100644
--- a/doc/manual/src/command-ref/env-common.md
+++ b/doc/manual/src/command-ref/env-common.md
@@ -71,9 +71,12 @@ Most Nix commands interpret the following environment variables:
Settings are separated by the newline character.
- [`NIX_USER_CONF_FILES`](#env-NIX_USER_CONF_FILES)\
- Overrides the location of the user Nix configuration files to load
- from (defaults to the XDG spec locations). The variable is treated
- as a list separated by the `:` token.
+ Overrides the location of the Nix user configuration files to load from.
+
+ The default are the locations according to the [XDG Base Directory Specification].
+ See the [XDG Base Directories](#xdg-base-directories) sub-section for details.
+
+ The variable is treated as a list separated by the `:` token.
- [`TMPDIR`](#env-TMPDIR)\
Use the specified directory to store temporary files. In particular,
@@ -103,15 +106,19 @@ Most Nix commands interpret the following environment variables:
384 MiB. Setting it to a low value reduces memory consumption, but
will increase runtime due to the overhead of garbage collection.
-## XDG Base Directory
+## XDG Base Directories
-New Nix commands conform to the [XDG Base Directory Specification], and use the following environment variables to determine locations of various state and configuration files:
+Nix follows the [XDG Base Directory Specification].
+
+For backwards compatibility, Nix commands will follow the standard only when [`use-xdg-base-directories`] is enabled.
+[New Nix commands](@docroot@/command-ref/new-cli/nix.md) (experimental) conform to the standard by default.
+
+The following environment variables are used to determine locations of various state and configuration files:
- [`XDG_CONFIG_HOME`]{#env-XDG_CONFIG_HOME} (default `~/.config`)
- [`XDG_STATE_HOME`]{#env-XDG_STATE_HOME} (default `~/.local/state`)
- [`XDG_CACHE_HOME`]{#env-XDG_CACHE_HOME} (default `~/.cache`)
-Classic Nix commands can also be made to follow this standard using the [`use-xdg-base-directories`] configuration option.
[XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
-[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
\ No newline at end of file
+[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
diff --git a/doc/manual/src/command-ref/files/channels.md b/doc/manual/src/command-ref/files/channels.md
new file mode 100644
index 000000000..7b1f27128
--- /dev/null
+++ b/doc/manual/src/command-ref/files/channels.md
@@ -0,0 +1,26 @@
+## Channels
+
+A directory containing symlinks to Nix channels, managed by [`nix-channel`]:
+
+- `$XDG_STATE_HOME/nix/profiles/channels` for regular users
+- `$NIX_STATE_DIR/profiles/per-user/root/channels` for `root`
+
+[`nix-channel`] uses a [profile](@docroot@/command-ref/files/profiles.md) to store channels.
+This profile contains symlinks to the contents of those channels.
+
+## Subscribed channels
+
+The list of subscribed channels is stored in
+
+- `~/.nix-channels`
+- `$XDG_STATE_HOME/nix/channels` if [`use-xdg-base-directories`] is set to `true`
+
+in the following format:
+
+```
+
+...
+```
+
+[`nix-channel`]: @docroot@/command-ref/nix-channel.md
+[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
diff --git a/doc/manual/src/command-ref/files/default-nix-expression.md b/doc/manual/src/command-ref/files/default-nix-expression.md
new file mode 100644
index 000000000..620f7035c
--- /dev/null
+++ b/doc/manual/src/command-ref/files/default-nix-expression.md
@@ -0,0 +1,52 @@
+## Default Nix expression
+
+The source for the default [Nix expressions](@docroot@/language/index.md) used by [`nix-env`]:
+
+- `~/.nix-defexpr`
+- `$XDG_STATE_HOME/nix/defexpr` if [`use-xdg-base-directories`] is set to `true`.
+
+It is loaded as follows:
+
+- If the default expression is a file, it is loaded as a Nix expression.
+- If the default expression is a directory containing a `default.nix` file, that `default.nix` file is loaded as a Nix expression.
+- If the default expression is a directory without a `default.nix` file, then its contents (both files and subdirectories) are loaded as Nix expressions.
+ The expressions are combined into a single attribute set, each expression under an attribute with the same name as the original file or subdirectory.
+ Subdirectories without a `default.nix` file are traversed recursively in search of more Nix expressions, but the names of these intermediate directories are not added to the attribute paths of the default Nix expression.
+
+Then, the resulting expression is interpreted like this:
+
+- If the expression is an attribute set, it is used as the default Nix expression.
+- If the expression is a function, an empty set is passed as argument and the return value is used as the default Nix expression.
+
+
+For example, if the default expression contains two files, `foo.nix` and `bar.nix`, then the default Nix expression will be equivalent to
+
+```nix
+{
+ foo = import ~/.nix-defexpr/foo.nix;
+ bar = import ~/.nix-defexpr/bar.nix;
+}
+```
+
+The file [`manifest.nix`](@docroot@/command-ref/files/manifest.nix.md) is always ignored.
+
+The command [`nix-channel`] places a symlink to the user's current [channels profile](@docroot@/command-ref/files/channels.md) in this directory.
+This makes all subscribed channels available as attributes in the default expression.
+
+## User channel link
+
+A symlink that ensures that [`nix-env`] can find your channels:
+
+- `~/.nix-defexpr/channels`
+- `$XDG_STATE_HOME/defexpr/channels` if [`use-xdg-base-directories`] is set to `true`.
+
+This symlink points to:
+
+- `$XDG_STATE_HOME/profiles/channels` for regular users
+- `$NIX_STATE_DIR/profiles/per-user/root/channels` for `root`
+
+In a multi-user installation, you may also have `~/.nix-defexpr/channels_root`, which links to the channels of the root user.[`nix-env`]: ../nix-env.md
+
+[`nix-env`]: @docroot@/command-ref/nix-env.md
+[`nix-channel`]: @docroot@/command-ref/nix-channel.md
+[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
diff --git a/doc/manual/src/command-ref/files/manifest.json.md b/doc/manual/src/command-ref/files/manifest.json.md
new file mode 100644
index 000000000..bcfe7373d
--- /dev/null
+++ b/doc/manual/src/command-ref/files/manifest.json.md
@@ -0,0 +1,45 @@
+## `manifest.json`
+
+The manifest file records the provenance of the packages that are installed in a [profile](./profiles.md) managed by [`nix profile`](@docroot@/command-ref/new-cli/nix3-profile.md) (experimental).
+
+Here is an example of what the file might look like after installing `zoom-us` from Nixpkgs:
+
+```json
+{
+ "version": 1,
+ "elements": [
+ {
+ "active": true,
+ "attrPath": "legacyPackages.x86_64-linux.zoom-us",
+ "originalUrl": "flake:nixpkgs",
+ "storePaths": [
+ "/nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927"
+ ],
+ "uri": "github:NixOS/nixpkgs/13d0c311e3ae923a00f734b43fd1d35b47d8943a"
+ },
+ …
+ ]
+}
+```
+
+Each object in the array `elements` denotes an installed package and
+has the following fields:
+
+* `originalUrl`: The [flake reference](@docroot@/command-ref/new-cli/nix3-flake.md) specified by
+ 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 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
+ user specified, but the one resulting from applying the default
+ attribute paths and prefixes; for instance, `hello` might resolve to
+ `packages.x86_64-linux.hello` and the empty string to
+ `packages.x86_64-linux.default`.
+
+* `storePath`: The paths in the Nix store containing the package.
+
+* `active`: Whether the profile contains symlinks to the files of this
+ package. If set to false, the package is kept in the Nix store, but
+ is not "visible" in the profile's symlink tree.
diff --git a/doc/manual/src/command-ref/files/manifest.nix.md b/doc/manual/src/command-ref/files/manifest.nix.md
new file mode 100644
index 000000000..d7d1b605b
--- /dev/null
+++ b/doc/manual/src/command-ref/files/manifest.nix.md
@@ -0,0 +1,128 @@
+## `manifest.nix`
+
+The manifest file records the provenance of the packages that are installed in a [profile](./profiles.md) managed by [`nix-env`](@docroot@/command-ref/nix-env.md).
+
+Here is an example of how this file might look like after installing `hello` from Nixpkgs:
+
+```nix
+[{
+ meta = {
+ available = true;
+ broken = false;
+ changelog =
+ "https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v2.12.1";
+ description = "A program that produces a familiar, friendly greeting";
+ homepage = "https://www.gnu.org/software/hello/manual/";
+ insecure = false;
+ license = {
+ deprecated = false;
+ free = true;
+ fullName = "GNU General Public License v3.0 or later";
+ redistributable = true;
+ shortName = "gpl3Plus";
+ spdxId = "GPL-3.0-or-later";
+ url = "https://spdx.org/licenses/GPL-3.0-or-later.html";
+ };
+ longDescription = ''
+ GNU Hello is a program that prints "Hello, world!" when you run it.
+ It is fully customizable.
+ '';
+ maintainers = [{
+ email = "edolstra+nixpkgs@gmail.com";
+ github = "edolstra";
+ githubId = 1148549;
+ name = "Eelco Dolstra";
+ }];
+ name = "hello-2.12.1";
+ outputsToInstall = [ "out" ];
+ platforms = [
+ "i686-cygwin"
+ "x86_64-cygwin"
+ "x86_64-darwin"
+ "i686-darwin"
+ "aarch64-darwin"
+ "armv7a-darwin"
+ "i686-freebsd13"
+ "x86_64-freebsd13"
+ "aarch64-genode"
+ "i686-genode"
+ "x86_64-genode"
+ "x86_64-solaris"
+ "js-ghcjs"
+ "aarch64-linux"
+ "armv5tel-linux"
+ "armv6l-linux"
+ "armv7a-linux"
+ "armv7l-linux"
+ "i686-linux"
+ "m68k-linux"
+ "microblaze-linux"
+ "microblazeel-linux"
+ "mipsel-linux"
+ "mips64el-linux"
+ "powerpc64-linux"
+ "powerpc64le-linux"
+ "riscv32-linux"
+ "riscv64-linux"
+ "s390-linux"
+ "s390x-linux"
+ "x86_64-linux"
+ "mmix-mmixware"
+ "aarch64-netbsd"
+ "armv6l-netbsd"
+ "armv7a-netbsd"
+ "armv7l-netbsd"
+ "i686-netbsd"
+ "m68k-netbsd"
+ "mipsel-netbsd"
+ "powerpc-netbsd"
+ "riscv32-netbsd"
+ "riscv64-netbsd"
+ "x86_64-netbsd"
+ "aarch64_be-none"
+ "aarch64-none"
+ "arm-none"
+ "armv6l-none"
+ "avr-none"
+ "i686-none"
+ "microblaze-none"
+ "microblazeel-none"
+ "msp430-none"
+ "or1k-none"
+ "m68k-none"
+ "powerpc-none"
+ "powerpcle-none"
+ "riscv32-none"
+ "riscv64-none"
+ "rx-none"
+ "s390-none"
+ "s390x-none"
+ "vc4-none"
+ "x86_64-none"
+ "i686-openbsd"
+ "x86_64-openbsd"
+ "x86_64-redox"
+ "wasm64-wasi"
+ "wasm32-wasi"
+ "x86_64-windows"
+ "i686-windows"
+ ];
+ position =
+ "/nix/store/7niq32w715567hbph0q13m5lqna64c1s-nixos-unstable.tar.gz/nixos-unstable.tar.gz/pkgs/applications/misc/hello/default.nix:34";
+ unfree = false;
+ unsupported = false;
+ };
+ name = "hello-2.12.1";
+ out = {
+ outPath = "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1";
+ };
+ outPath = "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1";
+ outputs = [ "out" ];
+ system = "x86_64-linux";
+ type = "derivation";
+}]
+```
+
+Each element in this list corresponds to an installed package.
+It incorporates some attributes of the original derivation, including `meta`, `name`, `out`, `outPath`, `outputs`, `system`.
+This information is used by Nix for querying and updating the package.
diff --git a/doc/manual/src/command-ref/files/profiles.md b/doc/manual/src/command-ref/files/profiles.md
new file mode 100644
index 000000000..b5c737880
--- /dev/null
+++ b/doc/manual/src/command-ref/files/profiles.md
@@ -0,0 +1,74 @@
+## Profiles
+
+A directory that contains links to profiles managed by [`nix-env`] and [`nix profile`]:
+
+- `$XDG_STATE_HOME/nix/profiles` for regular users
+- `$NIX_STATE_DIR/profiles/per-user/root` if the user is `root`
+
+A profile is a directory of symlinks to files in the Nix store.
+
+### Filesystem layout
+
+Profiles are versioned as follows. When using a profile named *path*, *path* is a symlink to *path*`-`*N*`-link`, where *N* is the version of the profile.
+In turn, *path*`-`*N*`-link` is a symlink to a path in the Nix store.
+For example:
+
+```console
+$ ls -l ~alice/.local/state/nix/profiles/profile*
+lrwxrwxrwx 1 alice users 14 Nov 25 14:35 /home/alice/.local/state/nix/profiles/profile -> profile-7-link
+lrwxrwxrwx 1 alice users 51 Oct 28 16:18 /home/alice/.local/state/nix/profiles/profile-5-link -> /nix/store/q69xad13ghpf7ir87h0b2gd28lafjj1j-profile
+lrwxrwxrwx 1 alice users 51 Oct 29 13:20 /home/alice/.local/state/nix/profiles/profile-6-link -> /nix/store/6bvhpysd7vwz7k3b0pndn7ifi5xr32dg-profile
+lrwxrwxrwx 1 alice users 51 Nov 25 14:35 /home/alice/.local/state/nix/profiles/profile-7-link -> /nix/store/mp0x6xnsg0b8qhswy6riqvimai4gm677-profile
+```
+
+Each of these symlinks is a root for the Nix garbage collector.
+
+The contents of the store path corresponding to each version of the
+profile is a tree of symlinks to the files of the installed packages,
+e.g.
+
+```console
+$ ll -R ~eelco/.local/state/nix/profiles/profile-7-link/
+/home/eelco/.local/state/nix/profiles/profile-7-link/:
+total 20
+dr-xr-xr-x 2 root root 4096 Jan 1 1970 bin
+-r--r--r-- 2 root root 1402 Jan 1 1970 manifest.nix
+dr-xr-xr-x 4 root root 4096 Jan 1 1970 share
+
+/home/eelco/.local/state/nix/profiles/profile-7-link/bin:
+total 20
+lrwxrwxrwx 5 root root 79 Jan 1 1970 chromium -> /nix/store/ijm5k0zqisvkdwjkc77mb9qzb35xfi4m-chromium-86.0.4240.111/bin/chromium
+lrwxrwxrwx 7 root root 87 Jan 1 1970 spotify -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/bin/spotify
+lrwxrwxrwx 3 root root 79 Jan 1 1970 zoom-us -> /nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927/bin/zoom-us
+
+/home/eelco/.local/state/nix/profiles/profile-7-link/share/applications:
+total 12
+lrwxrwxrwx 4 root root 120 Jan 1 1970 chromium-browser.desktop -> /nix/store/4cf803y4vzfm3gyk3vzhzb2327v0kl8a-chromium-unwrapped-86.0.4240.111/share/applications/chromium-browser.desktop
+lrwxrwxrwx 7 root root 110 Jan 1 1970 spotify.desktop -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/share/applications/spotify.desktop
+lrwxrwxrwx 3 root root 107 Jan 1 1970 us.zoom.Zoom.desktop -> /nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927/share/applications/us.zoom.Zoom.desktop
+
+…
+```
+
+Each profile version contains a manifest file:
+- [`manifest.nix`](@docroot@/command-ref/files/manifest.nix.md) used by [`nix-env`](@docroot@/command-ref/nix-env.md).
+- [`manifest.json`](@docroot@/command-ref/files/manifest.json.md) used by [`nix profile`](@docroot@/command-ref/new-cli/nix3-profile.md) (experimental).
+
+## User profile link
+
+A symbolic link to the user's current profile:
+
+- `~/.nix-profile`
+- `$XDG_STATE_HOME/nix/profile` if [`use-xdg-base-directories`] is set to `true`.
+
+By default, this symlink points to:
+
+- `$XDG_STATE_HOME/nix/profiles/profile` for regular users
+- `$NIX_STATE_DIR/profiles/per-user/root/profile` for `root`
+
+The `PATH` environment variable should include `/bin` subdirectory of the profile link (e.g. `~/.nix-profile/bin`) for the user environment to be visible to the user.
+The [installer](@docroot@/installation/installing-binary.md) sets this up by default, unless you enable [`use-xdg-base-directories`].
+
+[`nix-env`]: @docroot@/command-ref/nix-env.md
+[`nix profile`]: @docroot@/command-ref/new-cli/nix3-profile.md
+[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
diff --git a/doc/manual/src/command-ref/nix-build.md b/doc/manual/src/command-ref/nix-build.md
index 44de4cf53..f70bbd7f2 100644
--- a/doc/manual/src/command-ref/nix-build.md
+++ b/doc/manual/src/command-ref/nix-build.md
@@ -76,7 +76,7 @@ except for `--arg` and `--attr` / `-A` which are passed to `nix-instantiate`.
# Examples
```console
-$ nix-build '' -A firefox
+$ nix-build '' --attr firefox
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
@@ -91,7 +91,7 @@ If a derivation has multiple outputs, `nix-build` will build the default
(first) output. You can also build all outputs:
```console
-$ nix-build '' -A openssl.all
+$ nix-build '' --attr openssl.all
```
This will create a symlink for each output named `result-outputname`.
@@ -101,7 +101,7 @@ outputs `out`, `bin` and `man`, `nix-build` will create symlinks
specific output:
```console
-$ nix-build '' -A openssl.man
+$ nix-build '' --attr openssl.man
```
This will create a symlink `result-man`.
@@ -109,7 +109,7 @@ This will create a symlink `result-man`.
Build a Nix expression given on the command line:
```console
-$ nix-build -E 'with import { }; runCommand "foo" { } "echo bar > $out"'
+$ nix-build --expr 'with import { }; runCommand "foo" { } "echo bar > $out"'
$ cat ./result
bar
```
@@ -118,5 +118,5 @@ Build the GNU Hello package from the latest revision of the master
branch of Nixpkgs:
```console
-$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz -A hello
+$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz --attr hello
```
diff --git a/doc/manual/src/command-ref/nix-channel.md b/doc/manual/src/command-ref/nix-channel.md
index 2027cc98d..a210583ae 100644
--- a/doc/manual/src/command-ref/nix-channel.md
+++ b/doc/manual/src/command-ref/nix-channel.md
@@ -22,6 +22,9 @@ This command has the following operations:
channels. If *name* is omitted, it defaults to the last component of
*url*, with the suffixes `-stable` or `-unstable` removed.
+ A channel URL must point to a directory containing a file `nixexprs.tar.gz`.
+ At the top level, that tarball must contain a single directory with a `default.nix` file that serves as the channel’s entry point.
+
- `--remove` *name*\
Removes the channel named *name* from the list of subscribed
channels.
@@ -49,6 +52,12 @@ The list of subscribed channels is stored in `~/.nix-channels`.
{{#include ./env-common.md}}
+# Files
+
+`nix-channel` operates on the following files.
+
+{{#include ./files/channels.md}}
+
# Examples
To subscribe to the Nixpkgs channel and install the GNU Hello package:
@@ -56,45 +65,18 @@ To subscribe to the Nixpkgs channel and install the GNU Hello package:
```console
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
$ nix-channel --update
-$ nix-env -iA nixpkgs.hello
+$ nix-env --install --attr nixpkgs.hello
```
You can revert channel updates using `--rollback`:
```console
-$ nix-instantiate --eval -E '(import {}).lib.version'
+$ nix-instantiate --eval --expr '(import {}).lib.version'
"14.04.527.0e935f1"
$ nix-channel --rollback
switching from generation 483 to 482
-$ nix-instantiate --eval -E '(import {}).lib.version'
+$ nix-instantiate --eval --expr '(import {}).lib.version'
"14.04.526.dbadfad"
```
-
-# Files
-
- - `${XDG_STATE_HOME-$HOME/.local/state}/nix/profiles/channels`\
- `nix-channel` uses a `nix-env` profile to keep track of previous
- versions of the subscribed channels. Every time you run `nix-channel
- --update`, a new channel generation (that is, a symlink to the
- channel Nix expressions in the Nix store) is created. This enables
- `nix-channel --rollback` to revert to previous versions.
-
- - `~/.nix-defexpr/channels`\
- This is a symlink to
- `${XDG_STATE_HOME-$HOME/.local/state}/nix/profiles/channels`. It ensures that
- `nix-env` can find your channels. In a multi-user installation, you
- may also have `~/.nix-defexpr/channels_root`, which links to the
- channels of the root user.
-
-# Channel format
-
-A channel URL should point to a directory containing the following
-files:
-
- - `nixexprs.tar.xz`\
- A tarball containing Nix expressions and files referenced by them
- (such as build scripts and patches). At the top level, the tarball
- should contain a single directory. That directory must contain a
- file `default.nix` that serves as the channel’s “entry point”.
diff --git a/doc/manual/src/command-ref/nix-copy-closure.md b/doc/manual/src/command-ref/nix-copy-closure.md
index 0801e8246..fbf6828da 100644
--- a/doc/manual/src/command-ref/nix-copy-closure.md
+++ b/doc/manual/src/command-ref/nix-copy-closure.md
@@ -87,5 +87,5 @@ environment:
```console
$ nix-copy-closure --from alice@itchy.labs \
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
-$ nix-env -i /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
+$ nix-env --install /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
```
diff --git a/doc/manual/src/command-ref/nix-env.md b/doc/manual/src/command-ref/nix-env.md
index 42b5bca77..941723216 100644
--- a/doc/manual/src/command-ref/nix-env.md
+++ b/doc/manual/src/command-ref/nix-env.md
@@ -49,7 +49,7 @@ These pages can be viewed offline:
# Selectors
-Several commands, such as `nix-env -q` and `nix-env -i`, take a list of
+Several commands, such as `nix-env --query ` and `nix-env --install `, take a list of
arguments that specify the packages on which to operate. These are
extended regular expressions that must match the entire name of the
package. (For details on regular expressions, see **regex**(7).) The match is
@@ -83,46 +83,8 @@ match. Here are some examples:
# Files
- - `~/.nix-defexpr`\
- The source for the default Nix expressions used by the
- `--install`, `--upgrade`, and `--query --available` operations to
- obtain derivations. The `--file` option may be used to override
- this default.
+`nix-env` operates on the following files.
- If `~/.nix-defexpr` is a file, it is loaded as a Nix expression. If
- the expression is a set, it is used as the default Nix expression.
- If the expression is a function, an empty set is passed as argument
- and the return value is used as the default Nix expression.
+{{#include ./files/default-nix-expression.md}}
- If `~/.nix-defexpr` is a directory containing a `default.nix` file,
- that file is loaded as in the above paragraph.
-
- If `~/.nix-defexpr` is a directory without a `default.nix` file,
- then its contents (both files and subdirectories) are loaded as Nix
- expressions. The expressions are combined into a single set, each
- expression under an attribute with the same name as the original
- file or subdirectory.
-
- For example, if `~/.nix-defexpr` contains two files, `foo.nix` and
- `bar.nix`, then the default Nix expression will essentially be
-
- ```nix
- {
- foo = import ~/.nix-defexpr/foo.nix;
- bar = import ~/.nix-defexpr/bar.nix;
- }
- ```
-
- The file `manifest.nix` is always ignored. Subdirectories without a
- `default.nix` file are traversed recursively in search of more Nix
- expressions, but the names of these intermediate directories are not
- added to the attribute paths of the default Nix expression.
-
- The command `nix-channel` places symlinks to the downloaded Nix
- expressions from each subscribed channel in this directory.
-
- - `~/.nix-profile`\
- A symbolic link to the user's current profile. By default, this
- symlink points to `prefix/var/nix/profiles/default`. The `PATH`
- environment variable should include `~/.nix-profile/bin` for the
- user environment to be visible to the user.
+{{#include ./files/profiles.md}}
diff --git a/doc/manual/src/command-ref/nix-env/delete-generations.md b/doc/manual/src/command-ref/nix-env/delete-generations.md
index 6f0af5384..92cb7f0d9 100644
--- a/doc/manual/src/command-ref/nix-env/delete-generations.md
+++ b/doc/manual/src/command-ref/nix-env/delete-generations.md
@@ -41,6 +41,6 @@ $ nix-env --delete-generations 30d
```
```console
-$ nix-env -p other_profile --delete-generations old
+$ nix-env --profile other_profile --delete-generations old
```
diff --git a/doc/manual/src/command-ref/nix-env/install.md b/doc/manual/src/command-ref/nix-env/install.md
index d754accfe..ad179cbc7 100644
--- a/doc/manual/src/command-ref/nix-env/install.md
+++ b/doc/manual/src/command-ref/nix-env/install.md
@@ -36,7 +36,7 @@ a number of possible ways:
then the derivation with the highest version will be installed.
You can force the installation of multiple derivations with the same
- name by being specific about the versions. For instance, `nix-env -i
+ name by being specific about the versions. For instance, `nix-env --install
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
probably cause a user environment conflict\!).
@@ -44,7 +44,7 @@ a number of possible ways:
paths* that select attributes from the top-level Nix
expression. This is faster than using derivation names and
unambiguous. To find out the attribute paths of available
- packages, use `nix-env -qaP`.
+ packages, use `nix-env --query --available --attr-path `.
- If `--from-profile` *path* is given, *args* is a set of names
denoting installed store paths in the profile *path*. This is an
@@ -87,7 +87,7 @@ a number of possible ways:
- `--remove-all` / `-r`\
Remove all previously installed packages first. This is equivalent
- to running `nix-env -e '.*'` first, except that everything happens
+ to running `nix-env --uninstall '.*'` first, except that everything happens
in a single transaction.
{{#include ./opt-common.md}}
@@ -103,9 +103,9 @@ a number of possible ways:
To install a package using a specific attribute path from the active Nix expression:
```console
-$ nix-env -iA gcc40mips
+$ nix-env --install --attr gcc40mips
installing `gcc-4.0.2'
-$ nix-env -iA xorg.xorgserver
+$ nix-env --install --attr xorg.xorgserver
installing `xorg-server-1.2.0'
```
@@ -133,32 +133,32 @@ installing `gcc-3.3.2'
To install all derivations in the Nix expression `foo.nix`:
```console
-$ nix-env -f ~/foo.nix -i '.*'
+$ nix-env --file ~/foo.nix --install '.*'
```
To copy the store path with symbolic name `gcc` from another profile:
```console
-$ nix-env -i --from-profile /nix/var/nix/profiles/foo gcc
+$ nix-env --install --from-profile /nix/var/nix/profiles/foo gcc
```
To install a specific [store derivation] (typically created by
`nix-instantiate`):
```console
-$ nix-env -i /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
+$ nix-env --install /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
```
To install a specific output path:
```console
-$ nix-env -i /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
+$ nix-env --install /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
```
To install from a Nix expression specified on the command-line:
```console
-$ nix-env -f ./foo.nix -i -E \
+$ nix-env --file ./foo.nix --install --expr \
'f: (f {system = "i686-linux";}).subversionWithJava'
```
@@ -170,7 +170,7 @@ function defined in `./foo.nix`.
A dry-run tells you which paths will be downloaded or built from source:
```console
-$ nix-env -f '' -iA hello --dry-run
+$ nix-env --file '' --install --attr hello --dry-run
(dry run; not doing anything)
installing ‘hello-2.10’
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
@@ -182,6 +182,6 @@ To install Firefox from the latest revision in the Nixpkgs/NixOS 14.12
channel:
```console
-$ nix-env -f https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz -iA firefox
+$ nix-env --file https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz --install --attr firefox
```
diff --git a/doc/manual/src/command-ref/nix-env/query.md b/doc/manual/src/command-ref/nix-env/query.md
index 18f0ee210..c9b4d8513 100644
--- a/doc/manual/src/command-ref/nix-env/query.md
+++ b/doc/manual/src/command-ref/nix-env/query.md
@@ -137,7 +137,7 @@ derivation is shown unless `--no-name` is specified.
To show installed packages:
```console
-$ nix-env -q
+$ nix-env --query
bison-1.875c
docbook-xml-4.2
firefox-1.0.4
@@ -149,7 +149,7 @@ ORBit2-2.8.3
To show available packages:
```console
-$ nix-env -qa
+$ nix-env --query --available
firefox-1.0.7
GConf-2.4.0.1
MPlayer-1.0pre7
@@ -160,7 +160,7 @@ ORBit2-2.8.3
To show the status of available packages:
```console
-$ nix-env -qas
+$ nix-env --query --available --status
-P- firefox-1.0.7 (not installed but present)
--S GConf-2.4.0.1 (not present, but there is a substitute for fast installation)
--S MPlayer-1.0pre3 (i.e., this is not the installed MPlayer, even though the version is the same!)
@@ -171,14 +171,14 @@ IP- ORBit2-2.8.3 (installed and by definition present)
To show available packages in the Nix expression `foo.nix`:
```console
-$ nix-env -f ./foo.nix -qa
+$ nix-env --file ./foo.nix --query --available
foo-1.2.3
```
To compare installed versions to what’s available:
```console
-$ nix-env -qc
+$ nix-env --query --compare-versions
...
acrobat-reader-7.0 - ? (package is not available at all)
autoconf-2.59 = 2.59 (same version)
@@ -189,7 +189,7 @@ firefox-1.0.4 < 1.0.7 (a more recent version is available)
To show all packages with “`zip`” in the name:
```console
-$ nix-env -qa '.*zip.*'
+$ nix-env --query --available '.*zip.*'
bzip2-1.0.6
gzip-1.6
zip-3.0
@@ -199,7 +199,7 @@ zip-3.0
To show all packages with “`firefox`” or “`chromium`” in the name:
```console
-$ nix-env -qa '.*(firefox|chromium).*'
+$ nix-env --query --available '.*(firefox|chromium).*'
chromium-37.0.2062.94
chromium-beta-38.0.2125.24
firefox-32.0.3
@@ -210,6 +210,6 @@ firefox-with-plugins-13.0.1
To show all packages in the latest revision of the Nixpkgs repository:
```console
-$ nix-env -f https://github.com/NixOS/nixpkgs/archive/master.tar.gz -qa
+$ nix-env --file https://github.com/NixOS/nixpkgs/archive/master.tar.gz --query --available
```
diff --git a/doc/manual/src/command-ref/nix-env/set-flag.md b/doc/manual/src/command-ref/nix-env/set-flag.md
index 63f0a0ff9..e04b22a91 100644
--- a/doc/manual/src/command-ref/nix-env/set-flag.md
+++ b/doc/manual/src/command-ref/nix-env/set-flag.md
@@ -46,16 +46,16 @@ To prevent the currently installed Firefox from being upgraded:
$ nix-env --set-flag keep true firefox
```
-After this, `nix-env -u` will ignore Firefox.
+After this, `nix-env --upgrade ` will ignore Firefox.
To disable the currently installed Firefox, then install a new Firefox
while the old remains part of the profile:
```console
-$ nix-env -q
+$ nix-env --query
firefox-2.0.0.9 (the current one)
-$ nix-env --preserve-installed -i firefox-2.0.0.11
+$ nix-env --preserve-installed --install firefox-2.0.0.11
installing `firefox-2.0.0.11'
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
@@ -65,10 +65,10 @@ collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
$ nix-env --set-flag active false firefox
setting flag on `firefox-2.0.0.9'
-$ nix-env --preserve-installed -i firefox-2.0.0.11
+$ nix-env --preserve-installed --install firefox-2.0.0.11
installing `firefox-2.0.0.11'
-$ nix-env -q
+$ nix-env --query
firefox-2.0.0.11 (the enabled one)
firefox-2.0.0.9 (the disabled one)
```
diff --git a/doc/manual/src/command-ref/nix-env/set.md b/doc/manual/src/command-ref/nix-env/set.md
index c1cf75739..b9950eeab 100644
--- a/doc/manual/src/command-ref/nix-env/set.md
+++ b/doc/manual/src/command-ref/nix-env/set.md
@@ -25,6 +25,6 @@ The following updates a profile such that its current generation will
contain just Firefox:
```console
-$ nix-env -p /nix/var/nix/profiles/browser --set firefox
+$ nix-env --profile /nix/var/nix/profiles/browser --set firefox
```
diff --git a/doc/manual/src/command-ref/nix-env/switch-generation.md b/doc/manual/src/command-ref/nix-env/switch-generation.md
index e550325c4..38cf0534d 100644
--- a/doc/manual/src/command-ref/nix-env/switch-generation.md
+++ b/doc/manual/src/command-ref/nix-env/switch-generation.md
@@ -27,7 +27,7 @@ Switching will fail if the specified generation does not exist.
# Examples
```console
-$ nix-env -G 42
+$ nix-env --switch-generation 42
switching from generation 50 to 42
```
diff --git a/doc/manual/src/command-ref/nix-env/switch-profile.md b/doc/manual/src/command-ref/nix-env/switch-profile.md
index b389e4140..5ae2fdced 100644
--- a/doc/manual/src/command-ref/nix-env/switch-profile.md
+++ b/doc/manual/src/command-ref/nix-env/switch-profile.md
@@ -22,5 +22,5 @@ the symlink `~/.nix-profile` is made to point to *path*.
# Examples
```console
-$ nix-env -S ~/my-profile
+$ nix-env --switch-profile ~/my-profile
```
diff --git a/doc/manual/src/command-ref/nix-env/uninstall.md b/doc/manual/src/command-ref/nix-env/uninstall.md
index e9ec8a15e..734cc7675 100644
--- a/doc/manual/src/command-ref/nix-env/uninstall.md
+++ b/doc/manual/src/command-ref/nix-env/uninstall.md
@@ -24,5 +24,5 @@ designated by the symbolic names *drvnames* are removed.
```console
$ nix-env --uninstall gcc
-$ nix-env -e '.*' (remove everything)
+$ nix-env --uninstall '.*' (remove everything)
```
diff --git a/doc/manual/src/command-ref/nix-env/upgrade.md b/doc/manual/src/command-ref/nix-env/upgrade.md
index f88ffcbee..322dfbda2 100644
--- a/doc/manual/src/command-ref/nix-env/upgrade.md
+++ b/doc/manual/src/command-ref/nix-env/upgrade.md
@@ -76,21 +76,21 @@ version is installed.
# Examples
```console
-$ nix-env --upgrade -A nixpkgs.gcc
+$ nix-env --upgrade --attr nixpkgs.gcc
upgrading `gcc-3.3.1' to `gcc-3.4'
```
When there are no updates available, nothing will happen:
```console
-$ nix-env --upgrade -A nixpkgs.pan
+$ nix-env --upgrade --attr nixpkgs.pan
```
Using `-A` is preferred when possible, as it is faster and unambiguous but
it is also possible to upgrade to a specific version by matching the derivation name:
```console
-$ nix-env -u gcc-3.3.2 --always
+$ nix-env --upgrade gcc-3.3.2 --always
upgrading `gcc-3.4' to `gcc-3.3.2'
```
@@ -98,7 +98,7 @@ To try to upgrade everything
(matching packages based on the part of the derivation name without version):
```console
-$ nix-env -u
+$ nix-env --upgrade
upgrading `hello-2.1.2' to `hello-2.1.3'
upgrading `mozilla-1.2' to `mozilla-1.4'
```
diff --git a/doc/manual/src/command-ref/nix-instantiate.md b/doc/manual/src/command-ref/nix-instantiate.md
index e55fb2afd..e1b4a3e80 100644
--- a/doc/manual/src/command-ref/nix-instantiate.md
+++ b/doc/manual/src/command-ref/nix-instantiate.md
@@ -88,7 +88,7 @@ Instantiate [store derivation]s from a Nix expression, and build them using `nix
$ nix-instantiate test.nix (instantiate)
/nix/store/cigxbmvy6dzix98dxxh9b6shg7ar5bvs-perl-BerkeleyDB-0.26.drv
-$ nix-store -r $(nix-instantiate test.nix) (build)
+$ nix-store --realise $(nix-instantiate test.nix) (build)
...
/nix/store/qhqk4n8ci095g3sdp93x7rgwyh9rdvgk-perl-BerkeleyDB-0.26 (output path)
@@ -100,30 +100,30 @@ dr-xr-xr-x 2 eelco users 4096 1970-01-01 01:00 lib
You can also give a Nix expression on the command line:
```console
-$ nix-instantiate -E 'with import { }; hello'
+$ nix-instantiate --expr 'with import { }; hello'
/nix/store/j8s4zyv75a724q38cb0r87rlczaiag4y-hello-2.8.drv
```
This is equivalent to:
```console
-$ nix-instantiate '' -A hello
+$ nix-instantiate '' --attr hello
```
Parsing and evaluating Nix expressions:
```console
-$ nix-instantiate --parse -E '1 + 2'
+$ nix-instantiate --parse --expr '1 + 2'
1 + 2
```
```console
-$ nix-instantiate --eval -E '1 + 2'
+$ nix-instantiate --eval --expr '1 + 2'
3
```
```console
-$ nix-instantiate --eval --xml -E '1 + 2'
+$ nix-instantiate --eval --xml --expr '1 + 2'
@@ -133,7 +133,7 @@ $ nix-instantiate --eval --xml -E '1 + 2'
The difference between non-strict and strict evaluation:
```console
-$ nix-instantiate --eval --xml -E 'rec { x = "foo"; y = x; }'
+$ nix-instantiate --eval --xml --expr 'rec { x = "foo"; y = x; }'
...
@@ -148,7 +148,7 @@ Note that `y` is left unevaluated (the XML representation doesn’t
attempt to show non-normal forms).
```console
-$ nix-instantiate --eval --xml --strict -E 'rec { x = "foo"; y = x; }'
+$ nix-instantiate --eval --xml --strict --expr 'rec { x = "foo"; y = x; }'
...
diff --git a/doc/manual/src/command-ref/nix-shell.md b/doc/manual/src/command-ref/nix-shell.md
index 576e5ba0b..195b72be5 100644
--- a/doc/manual/src/command-ref/nix-shell.md
+++ b/doc/manual/src/command-ref/nix-shell.md
@@ -89,7 +89,7 @@ All options not listed here are passed to `nix-store
- `--packages` / `-p` *packages*…\
Set up an environment in which the specified packages are present.
The command line arguments are interpreted as attribute names inside
- the Nix Packages collection. Thus, `nix-shell -p libjpeg openjdk`
+ the Nix Packages collection. Thus, `nix-shell --packages libjpeg openjdk`
will start a shell in which the packages denoted by the attribute
names `libjpeg` and `openjdk` are present.
@@ -118,7 +118,7 @@ To build the dependencies of the package Pan, and start an interactive
shell in which to build it:
```console
-$ nix-shell '' -A pan
+$ nix-shell '' --attr pan
[nix-shell]$ eval ${unpackPhase:-unpackPhase}
[nix-shell]$ cd $sourceRoot
[nix-shell]$ eval ${patchPhase:-patchPhase}
@@ -137,7 +137,7 @@ To clear the environment first, and do some additional automatic
initialisation of the interactive shell:
```console
-$ nix-shell '' -A pan --pure \
+$ nix-shell '' --attr pan --pure \
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
```
@@ -146,13 +146,13 @@ Nix expressions can also be given on the command line using the `-E` and
packages `sqlite` and `libX11`:
```console
-$ nix-shell -E 'with import { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
+$ nix-shell --expr 'with import { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
```
A shorter way to do the same is:
```console
-$ nix-shell -p sqlite xorg.libX11
+$ nix-shell --packages sqlite xorg.libX11
[nix-shell]$ echo $NIX_LDFLAGS
… -L/nix/store/j1zg5v…-sqlite-3.8.0.2/lib -L/nix/store/0gmcz9…-libX11-1.6.1/lib …
```
@@ -162,7 +162,7 @@ the `buildInputs = [ ... ]` shown above, not only package names. So the
following is also legal:
```console
-$ nix-shell -p sqlite 'git.override { withManual = false; }'
+$ nix-shell --packages sqlite 'git.override { withManual = false; }'
```
The `-p` flag looks up Nixpkgs in the Nix search path. You can override
@@ -171,7 +171,7 @@ gives you a shell containing the Pan package from a specific revision of
Nixpkgs:
```console
-$ nix-shell -p pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
+$ nix-shell --packages pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
[nix-shell:~]$ pan --version
Pan 0.139
@@ -185,7 +185,7 @@ done by starting the script with the following lines:
```bash
#! /usr/bin/env nix-shell
-#! nix-shell -i real-interpreter -p packages
+#! nix-shell -i real-interpreter --packages packages
```
where *real-interpreter* is the “real” script interpreter that will be
@@ -202,7 +202,7 @@ For example, here is a Python script that depends on Python and the
```python
#! /usr/bin/env nix-shell
-#! nix-shell -i python -p python pythonPackages.prettytable
+#! nix-shell -i python --packages python pythonPackages.prettytable
import prettytable
@@ -217,7 +217,7 @@ requires Perl and the `HTML::TokeParser::Simple` and `LWP` packages:
```perl
#! /usr/bin/env nix-shell
-#! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
+#! nix-shell -i perl --packages perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
use HTML::TokeParser::Simple;
@@ -235,7 +235,7 @@ package like Terraform:
```bash
#! /usr/bin/env nix-shell
-#! nix-shell -i bash -p "terraform.withPlugins (plugins: [ plugins.openstack ])"
+#! nix-shell -i bash --packages "terraform.withPlugins (plugins: [ plugins.openstack ])"
terraform apply
```
@@ -251,7 +251,7 @@ branch):
```haskell
#! /usr/bin/env nix-shell
-#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
+#! nix-shell -i runghc --packages "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
import Network.Curl.Download
diff --git a/doc/manual/src/command-ref/nix-store/dump.md b/doc/manual/src/command-ref/nix-store/dump.md
index 62656d599..c2f3c42ef 100644
--- a/doc/manual/src/command-ref/nix-store/dump.md
+++ b/doc/manual/src/command-ref/nix-store/dump.md
@@ -23,7 +23,7 @@ produce the same NAR archive. For instance, directory entries are
always sorted so that the actual on-disk order doesn’t influence the
result. This means that the cryptographic hash of a NAR dump of a
path is usable as a fingerprint of the contents of the path. Indeed,
-the hashes of store paths stored in Nix’s database (see `nix-store -q
+the hashes of store paths stored in Nix’s database (see `nix-store --query
--hash`) are SHA-256 hashes of the NAR dump of each store path.
NAR archives support filenames of unlimited length and 64-bit file
diff --git a/doc/manual/src/command-ref/nix-store/export.md b/doc/manual/src/command-ref/nix-store/export.md
index aeea38636..1bc46f53b 100644
--- a/doc/manual/src/command-ref/nix-store/export.md
+++ b/doc/manual/src/command-ref/nix-store/export.md
@@ -31,7 +31,7 @@ To copy a whole closure, do something
like:
```console
-$ nix-store --export $(nix-store -qR paths) > out
+$ nix-store --export $(nix-store --query --requisites paths) > out
```
To import the whole closure again, run:
diff --git a/doc/manual/src/command-ref/nix-store/opt-common.md b/doc/manual/src/command-ref/nix-store/opt-common.md
index bf6566555..dd9a6bf21 100644
--- a/doc/manual/src/command-ref/nix-store/opt-common.md
+++ b/doc/manual/src/command-ref/nix-store/opt-common.md
@@ -11,7 +11,7 @@ The following options are allowed for all `nix-store` operations, but may not al
be created in `/nix/var/nix/gcroots/auto/`. For instance,
```console
- $ nix-store --add-root /home/eelco/bla/result -r ...
+ $ nix-store --add-root /home/eelco/bla/result --realise ...
$ ls -l /nix/var/nix/gcroots/auto
lrwxrwxrwx 1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result
diff --git a/doc/manual/src/command-ref/nix-store/query.md b/doc/manual/src/command-ref/nix-store/query.md
index 9f7dbd3e8..cd45a4932 100644
--- a/doc/manual/src/command-ref/nix-store/query.md
+++ b/doc/manual/src/command-ref/nix-store/query.md
@@ -145,7 +145,7 @@ Print the closure (runtime dependencies) of the `svn` program in the
current user environment:
```console
-$ nix-store -qR $(which svn)
+$ nix-store --query --requisites $(which svn)
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
/nix/store/9lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
...
@@ -154,7 +154,7 @@ $ nix-store -qR $(which svn)
Print the build-time dependencies of `svn`:
```console
-$ nix-store -qR $(nix-store -qd $(which svn))
+$ nix-store --query --requisites $(nix-store --query --deriver $(which svn))
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
@@ -168,7 +168,7 @@ the derivation (`-qd`), not the closure of the output path that contains
Show the build-time dependencies as a tree:
```console
-$ nix-store -q --tree $(nix-store -qd $(which svn))
+$ nix-store --query --tree $(nix-store --query --deriver $(which svn))
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
@@ -180,7 +180,7 @@ $ nix-store -q --tree $(nix-store -qd $(which svn))
Show all paths that depend on the same OpenSSL library as `svn`:
```console
-$ nix-store -q --referrers $(nix-store -q --binding openssl $(nix-store -qd $(which svn)))
+$ nix-store --query --referrers $(nix-store --query --binding openssl $(nix-store --query --deriver $(which svn)))
/nix/store/23ny9l9wixx21632y2wi4p585qhva1q8-sylpheed-1.0.0
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3
@@ -191,7 +191,7 @@ Show all paths that directly or indirectly depend on the Glibc (C
library) used by `svn`:
```console
-$ nix-store -q --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
+$ nix-store --query --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
/nix/store/034a6h4vpz9kds5r6kzb9lhh81mscw43-libgnomeprintui-2.8.2
/nix/store/15l3yi0d45prm7a82pcrknxdh6nzmxza-gawk-3.1.4
...
@@ -204,7 +204,7 @@ Make a picture of the runtime dependency graph of the current user
environment:
```console
-$ nix-store -q --graph ~/.nix-profile | dot -Tps > graph.ps
+$ nix-store --query --graph ~/.nix-profile | dot -Tps > graph.ps
$ gv graph.ps
```
@@ -212,7 +212,7 @@ Show every garbage collector root that points to a store path that
depends on `svn`:
```console
-$ nix-store -q --roots $(which svn)
+$ nix-store --query --roots $(which svn)
/nix/var/nix/profiles/default-81-link
/nix/var/nix/profiles/default-82-link
/home/eelco/.local/state/nix/profiles/profile-97-link
diff --git a/doc/manual/src/command-ref/nix-store/read-log.md b/doc/manual/src/command-ref/nix-store/read-log.md
index 4a88e9382..d1ff17891 100644
--- a/doc/manual/src/command-ref/nix-store/read-log.md
+++ b/doc/manual/src/command-ref/nix-store/read-log.md
@@ -27,7 +27,7 @@ substitute, then the log is unavailable.
# Example
```console
-$ nix-store -l $(which ktorrent)
+$ nix-store --read-log $(which ktorrent)
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
unpacking sources
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
diff --git a/doc/manual/src/command-ref/nix-store/realise.md b/doc/manual/src/command-ref/nix-store/realise.md
index f61a20100..6b50d2145 100644
--- a/doc/manual/src/command-ref/nix-store/realise.md
+++ b/doc/manual/src/command-ref/nix-store/realise.md
@@ -99,7 +99,7 @@ This operation is typically used to build [store derivation]s produced by
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
```console
-$ nix-store -r $(nix-instantiate ./test.nix)
+$ nix-store --realise $(nix-instantiate ./test.nix)
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
```
@@ -108,7 +108,7 @@ This is essentially what [`nix-build`](@docroot@/command-ref/nix-build.md) does.
To test whether a previously-built derivation is deterministic:
```console
-$ nix-build '' -A hello --check -K
+$ nix-build '' --attr hello --check -K
```
Use [`nix-store --read-log`](./read-log.md) to show the stderr and stdout of a build:
diff --git a/doc/manual/src/command-ref/nix-store/verify-path.md b/doc/manual/src/command-ref/nix-store/verify-path.md
index 59ffe92a3..927201599 100644
--- a/doc/manual/src/command-ref/nix-store/verify-path.md
+++ b/doc/manual/src/command-ref/nix-store/verify-path.md
@@ -24,6 +24,6 @@ path has changed, and 1 otherwise.
To verify the integrity of the `svn` command and all its dependencies:
```console
-$ nix-store --verify-path $(nix-store -qR $(which svn))
+$ nix-store --verify-path $(nix-store --query --requisites $(which svn))
```
diff --git a/doc/manual/src/command-ref/opt-common.md b/doc/manual/src/command-ref/opt-common.md
index 7a012250d..54c0a1d0d 100644
--- a/doc/manual/src/command-ref/opt-common.md
+++ b/doc/manual/src/command-ref/opt-common.md
@@ -162,11 +162,11 @@ Most Nix commands accept the following command-line options:
}: ...
```
- So if you call this Nix expression (e.g., when you do `nix-env -iA
+ So if you call this Nix expression (e.g., when you do `nix-env --install --attr
pkgname`), the function will be called automatically using the
value [`builtins.currentSystem`](@docroot@/language/builtins.md) for
the `system` argument. You can override this using `--arg`, e.g.,
- `nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
+ `nix-env --install --attr pkgname --arg system \"i686-freebsd\"`. (Note that
since the argument is a Nix string literal, you have to escape the
quotes.)
@@ -199,7 +199,7 @@ Most Nix commands accept the following command-line options:
For `nix-shell`, this option is commonly used to give you a shell in
which you can build the packages returned by the expression. If you
want to get a shell which contain the *built* packages ready for
- use, give your expression to the `nix-shell -p` convenience flag
+ use, give your expression to the `nix-shell --packages ` convenience flag
instead.
- [`-I`](#opt-I) *path*\
diff --git a/doc/manual/src/contributing/hacking.md b/doc/manual/src/contributing/hacking.md
index ca69f076a..b954a2167 100644
--- a/doc/manual/src/contributing/hacking.md
+++ b/doc/manual/src/contributing/hacking.md
@@ -77,7 +77,7 @@ $ nix-shell
To get a shell with one of the other [supported compilation environments](#compilation-environments):
```console
-$ nix-shell -A devShells.x86_64-linux.native-clang11StdenvPackages
+$ nix-shell --attr devShells.x86_64-linux.native-clang11StdenvPackages
```
> **Note**
@@ -139,7 +139,7 @@ $ nix build .#packages.aarch64-linux.default
for flake-enabled Nix, or
```console
-$ nix-build -A packages.aarch64-linux.default
+$ nix-build --attr packages.aarch64-linux.default
```
for classic Nix.
@@ -166,7 +166,7 @@ $ nix build .#nix-ccacheStdenv
for flake-enabled Nix, or
```console
-$ nix-build -A nix-ccacheStdenv
+$ nix-build --attr nix-ccacheStdenv
```
for classic Nix.
diff --git a/doc/manual/src/glossary.md b/doc/manual/src/glossary.md
index eeb19ad50..e142bd415 100644
--- a/doc/manual/src/glossary.md
+++ b/doc/manual/src/glossary.md
@@ -101,11 +101,8 @@
derivation.
- [output-addressed store object]{#gloss-output-addressed-store-object}\
- A store object whose store path hashes its content. This
- includes derivations, the outputs of
- [content-addressed derivations](#gloss-content-addressed-derivation),
- and the outputs of
- [fixed-output derivations](#gloss-fixed-output-derivation).
+ A [store object] whose [store path] is determined by its contents.
+ This includes derivations, the outputs of [content-addressed derivations](#gloss-content-addressed-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
- [substitute]{#gloss-substitute}\
A substitute is a command invocation stored in the [Nix database] that
@@ -163,7 +160,7 @@
build-time dependencies, while the closure of its output path is
equivalent to its runtime dependencies. For correct deployment it
is necessary to deploy whole closures, since otherwise at runtime
- files could be missing. The command `nix-store -qR` prints out
+ files could be missing. The command `nix-store --query --requisites ` prints out
closures of store paths.
As an example, if the [store object] at path `P` contains a [reference]
diff --git a/doc/manual/src/installation/installing-binary.md b/doc/manual/src/installation/installing-binary.md
index 525654d35..ffabb250a 100644
--- a/doc/manual/src/installation/installing-binary.md
+++ b/doc/manual/src/installation/installing-binary.md
@@ -47,12 +47,6 @@ The install script will modify the first writable file from amongst
`NIX_INSTALLER_NO_MODIFY_PROFILE` environment variable before executing
the install script to disable this behaviour.
-You can uninstall Nix simply by running:
-
-```console
-$ rm -rf /nix
-```
-
# Multi User Installation
The multi-user Nix installation creates system users, and a system
@@ -84,155 +78,8 @@ The installer will modify `/etc/bashrc`, and `/etc/zshrc` if they exist.
The installer will first back up these files with a `.backup-before-nix`
extension. The installer will also create `/etc/profile.d/nix.sh`.
-## Uninstalling
-
-### Linux
-
-If you are on Linux with systemd:
-
-1. Remove the Nix daemon service:
-
- ```console
- sudo systemctl stop nix-daemon.service
- sudo systemctl disable nix-daemon.socket nix-daemon.service
- sudo systemctl daemon-reload
- ```
-
-1. Remove systemd service files:
-
- ```console
- sudo rm /etc/systemd/system/nix-daemon.service /etc/systemd/system/nix-daemon.socket
- ```
-
-1. The installer script uses systemd-tmpfiles to create the socket directory.
- You may also want to remove the configuration for that:
-
- ```console
- sudo rm /etc/tmpfiles.d/nix-daemon.conf
- ```
-
-Remove files created by Nix:
-
-```console
-sudo rm -rf /nix /etc/nix /etc/profile/nix.sh ~root/.nix-profile ~root/.nix-defexpr ~root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
-```
-
-Remove build users and their group:
-
-```console
-for i in $(seq 1 32); do
- sudo userdel nixbld$i
-done
-sudo groupdel nixbld
-```
-
-There may also be references to Nix in
-
-- `/etc/profile`
-- `/etc/bashrc`
-- `/etc/zshrc`
-
-which you may remove.
-
-### macOS
-
-1. Edit `/etc/zshrc`, `/etc/bashrc`, and `/etc/bash.bashrc` to remove the lines sourcing
- `nix-daemon.sh`, which should look like this:
-
- ```bash
- # Nix
- if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
- . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
- fi
- # End Nix
- ```
-
- If these files haven't been altered since installing Nix you can simply put
- the backups back in place:
-
- ```console
- sudo mv /etc/zshrc.backup-before-nix /etc/zshrc
- sudo mv /etc/bashrc.backup-before-nix /etc/bashrc
- sudo mv /etc/bash.bashrc.backup-before-nix /etc/bash.bashrc
- ```
-
- This will stop shells from sourcing the file and bringing everything you
- installed using Nix in scope.
-
-2. Stop and remove the Nix daemon services:
-
- ```console
- sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist
- sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist
- sudo launchctl unload /Library/LaunchDaemons/org.nixos.darwin-store.plist
- sudo rm /Library/LaunchDaemons/org.nixos.darwin-store.plist
- ```
-
- This stops the Nix daemon and prevents it from being started next time you
- boot the system.
-
-3. Remove the `nixbld` group and the `_nixbuildN` users:
-
- ```console
- sudo dscl . -delete /Groups/nixbld
- for u in $(sudo dscl . -list /Users | grep _nixbld); do sudo dscl . -delete /Users/$u; done
- ```
-
- This will remove all the build users that no longer serve a purpose.
-
-4. Edit fstab using `sudo vifs` to remove the line mounting the Nix Store
- volume on `/nix`, which looks like
- `UUID= /nix apfs rw,noauto,nobrowse,suid,owners` or
- `LABEL=Nix\040Store /nix apfs rw,nobrowse`. This will prevent automatic
- mounting of the Nix Store volume.
-
-5. Edit `/etc/synthetic.conf` to remove the `nix` line. If this is the only
- line in the file you can remove it entirely, `sudo rm /etc/synthetic.conf`.
- This will prevent the creation of the empty `/nix` directory to provide a
- mountpoint for the Nix Store volume.
-
-6. Remove the files Nix added to your system:
-
- ```console
- sudo rm -rf /etc/nix /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
- ```
-
- This gets rid of any data Nix may have created except for the store which is
- removed next.
-
-7. Remove the Nix Store volume:
-
- ```console
- sudo diskutil apfs deleteVolume /nix
- ```
-
- This will remove the Nix Store volume and everything that was added to the
- store.
-
- If the output indicates that the command couldn't remove the volume, you should
- make sure you don't have an _unmounted_ Nix Store volume. Look for a
- "Nix Store" volume in the output of the following command:
-
- ```console
- diskutil list
- ```
-
- If you _do_ see a "Nix Store" volume, delete it by re-running the diskutil
- deleteVolume command, but replace `/nix` with the store volume's `diskXsY`
- identifier.
-
-> **Note**
->
-> After you complete the steps here, you will still have an empty `/nix`
-> directory. This is an expected sign of a successful uninstall. The empty
-> `/nix` directory will disappear the next time you reboot.
->
-> You do not have to reboot to finish uninstalling Nix. The uninstall is
-> complete. macOS (Catalina+) directly controls root directories and its
-> read-only root will prevent you from manually deleting the empty `/nix`
-> mountpoint.
-
# macOS Installation
+
[]{#sect-macos-installation-change-store-prefix}[]{#sect-macos-installation-encrypted-volume}[]{#sect-macos-installation-symlink}[]{#sect-macos-installation-recommended-notes}
@@ -281,19 +128,16 @@ this to run the installer, but it may help if you run into trouble:
# Installing a pinned Nix version from a URL
-NixOS.org hosts version-specific installation URLs for all Nix versions
-since 1.11.16, at `https://releases.nixos.org/nix/nix-version/install`.
+Version-specific installation URLs for all Nix versions
+since 1.11.16 can be found at [releases.nixos.org](https://releases.nixos.org/?prefix=nix/).
+The corresponding SHA-256 hash can be found in the directory for the given version.
-These install scripts can be used the same as the main NixOS.org
-installation script:
+These install scripts can be used the same as usual:
```console
-$ curl -L https://nixos.org/nix/install | sh
+$ curl -L https://releases.nixos.org/nix/nix-/install | sh
```
-In the same directory of the install script are sha256 sums, and gpg
-signature files.
-
# Installing from a binary tarball
You can also download a binary tarball that contains Nix and all its
diff --git a/doc/manual/src/installation/uninstall.md b/doc/manual/src/installation/uninstall.md
new file mode 100644
index 000000000..9ead5e53c
--- /dev/null
+++ b/doc/manual/src/installation/uninstall.md
@@ -0,0 +1,148 @@
+# Uninstalling Nix
+
+## Single User
+
+If you have a [single-user installation](./installing-binary.md#single-user-installation) of Nix, uninstall it by running:
+
+```console
+$ rm -rf /nix
+```
+
+## Multi User
+
+Removing a [multi-user installation](./installing-binary.md#multi-user-installation) of Nix is more involved, and depends on the operating system.
+
+### Linux
+
+If you are on Linux with systemd:
+
+1. Remove the Nix daemon service:
+
+ ```console
+ sudo systemctl stop nix-daemon.service
+ sudo systemctl disable nix-daemon.socket nix-daemon.service
+ sudo systemctl daemon-reload
+ ```
+
+Remove files created by Nix:
+
+```console
+sudo rm -rf /etc/nix /etc/profile.d/nix.sh /etc/tmpfiles.d/nix-daemon.conf /nix ~root/.nix-channels ~root/.nix-defexpr ~root/.nix-profile
+```
+
+Remove build users and their group:
+
+```console
+for i in $(seq 1 32); do
+ sudo userdel nixbld$i
+done
+sudo groupdel nixbld
+```
+
+There may also be references to Nix in
+
+- `/etc/bash.bashrc`
+- `/etc/bashrc`
+- `/etc/profile`
+- `/etc/zsh/zshrc`
+- `/etc/zshrc`
+
+which you may remove.
+
+### macOS
+
+1. Edit `/etc/zshrc`, `/etc/bashrc`, and `/etc/bash.bashrc` to remove the lines sourcing `nix-daemon.sh`, which should look like this:
+
+ ```bash
+ # Nix
+ if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
+ . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
+ fi
+ # End Nix
+ ```
+
+ If these files haven't been altered since installing Nix you can simply put
+ the backups back in place:
+
+ ```console
+ sudo mv /etc/zshrc.backup-before-nix /etc/zshrc
+ sudo mv /etc/bashrc.backup-before-nix /etc/bashrc
+ sudo mv /etc/bash.bashrc.backup-before-nix /etc/bash.bashrc
+ ```
+
+ This will stop shells from sourcing the file and bringing everything you
+ installed using Nix in scope.
+
+2. Stop and remove the Nix daemon services:
+
+ ```console
+ sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist
+ sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist
+ sudo launchctl unload /Library/LaunchDaemons/org.nixos.darwin-store.plist
+ sudo rm /Library/LaunchDaemons/org.nixos.darwin-store.plist
+ ```
+
+ This stops the Nix daemon and prevents it from being started next time you
+ boot the system.
+
+3. Remove the `nixbld` group and the `_nixbuildN` users:
+
+ ```console
+ sudo dscl . -delete /Groups/nixbld
+ for u in $(sudo dscl . -list /Users | grep _nixbld); do sudo dscl . -delete /Users/$u; done
+ ```
+
+ This will remove all the build users that no longer serve a purpose.
+
+4. Edit fstab using `sudo vifs` to remove the line mounting the Nix Store
+ volume on `/nix`, which looks like
+ `UUID= /nix apfs rw,noauto,nobrowse,suid,owners` or
+ `LABEL=Nix\040Store /nix apfs rw,nobrowse`. This will prevent automatic
+ mounting of the Nix Store volume.
+
+5. Edit `/etc/synthetic.conf` to remove the `nix` line. If this is the only
+ line in the file you can remove it entirely, `sudo rm /etc/synthetic.conf`.
+ This will prevent the creation of the empty `/nix` directory to provide a
+ mountpoint for the Nix Store volume.
+
+6. Remove the files Nix added to your system:
+
+ ```console
+ sudo rm -rf /etc/nix /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
+ ```
+
+ This gets rid of any data Nix may have created except for the store which is
+ removed next.
+
+7. Remove the Nix Store volume:
+
+ ```console
+ sudo diskutil apfs deleteVolume /nix
+ ```
+
+ This will remove the Nix Store volume and everything that was added to the
+ store.
+
+ If the output indicates that the command couldn't remove the volume, you should
+ make sure you don't have an _unmounted_ Nix Store volume. Look for a
+ "Nix Store" volume in the output of the following command:
+
+ ```console
+ diskutil list
+ ```
+
+ If you _do_ see a "Nix Store" volume, delete it by re-running the diskutil
+ deleteVolume command, but replace `/nix` with the store volume's `diskXsY`
+ identifier.
+
+> **Note**
+>
+> After you complete the steps here, you will still have an empty `/nix`
+> directory. This is an expected sign of a successful uninstall. The empty
+> `/nix` directory will disappear the next time you reboot.
+>
+> You do not have to reboot to finish uninstalling Nix. The uninstall is
+> complete. macOS (Catalina+) directly controls root directories and its
+> read-only root will prevent you from manually deleting the empty `/nix`
+> mountpoint.
+
diff --git a/doc/manual/src/installation/upgrading.md b/doc/manual/src/installation/upgrading.md
index 24efc4681..6d09f54d8 100644
--- a/doc/manual/src/installation/upgrading.md
+++ b/doc/manual/src/installation/upgrading.md
@@ -2,13 +2,13 @@
Multi-user Nix users on macOS can upgrade Nix by running: `sudo -i sh -c
'nix-channel --update &&
-nix-env -iA nixpkgs.nix &&
+nix-env --install --attr nixpkgs.nix &&
launchctl remove org.nixos.nix-daemon &&
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'`
Single-user installations of Nix should run this: `nix-channel --update;
-nix-env -iA nixpkgs.nix nixpkgs.cacert`
+nix-env --install --attr nixpkgs.nix nixpkgs.cacert`
Multi-user Nix users on Linux should run this with sudo: `nix-channel
---update; nix-env -iA nixpkgs.nix nixpkgs.cacert; systemctl
+--update; nix-env --install --attr nixpkgs.nix nixpkgs.cacert; systemctl
daemon-reload; systemctl restart nix-daemon`
diff --git a/doc/manual/src/introduction.md b/doc/manual/src/introduction.md
index b54346db8..76489bc1b 100644
--- a/doc/manual/src/introduction.md
+++ b/doc/manual/src/introduction.md
@@ -76,7 +76,7 @@ there after an upgrade. This means that you can _roll back_ to the
old version:
```console
-$ nix-env --upgrade -A nixpkgs.some-package
+$ nix-env --upgrade --attr nixpkgs.some-package
$ nix-env --rollback
```
@@ -122,7 +122,7 @@ Nix expressions generally describe how to build a package from
source, so an installation action like
```console
-$ nix-env --install -A nixpkgs.firefox
+$ nix-env --install --attr nixpkgs.firefox
```
_could_ cause quite a bit of build activity, as not only Firefox but
@@ -158,7 +158,7 @@ Pan newsreader, as described by [its
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
```console
-$ nix-shell '' -A pan
+$ nix-shell '' --attr pan
```
You’re then dropped into a shell where you can edit, build and test
diff --git a/doc/manual/src/language/builtin-constants.md b/doc/manual/src/language/builtin-constants.md
index 78d066a82..e6bc7e915 100644
--- a/doc/manual/src/language/builtin-constants.md
+++ b/doc/manual/src/language/builtin-constants.md
@@ -1,20 +1,43 @@
# Built-in Constants
-Here are the constants built into the Nix expression evaluator:
+These constants are built into the Nix language evaluator:
- - `builtins`\
- The set `builtins` contains all the built-in functions and values.
- You can use `builtins` to test for the availability of features in
- the Nix installation, e.g.,
-
- ```nix
- if builtins ? getEnv then builtins.getEnv "PATH" else ""
- ```
-
- This allows a Nix expression to fall back gracefully on older Nix
- installations that don’t have the desired built-in function.
+- [`builtins`]{#builtins-builtins} (attribute set)
- - [`builtins.currentSystem`]{#builtins-currentSystem}\
- The built-in value `currentSystem` evaluates to the Nix platform
- identifier for the Nix installation on which the expression is being
- evaluated, such as `"i686-linux"` or `"x86_64-darwin"`.
+ Contains all the [built-in functions](./builtins.md) and values, in order to avoid polluting the global scope.
+
+ Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
+
+ ```nix
+ if builtins ? getEnv then builtins.getEnv "PATH" else ""
+ ```
+
+- [`builtins.currentSystem`]{#builtins-currentSystem} (string)
+
+ The built-in value `currentSystem` evaluates to the Nix platform
+ identifier for the Nix installation on which the expression is being
+ evaluated, such as `"i686-linux"` or `"x86_64-darwin"`.
+
+ Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
+
+- [`builtins.currentTime`]{#builtins-currentTime} (integer)
+
+ Return the [Unix time](https://en.wikipedia.org/wiki/Unix_time) at first evaluation.
+ Repeated references to that name will re-use the initially obtained value.
+
+ Example:
+
+ ```console
+ $ nix repl
+ Welcome to Nix 2.15.1 Type :? for help.
+
+ nix-repl> builtins.currentTime
+ 1683705525
+
+ nix-repl> builtins.currentTime
+ 1683705525
+ ```
+
+ The [store path](@docroot@/glossary.md#gloss-store-path) of a derivation depending on `currentTime` will differ for each evaluation.
+
+ Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
diff --git a/doc/manual/src/language/builtins-prefix.md b/doc/manual/src/language/builtins-prefix.md
index c631a8453..35e3dccc3 100644
--- a/doc/manual/src/language/builtins-prefix.md
+++ b/doc/manual/src/language/builtins-prefix.md
@@ -1,16 +1,16 @@
# Built-in Functions
-This section lists the functions built into the Nix expression
-evaluator. (The built-in function `derivation` is discussed above.)
-Some built-ins, such as `derivation`, are always in scope of every Nix
-expression; you can just access them right away. But to prevent
-polluting the namespace too much, most built-ins are not in
-scope. Instead, you can access them through the `builtins` built-in
-value, which is a set that contains all built-in functions and values.
-For instance, `derivation` is also available as `builtins.derivation`.
+This section lists the functions built into the Nix language evaluator.
+All built-in functions are available through the global [`builtins`](./builtin-constants.md#builtins-builtins) constant.
+
+For convenience, some built-ins are can be accessed directly:
+
+- [`derivation`](#builtins-derivation)
+- [`import`](#builtins-import)
+- [`abort`](#builtins-abort)
+- [`throw`](#builtins-throw)
- derivation attrs
;
- builtins.derivation attrs
+ derivation attrs
derivation is described in
its own section.
diff --git a/doc/manual/src/language/constructs.md b/doc/manual/src/language/constructs.md
index 1c01f2cc7..c53eb8889 100644
--- a/doc/manual/src/language/constructs.md
+++ b/doc/manual/src/language/constructs.md
@@ -2,8 +2,11 @@
## Recursive sets
-Recursive sets are just normal sets, but the attributes can refer to
-each other. For example,
+Recursive sets are like normal [attribute sets](./values.md#attribute-set), but the attributes can refer to each other.
+
+> *rec-attrset* = `rec {` [ *name* `=` *expr* `;` `]`... `}`
+
+Example:
```nix
rec {
@@ -12,7 +15,9 @@ rec {
}.x
```
-evaluates to `123`. Note that without `rec` the binding `x = y;` would
+This evaluates to `123`.
+
+Note that without `rec` the binding `x = y;` would
refer to the variable `y` in the surrounding scope, if one exists, and
would be invalid if no such variable exists. That is, in a normal
(non-recursive) set, attributes are not added to the lexical scope; in a
@@ -33,7 +38,10 @@ will crash with an `infinite recursion encountered` error message.
## Let-expressions
A let-expression allows you to define local variables for an expression.
-For instance,
+
+> *let-in* = `let` [ *identifier* = *expr* ]... `in` *expr*
+
+Example:
```nix
let
@@ -42,18 +50,19 @@ let
in x + y
```
-evaluates to `"foobar"`.
+This evaluates to `"foobar"`.
## Inheriting attributes
-When defining a set or in a let-expression it is often convenient to
-copy variables from the surrounding lexical scope (e.g., when you want
-to propagate attributes). This can be shortened using the `inherit`
-keyword. For instance,
+When defining an [attribute set](./values.md#attribute-set) or in a [let-expression](#let-expressions) it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes).
+This can be shortened using the `inherit` keyword.
+
+Example:
```nix
let x = 123; in
-{ inherit x;
+{
+ inherit x;
y = 456;
}
```
@@ -62,15 +71,23 @@ is equivalent to
```nix
let x = 123; in
-{ x = x;
+{
+ x = x;
y = 456;
}
```
-and both evaluate to `{ x = 123; y = 456; }`. (Note that this works
-because `x` is added to the lexical scope by the `let` construct.) It is
-also possible to inherit attributes from another set. For instance, in
-this fragment from `all-packages.nix`,
+and both evaluate to `{ x = 123; y = 456; }`.
+
+> **Note**
+>
+> This works because `x` is added to the lexical scope by the `let` construct.
+
+It is also possible to inherit attributes from another attribute set.
+
+Example:
+
+In this fragment from `all-packages.nix`,
```nix
graphviz = (import ../tools/graphics/graphviz) {
diff --git a/doc/manual/src/language/operators.md b/doc/manual/src/language/operators.md
index a07d976ad..f8382ae19 100644
--- a/doc/manual/src/language/operators.md
+++ b/doc/manual/src/language/operators.md
@@ -35,17 +35,14 @@
## Attribute selection
+> *attrset* `.` *attrpath* \[ `or` *expr* \]
+
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
-If the attribute doesn’t exist, return *value* if provided, otherwise abort evaluation.
+If the attribute doesn’t exist, return the *expr* after `or` if provided, otherwise abort evaluation.
-
+An attribute path is a dot-separated list of [attribute names](./values.md#attribute-set).
-An attribute path is a dot-separated list of attribute names.
-An attribute name can be an identifier or a string.
-
-> *attrpath* = *name* [ `.` *name* ]... \
-> *name* = *identifier* | *string* \
-> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
+> *attrpath* = *name* [ `.` *name* ]...
[Attribute selection]: #attribute-selection
diff --git a/doc/manual/src/language/values.md b/doc/manual/src/language/values.md
index c85124278..2ae3e143a 100644
--- a/doc/manual/src/language/values.md
+++ b/doc/manual/src/language/values.md
@@ -164,9 +164,17 @@ Note that lists are only lazy in values, and they are strict in length.
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
+An attribute name can be an identifier or a [string](#string).
+An identifier must start with a letter (`a-z`, `A-Z`) or underscore (`_`), and can otherwise contain letters (`a-z`, `A-Z`), numbers (`0-9`), underscores (`_`), apostrophes (`'`), or dashes (`-`).
+
+> *name* = *identifier* | *string* \
+> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
+
Names and values are separated by an equal sign (`=`).
Each value is an arbitrary expression terminated by a semicolon (`;`).
+> *attrset* = `{` [ *name* `=` *expr* `;` `]`... `}`
+
Attributes can appear in any order.
An attribute name may only occur once.
@@ -182,21 +190,29 @@ Example:
This defines a set with attributes named `x`, `text`, `y`.
-Attributes can be selected from a set using the `.` operator. For
-instance,
+Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection).
+
+Example:
```nix
{ a = "Foo"; b = "Bar"; }.a
```
-evaluates to `"Foo"`. It is possible to provide a default value in an
-attribute selection using the `or` keyword. For example,
+This evaluates to `"Foo"`.
+
+It is possible to provide a default value in an attribute selection using the `or` keyword.
+
+Example:
```nix
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
```
-will evaluate to `"Xyzzy"` because there is no `c` attribute in the set.
+```nix
+{ a = "Foo"; b = "Bar"; }.c.d.e.f.g or "Xyzzy"
+```
+
+will both evaluate to `"Xyzzy"` because there is no `c` attribute in the set.
You can use arbitrary double-quoted strings as attribute names:
diff --git a/doc/manual/src/package-management/basic-package-mgmt.md b/doc/manual/src/package-management/basic-package-mgmt.md
index 5f1d7a89c..6b86e763e 100644
--- a/doc/manual/src/package-management/basic-package-mgmt.md
+++ b/doc/manual/src/package-management/basic-package-mgmt.md
@@ -47,7 +47,7 @@ $ nix-channel --update
You can view the set of available packages in Nixpkgs:
```console
-$ nix-env -qaP
+$ nix-env --query --available --attr-path
nixpkgs.aterm aterm-2.2
nixpkgs.bash bash-3.0
nixpkgs.binutils binutils-2.15
@@ -65,7 +65,7 @@ If you downloaded Nixpkgs yourself, or if you checked it out from GitHub,
then you need to pass the path to your Nixpkgs tree using the `-f` flag:
```console
-$ nix-env -qaPf /path/to/nixpkgs
+$ nix-env --query --available --attr-path --file /path/to/nixpkgs
aterm aterm-2.2
bash bash-3.0
…
@@ -77,7 +77,7 @@ Nixpkgs.
You can filter the packages by name:
```console
-$ nix-env -qaP firefox
+$ nix-env --query --available --attr-path firefox
nixpkgs.firefox-esr firefox-91.3.0esr
nixpkgs.firefox firefox-94.0.1
```
@@ -85,7 +85,7 @@ nixpkgs.firefox firefox-94.0.1
and using regular expressions:
```console
-$ nix-env -qaP 'firefox.*'
+$ nix-env --query --available --attr-path 'firefox.*'
```
It is also possible to see the *status* of available packages, i.e.,
@@ -93,7 +93,7 @@ whether they are installed into the user environment and/or present in
the system:
```console
-$ nix-env -qaPs
+$ nix-env --query --available --attr-path --status
…
-PS nixpkgs.bash bash-3.0
--S nixpkgs.binutils binutils-2.15
@@ -110,10 +110,10 @@ which is Nix’s mechanism for doing binary deployment. It just means that
Nix knows that it can fetch a pre-built package from somewhere
(typically a network server) instead of building it locally.
-You can install a package using `nix-env -iA`. For instance,
+You can install a package using `nix-env --install --attr `. For instance,
```console
-$ nix-env -iA nixpkgs.subversion
+$ nix-env --install --attr nixpkgs.subversion
```
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
@@ -143,14 +143,14 @@ instead of the attribute path, as `nix-env` does not record which attribute
was used for installing:
```console
-$ nix-env -e subversion
+$ nix-env --uninstall subversion
```
Upgrading to a new version is just as easy. If you have a new release of
Nix Packages, you can do:
```console
-$ nix-env -uA nixpkgs.subversion
+$ nix-env --upgrade --attr nixpkgs.subversion
```
This will *only* upgrade Subversion if there is a “newer” version in the
@@ -163,15 +163,15 @@ whatever version is in the Nix expressions, use `-i` instead of `-u`;
You can also upgrade all packages for which there are newer versions:
```console
-$ nix-env -u
+$ nix-env --upgrade
```
Sometimes it’s useful to be able to ask what `nix-env` would do, without
actually doing it. For instance, to find out what packages would be
-upgraded by `nix-env -u`, you can do
+upgraded by `nix-env --upgrade `, you can do
```console
-$ nix-env -u --dry-run
+$ nix-env --upgrade --dry-run
(dry run; not doing anything)
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
upgrading `graphviz-1.10' to `graphviz-1.12'
diff --git a/doc/manual/src/package-management/binary-cache-substituter.md b/doc/manual/src/package-management/binary-cache-substituter.md
index 5befad9f8..855eaf470 100644
--- a/doc/manual/src/package-management/binary-cache-substituter.md
+++ b/doc/manual/src/package-management/binary-cache-substituter.md
@@ -9,7 +9,7 @@ The daemon that handles binary cache requests via HTTP, `nix-serve`, is
not part of the Nix distribution, but you can install it from Nixpkgs:
```console
-$ nix-env -iA nixpkgs.nix-serve
+$ nix-env --install --attr nixpkgs.nix-serve
```
You can then start the server, listening for HTTP connections on
@@ -35,7 +35,7 @@ On the client side, you can tell Nix to use your binary cache using
`--substituters`, e.g.:
```console
-$ nix-env -iA nixpkgs.firefox --substituters http://avalon:8080/
+$ nix-env --install --attr nixpkgs.firefox --substituters http://avalon:8080/
```
The option `substituters` tells Nix to use this binary cache in
diff --git a/doc/manual/src/package-management/channels.md b/doc/manual/src/package-management/channels.md
index 93c8b41a6..8e4da180b 100644
--- a/doc/manual/src/package-management/channels.md
+++ b/doc/manual/src/package-management/channels.md
@@ -43,7 +43,7 @@ operations (via the symlink `~/.nix-defexpr/channels`). Consequently,
you can then say
```console
-$ nix-env -u
+$ nix-env --upgrade
```
to upgrade all packages in your profile to the latest versions available
diff --git a/doc/manual/src/package-management/copy-closure.md b/doc/manual/src/package-management/copy-closure.md
index d3fac4d76..14326298b 100644
--- a/doc/manual/src/package-management/copy-closure.md
+++ b/doc/manual/src/package-management/copy-closure.md
@@ -15,7 +15,7 @@ With `nix-store
path (that is, the path and all its dependencies) to a file, and then
unpack that file into another Nix store. For example,
- $ nix-store --export $(nix-store -qR $(type -p firefox)) > firefox.closure
+ $ nix-store --export $(nix-store --query --requisites $(type -p firefox)) > firefox.closure
writes the closure of Firefox to a file. You can then copy this file to
another machine and install the closure:
@@ -27,7 +27,7 @@ store are ignored. It is also possible to pipe the export into another
command, e.g. to copy and install a closure directly to/on another
machine:
- $ nix-store --export $(nix-store -qR $(type -p firefox)) | bzip2 | \
+ $ nix-store --export $(nix-store --query --requisites $(type -p firefox)) | bzip2 | \
ssh alice@itchy.example.org "bunzip2 | nix-store --import"
However, `nix-copy-closure` is generally more efficient because it only
diff --git a/doc/manual/src/package-management/profiles.md b/doc/manual/src/package-management/profiles.md
index d1a2580d4..1d9e672a8 100644
--- a/doc/manual/src/package-management/profiles.md
+++ b/doc/manual/src/package-management/profiles.md
@@ -39,7 +39,7 @@ just Subversion 1.1.2 (arrows in the figure indicate symlinks). This
would be what we would obtain if we had done
```console
-$ nix-env -iA nixpkgs.subversion
+$ nix-env --install --attr nixpkgs.subversion
```
on a set of Nix expressions that contained Subversion 1.1.2.
@@ -54,7 +54,7 @@ environment is generated based on the current one. For instance,
generation 43 was created from generation 42 when we did
```console
-$ nix-env -iA nixpkgs.subversion nixpkgs.firefox
+$ nix-env --install --attr nixpkgs.subversion nixpkgs.firefox
```
on a set of Nix expressions that contained Firefox and a new version of
@@ -127,7 +127,7 @@ All `nix-env` operations work on the profile pointed to by
(abbreviation `-p`):
```console
-$ nix-env -p /nix/var/nix/profiles/other-profile -iA nixpkgs.subversion
+$ nix-env --profile /nix/var/nix/profiles/other-profile --install --attr nixpkgs.subversion
```
This will *not* change the `~/.nix-profile` symlink.
diff --git a/doc/manual/src/package-management/ssh-substituter.md b/doc/manual/src/package-management/ssh-substituter.md
index c59933f61..7014c3cc8 100644
--- a/doc/manual/src/package-management/ssh-substituter.md
+++ b/doc/manual/src/package-management/ssh-substituter.md
@@ -6,7 +6,7 @@ automatically fetching any store paths in Firefox’s closure if they are
available on the server `avalon`:
```console
-$ nix-env -iA nixpkgs.firefox --substituters ssh://alice@avalon
+$ nix-env --install --attr nixpkgs.firefox --substituters ssh://alice@avalon
```
This works similar to the binary cache substituter that Nix usually
@@ -25,7 +25,7 @@ You can also copy the closure of some store path, without installing it
into your profile, e.g.
```console
-$ nix-store -r /nix/store/m85bxg…-firefox-34.0.5 --substituters
+$ nix-store --realise /nix/store/m85bxg…-firefox-34.0.5 --substituters
ssh://alice@avalon
```
diff --git a/doc/manual/src/release-notes/rl-2.16.md b/doc/manual/src/release-notes/rl-2.16.md
new file mode 100644
index 000000000..97b40d0b8
--- /dev/null
+++ b/doc/manual/src/release-notes/rl-2.16.md
@@ -0,0 +1,8 @@
+# Release 2.16 (2023-05-31)
+
+* Speed-up of downloads from binary caches.
+ The number of parallel downloads (also known as substitutions) has been separated from the [`--max-jobs` setting](../command-ref/conf-file.md#conf-max-jobs).
+ The new setting is called [`max-substitution-jobs`](../command-ref/conf-file.md#conf-max-substitution-jobs).
+ The number of parallel downloads is now set to 16 by default (previously, the default was 1 due to the coupling to build jobs).
+
+* The function [`builtins.replaceStrings`](@docroot@/language/builtins.md#builtins-replaceStrings) is now lazy in the value of its second argument `to`. That is, `to` is only evaluated when its corresponding pattern in `from` is matched in the string `s`.
diff --git a/docker.nix b/docker.nix
index 52199af66..bd16b71cd 100644
--- a/docker.nix
+++ b/docker.nix
@@ -190,6 +190,12 @@ let
cp -a ${rootEnv}/* $out/
ln -s ${manifest} $out/manifest.nix
'';
+ flake-registry-path = if (flake-registry == null) then
+ null
+ else if (builtins.readFileType (toString flake-registry)) == "directory" then
+ "${flake-registry}/flake-registry.json"
+ else
+ flake-registry;
in
pkgs.runCommand "base-system"
{
@@ -202,7 +208,7 @@ let
];
allowSubstitutes = false;
preferLocalBuild = true;
- } ''
+ } (''
env
set -x
mkdir -p $out/etc
@@ -249,15 +255,15 @@ let
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
- '' + (lib.optionalString (flake-registry != null) ''
+ '' + (lib.optionalString (flake-registry-path != null) ''
nixCacheDir="/root/.cache/nix"
mkdir -p $out$nixCacheDir
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
- ln -s ${flake-registry}/flake-registry.json $out$globalFlakeRegistryPath
+ ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
mkdir -p $out/nix/var/nix/gcroots/auto
rootName=$(${pkgs.nix}/bin/nix --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
- '');
+ ''));
in
pkgs.dockerTools.buildLayeredImageWithNixDb {
diff --git a/maintainers/README.md b/maintainers/README.md
index 618bfb4e4..d13349438 100644
--- a/maintainers/README.md
+++ b/maintainers/README.md
@@ -42,12 +42,12 @@ The team meets twice a week:
- Discussion meeting: [Fridays 13:00-14:00 CET](https://calendar.google.com/calendar/event?eid=MHNtOGVuNWtrZXNpZHR2bW1sM3QyN2ZjaGNfMjAyMjExMjVUMTIwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn)
- 1. Triage issues and pull requests from the _No Status_ column (30 min)
- 2. Discuss issues and pull requests from the _To discuss_ column (30 min)
+ 1. Triage issues and pull requests from the [No Status](#no-status) column (30 min)
+ 2. Discuss issues and pull requests from the [To discuss](#to-discuss) column (30 min)
- Work meeting: [Mondays 13:00-15:00 CET](https://calendar.google.com/calendar/event?eid=NTM1MG1wNGJnOGpmOTZhYms3bTB1bnY5cWxfMjAyMjExMjFUMTIwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn)
- 1. Code review on pull requests from _In review_.
+ 1. Code review on pull requests from [In review](#in-review).
2. Other chores and tasks.
Meeting notes are collected on a [collaborative scratchpad](https://pad.lassul.us/Cv7FpYx-Ri-4VjUykQOLAw), and published on Discourse under the [Nix category](https://discourse.nixos.org/c/dev/nix/50).
@@ -58,64 +58,74 @@ The team uses a [GitHub project board](https://github.com/orgs/NixOS/projects/19
Items on the board progress through the following states:
-- No Status
+### No Status
- During the discussion meeting, the team triages new items.
- To be considered, issues and pull requests must have a high-level description to provide the whole team with the necessary context at a glance.
+During the discussion meeting, the team triages new items.
+To be considered, issues and pull requests must have a high-level description to provide the whole team with the necessary context at a glance.
- On every meeting, at least one item from each of the following categories is inspected:
+On every meeting, at least one item from each of the following categories is inspected:
- 1. [critical](https://github.com/NixOS/nix/labels/critical)
- 2. [security](https://github.com/NixOS/nix/labels/security)
- 3. [regression](https://github.com/NixOS/nix/labels/regression)
- 4. [bug](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc)
- 5. [tests of existing functionality](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Atests+-label%3Afeature+sort%3Areactions-%2B1-desc)
+1. [critical](https://github.com/NixOS/nix/labels/critical)
+2. [security](https://github.com/NixOS/nix/labels/security)
+3. [regression](https://github.com/NixOS/nix/labels/regression)
+4. [bug](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc)
+5. [tests of existing functionality](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Atests+-label%3Afeature+sort%3Areactions-%2B1-desc)
- - [oldest pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc)
- - [most popular pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Areactions-%2B1-desc)
- - [oldest issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc)
- - [most popular issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc)
+- [oldest pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc)
+- [most popular pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Areactions-%2B1-desc)
+- [oldest issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc)
+- [most popular issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc)
- Team members can also add pull requests or issues they would like the whole team to consider.
+Team members can also add pull requests or issues they would like the whole team to consider.
+To ensure process quality and reliability, all non-trivial pull requests must be triaged before merging.
- If there is disagreement on the general idea behind an issue or pull request, it is moved to _To discuss_, otherwise to _In review_.
+If there is disagreement on the general idea behind an issue or pull request, it is moved to [To discuss](#to-discuss).
+Otherwise, the issue or pull request in questions get the label [`idea approved`](https://github.com/NixOS/nix/labels/idea%20approved).
+For issues this means that an implementation is welcome and will be prioritised for review.
+For pull requests this means that:
+- Unfinished work is encouraged to be continued.
+- A reviewer is assigned to take responsibility for getting the pull request merged.
+ The item is moved to the [Assigned](#assigned) column.
+- If needed, the team can decide to do a collarorative review.
+ Then the item is moved to the [In review](#in-review) column, and review session is scheduled.
- To ensure process quality and reliability, all non-trivial pull requests must be triaged before merging.
- What constitutes a trivial pull request is up to maintainers' judgement.
+What constitutes a trivial pull request is up to maintainers' judgement.
-- To discuss
+### To discuss
- Pull requests and issues that are deemed important and controversial are discussed by the team during discussion meetings.
+Pull requests and issues that are deemed important and controversial are discussed by the team during discussion meetings.
- This may be where the merit of the change itself or the implementation strategy is contested by a team member.
+This may be where the merit of the change itself or the implementation strategy is contested by a team member.
- As a general guideline, the order of items is determined as follows:
+As a general guideline, the order of items is determined as follows:
- - Prioritise pull requests over issues
+- Prioritise pull requests over issues
- Contributors who took the time to implement concrete change proposals should not wait indefinitely.
+ Contributors who took the time to implement concrete change proposals should not wait indefinitely.
- - Prioritise fixing bugs and testing over documentation, improvements or new features
+- Prioritise fixing bugs and testing over documentation, improvements or new features
- The team values stability and accessibility higher than raw functionality.
+ The team values stability and accessibility higher than raw functionality.
- - Interleave issues and PRs
+- Interleave issues and PRs
- This way issues without attempts at a solution get a chance to get addressed.
+ This way issues without attempts at a solution get a chance to get addressed.
-- In review
+### In review
- Pull requests in this column are reviewed together during work meetings.
- This is both for spreading implementation knowledge and for establishing common values in code reviews.
+Pull requests in this column are reviewed together during work meetings.
+This is both for spreading implementation knowledge and for establishing common values in code reviews.
- When the overall direction is agreed upon, even when further changes are required, the pull request is assigned to one team member.
+When the overall direction is agreed upon, even when further changes are required, the pull request is assigned to one team member.
-- Assigned for merging
+### Assigned
- One team member is assigned to each of these pull requests.
- They will communicate with the authors, and make the final approval once all remaining issues are addressed.
+One team member is assigned to each of these pull requests.
+They will communicate with the authors, and make the final approval once all remaining issues are addressed.
- If more substantive issues arise, the assignee can move the pull request back to _To discuss_ to involve the team again.
+If more substantive issues arise, the assignee can move the pull request back to [To discuss](#to-discuss) or [In review](#in-review) to involve the team again.
+
+### Flowchart
The process is illustrated in the following diagram:
diff --git a/maintainers/release-process.md b/maintainers/release-process.md
index ec9e96489..d85266b81 100644
--- a/maintainers/release-process.md
+++ b/maintainers/release-process.md
@@ -119,8 +119,7 @@ release:
TODO: This script requires the right AWS credentials. Document.
TODO: This script currently requires a
- `/home/eelco/Dev/nix-pristine` and
- `/home/eelco/Dev/nixpkgs-pristine`.
+ `/home/eelco/Dev/nix-pristine`.
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
@@ -141,7 +140,7 @@ release:
$ git checkout master
$ git pull
$ NEW_VERSION=2.13.0
- $ echo -n $NEW_VERSION > .version
+ $ echo $NEW_VERSION > .version
$ git checkout -b bump-$NEW_VERSION
$ git commit -a -m 'Bump version'
$ git push --set-upstream origin bump-$NEW_VERSION
diff --git a/maintainers/upload-release.pl b/maintainers/upload-release.pl
index 77469148a..ebc536f12 100755
--- a/maintainers/upload-release.pl
+++ b/maintainers/upload-release.pl
@@ -15,7 +15,6 @@ my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n";
my $releasesBucketName = "nix-releases";
my $channelsBucketName = "nix-channels";
-my $nixpkgsDir = "/home/eelco/Dev/nixpkgs-pristine";
my $TMPDIR = $ENV{'TMPDIR'} // "/tmp";
@@ -81,6 +80,38 @@ my $s3_us = Net::Amazon::S3->new(
my $channelsBucket = $s3_us->bucket($channelsBucketName) or die;
+sub getStorePath {
+ my ($jobName, $output) = @_;
+ my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
+ return $buildInfo->{buildoutputs}->{$output or "out"}->{path} or die "cannot get store path for '$jobName'";
+}
+
+sub copyManual {
+ my $manual = getStorePath("build.x86_64-linux", "doc");
+ print "$manual\n";
+
+ my $manualNar = "$tmpDir/$releaseName-manual.nar.xz";
+ print "$manualNar\n";
+
+ unless (-e $manualNar) {
+ system("NIX_REMOTE=$binaryCache nix store dump-path '$manual' | xz > '$manualNar'.tmp") == 0
+ or die "unable to fetch $manual\n";
+ rename("$manualNar.tmp", $manualNar) or die;
+ }
+
+ unless (-e "$tmpDir/manual") {
+ system("xz -d < '$manualNar' | nix-store --restore $tmpDir/manual.tmp") == 0
+ or die "unable to unpack $manualNar\n";
+ rename("$tmpDir/manual.tmp/share/doc/nix/manual", "$tmpDir/manual") or die;
+ system("rm -rf '$tmpDir/manual.tmp'") == 0 or die;
+ }
+
+ system("aws s3 sync '$tmpDir/manual' s3://$releasesBucketName/$releaseDir/manual") == 0
+ or die "syncing manual to S3\n";
+}
+
+copyManual;
+
sub downloadFile {
my ($jobName, $productNr, $dstName) = @_;
@@ -180,9 +211,20 @@ if ($isLatest) {
system("docker manifest push nixos/nix:latest") == 0 or die;
}
+# Upload nix-fallback-paths.nix.
+write_file("$tmpDir/fallback-paths.nix",
+ "{\n" .
+ " x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
+ " i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
+ " aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
+ " x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
+ " aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
+ "}\n");
+
# Upload release files to S3.
for my $fn (glob "$tmpDir/*") {
my $name = basename($fn);
+ next if $name eq "manual";
my $dstKey = "$releaseDir/" . $name;
unless (defined $releasesBucket->head_key($dstKey)) {
print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n";
@@ -190,8 +232,7 @@ for my $fn (glob "$tmpDir/*") {
my $configuration = ();
$configuration->{content_type} = "application/octet-stream";
- if ($fn =~ /.sha256|install/) {
- # Text files
+ if ($fn =~ /.sha256|install|\.nix$/) {
$configuration->{content_type} = "text/plain";
}
@@ -200,28 +241,6 @@ for my $fn (glob "$tmpDir/*") {
}
}
-# Update nix-fallback-paths.nix.
-if ($isLatest) {
- system("cd $nixpkgsDir && git pull") == 0 or die;
-
- sub getStorePath {
- my ($jobName) = @_;
- my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
- return $buildInfo->{buildoutputs}->{out}->{path} or die "cannot get store path for '$jobName'";
- }
-
- write_file("$nixpkgsDir/nixos/modules/installer/tools/nix-fallback-paths.nix",
- "{\n" .
- " x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
- " i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
- " aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
- " x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
- " aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
- "}\n");
-
- system("cd $nixpkgsDir && git commit -a -m 'nix-fallback-paths.nix: Update to $version'") == 0 or die;
-}
-
# Update the "latest" symlink.
$channelsBucket->add_key(
"nix-latest/install", "",
diff --git a/mk/cxx-big-literal.mk b/mk/cxx-big-literal.mk
new file mode 100644
index 000000000..85365df8e
--- /dev/null
+++ b/mk/cxx-big-literal.mk
@@ -0,0 +1,5 @@
+%.gen.hh: %
+ @echo 'R"foo(' >> $@.tmp
+ $(trace-gen) cat $< >> $@.tmp
+ @echo ')foo"' >> $@.tmp
+ @mv $@.tmp $@
diff --git a/mk/lib.mk b/mk/lib.mk
index 92f0983d5..34fa624d8 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -101,6 +101,7 @@ include mk/libraries.mk
include mk/programs.mk
include mk/patterns.mk
include mk/templates.mk
+include mk/cxx-big-literal.mk
include mk/tests.mk
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index 7c66538b0..c11783158 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -246,8 +246,15 @@ printf -v _OLD_LINE_FMT "%b" $'\033[1;7;31m-'"$ESC ${RED}%L${ESC}"
printf -v _NEW_LINE_FMT "%b" $'\033[1;7;32m+'"$ESC ${GREEN}%L${ESC}"
_diff() {
+ # macOS Ventura doesn't ship with GNU diff. Print similar output except
+ # without +/- markers or dimming
+ if diff --version | grep -q "Apple diff"; then
+ printf -v CHANGED_GROUP_FORMAT "%b" "${GREEN}%>${RED}%<${ESC}"
+ diff --changed-group-format="$CHANGED_GROUP_FORMAT" "$@"
+ else
# simple colorized diff comatible w/ pre `--color` versions
- diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
+ diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
+ fi
}
confirm_rm() {
@@ -873,7 +880,7 @@ configure_shell_profile() {
fi
done
- task "Setting up shell profiles for Fish with with ${PROFILE_FISH_SUFFIX} inside ${PROFILE_FISH_PREFIXES[*]}"
+ task "Setting up shell profiles for Fish with ${PROFILE_FISH_SUFFIX} inside ${PROFILE_FISH_PREFIXES[*]}"
for fish_prefix in "${PROFILE_FISH_PREFIXES[@]}"; do
if [ ! -d "$fish_prefix" ]; then
# this specific prefix (ie: /etc/fish) is very likely to exist
diff --git a/scripts/install-systemd-multi-user.sh b/scripts/install-systemd-multi-user.sh
index 7dd567747..07b34033a 100755
--- a/scripts/install-systemd-multi-user.sh
+++ b/scripts/install-systemd-multi-user.sh
@@ -92,7 +92,7 @@ poly_configure_nix_daemon_service() {
task "Setting up the nix-daemon systemd service"
_sudo "to create the nix-daemon tmpfiles config" \
- ln -sfn /nix/var/nix/profiles/default/$TMPFILES_SRC $TMPFILES_DEST
+ ln -sfn "/nix/var/nix/profiles/default$TMPFILES_SRC" "$TMPFILES_DEST"
_sudo "to run systemd-tmpfiles once to pick that path up" \
systemd-tmpfiles --create --prefix=/nix/var/nix
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index ce9c7f45a..323e04fdb 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -258,6 +258,8 @@ static int main_build_remote(int argc, char * * argv)
connected:
close(5);
+ assert(sshStore);
+
std::cerr << "# accept\n" << storeUri << "\n";
auto inputs = readStrings(source);
@@ -286,23 +288,48 @@ connected:
uploadLock = -1;
auto drv = store->readDerivation(*drvPath);
+
+ std::optional optResult;
+
+ // If we don't know whether we are trusted (e.g. `ssh://`
+ // stores), we assume we are. This is necessary for backwards
+ // compat.
+ bool trustedOrLegacy = ({
+ std::optional trusted = sshStore->isTrustedClient();
+ !trusted || *trusted;
+ });
+
+ // See the very large comment in `case wopBuildDerivation:` in
+ // `src/libstore/daemon.cc` that explains the trust model here.
+ //
+ // This condition mirrors that: that code enforces the "rules" outlined there;
+ // we do the best we can given those "rules".
+ if (trustedOrLegacy || drv.type().isCA()) {
+ // Hijack the inputs paths of the derivation to include all
+ // the paths that come from the `inputDrvs` set. We don’t do
+ // that for the derivations whose `inputDrvs` is empty
+ // because:
+ //
+ // 1. It’s not needed
+ //
+ // 2. Changing the `inputSrcs` set changes the associated
+ // output ids, which break CA derivations
+ if (!drv.inputDrvs.empty())
+ drv.inputSrcs = store->parseStorePathSet(inputs);
+ optResult = sshStore->buildDerivation(*drvPath, (const BasicDerivation &) drv);
+ auto & result = *optResult;
+ if (!result.success())
+ throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
+ } else {
+ copyClosure(*store, *sshStore, StorePathSet {*drvPath}, NoRepair, NoCheckSigs, substitute);
+ auto res = sshStore->buildPathsWithResults({ DerivedPath::Built { *drvPath, OutputsSpec::All {} } });
+ // One path to build should produce exactly one build result
+ assert(res.size() == 1);
+ optResult = std::move(res[0]);
+ }
+
+
auto outputHashes = staticOutputHashes(*store, drv);
-
- // Hijack the inputs paths of the derivation to include all the paths
- // that come from the `inputDrvs` set.
- // We don’t do that for the derivations whose `inputDrvs` is empty
- // because
- // 1. It’s not needed
- // 2. Changing the `inputSrcs` set changes the associated output ids,
- // which break CA derivations
- if (!drv.inputDrvs.empty())
- drv.inputSrcs = store->parseStorePathSet(inputs);
-
- auto result = sshStore->buildDerivation(*drvPath, drv);
-
- if (!result.success())
- throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
-
std::set missingRealisations;
StorePathSet missingPaths;
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) {
@@ -311,6 +338,8 @@ connected:
auto thisOutputId = DrvOutput{ thisOutputHash, outputName };
if (!store->queryRealisation(thisOutputId)) {
debug("missing output %s", outputName);
+ assert(optResult);
+ auto & result = *optResult;
auto i = result.builtOutputs.find(outputName);
assert(i != result.builtOutputs.end());
auto & newRealisation = i->second;
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index bedf11e2c..6c4648b34 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -121,6 +121,8 @@ ref EvalCommand::getEvalState()
#endif
;
+ evalState->repair = repair;
+
if (startReplOnEvalErrors) {
evalState->debugRepl = &AbstractNixRepl::runSimple;
};
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 5b6477c82..ff3abd534 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -153,7 +153,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
for (auto & i : autoArgs) {
auto v = state.allocValue();
if (i.second[0] == 'E')
- state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), absPath(".")));
+ state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), state.rootPath(CanonPath::fromCwd())));
else
v->mkString(((std::string_view) i.second).substr(1));
res.insert(state.symbols.create(i.first), v);
@@ -161,19 +161,19 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish();
}
-Path lookupFileArg(EvalState & state, std::string_view s)
+SourcePath lookupFileArg(EvalState & state, std::string_view s)
{
if (EvalSettings::isPseudoUrl(s)) {
auto storePath = fetchers::downloadTarball(
state.store, EvalSettings::resolvePseudoUrl(s), "source", false).first.storePath;
- return state.store->toRealPath(storePath);
+ return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
}
else if (hasPrefix(s, "flake:")) {
experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
- return state.store->toRealPath(storePath);
+ return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
}
else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
@@ -182,7 +182,7 @@ Path lookupFileArg(EvalState & state, std::string_view s)
}
else
- return absPath(std::string(s));
+ return state.rootPath(CanonPath::fromCwd(s));
}
}
diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index b69db11dd..b65cb5b20 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -2,14 +2,16 @@
///@file
#include "args.hh"
+#include "common-args.hh"
namespace nix {
class Store;
class EvalState;
class Bindings;
+struct SourcePath;
-struct MixEvalArgs : virtual Args
+struct MixEvalArgs : virtual Args, virtual MixRepair
{
static constexpr auto category = "Common evaluation options";
@@ -25,6 +27,6 @@ private:
std::map autoArgs;
};
-Path lookupFileArg(EvalState & state, std::string_view s);
+SourcePath lookupFileArg(EvalState & state, std::string_view s);
}
diff --git a/src/libcmd/editor-for.cc b/src/libcmd/editor-for.cc
index f674f32bd..a17c6f12a 100644
--- a/src/libcmd/editor-for.cc
+++ b/src/libcmd/editor-for.cc
@@ -3,8 +3,11 @@
namespace nix {
-Strings editorFor(const Path & file, uint32_t line)
+Strings editorFor(const SourcePath & file, uint32_t line)
{
+ auto path = file.getPhysicalPath();
+ if (!path)
+ throw Error("cannot open '%s' in an editor because it has no physical path", file);
auto editor = getEnv("EDITOR").value_or("cat");
auto args = tokenizeString(editor);
if (line > 0 && (
@@ -13,7 +16,7 @@ Strings editorFor(const Path & file, uint32_t line)
editor.find("vim") != std::string::npos ||
editor.find("kak") != std::string::npos))
args.push_back(fmt("+%d", line));
- args.push_back(file);
+ args.push_back(path->abs());
return args;
}
diff --git a/src/libcmd/editor-for.hh b/src/libcmd/editor-for.hh
index c8c4e9d9b..fbf4307c9 100644
--- a/src/libcmd/editor-for.hh
+++ b/src/libcmd/editor-for.hh
@@ -2,6 +2,7 @@
///@file
#include "types.hh"
+#include "input-accessor.hh"
namespace nix {
@@ -9,6 +10,6 @@ namespace nix {
* Helper function to generate args that invoke $EDITOR on
* filename:lineno.
*/
-Strings editorFor(const Path & file, uint32_t line);
+Strings editorFor(const SourcePath & file, uint32_t line);
}
diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc
index cf513126d..b35ca2910 100644
--- a/src/libcmd/installable-attr-path.cc
+++ b/src/libcmd/installable-attr-path.cc
@@ -46,7 +46,15 @@ std::pair InstallableAttrPath::toValue(EvalState & state)
DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
{
- auto v = toValue(*state).first;
+ auto [v, pos] = toValue(*state);
+
+ if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
+ *v,
+ pos,
+ fmt("while evaluating the attribute '%s'", attrPath)))
+ {
+ return { *derivedPathWithInfo };
+ }
Bindings & autoArgs = *cmd.getAutoArgs(*state);
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index a3352af76..eb944240b 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -95,32 +95,13 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
// FIXME: use eval cache?
auto v = attr->forceValue();
- if (v.type() == nPath) {
- PathSet context;
- auto storePath = state->copyPathToStore(context, Path(v.path));
- return {{
- .path = DerivedPath::Opaque {
- .path = std::move(storePath),
- },
- .info = make_ref(),
- }};
+ if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
+ v,
+ noPos,
+ fmt("while evaluating the flake output attribute '%s'", attrPath)))
+ {
+ return { *derivedPathWithInfo };
}
-
- else if (v.type() == nString) {
- PathSet context;
- auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
- auto storePath = state->store->maybeParseStorePath(s);
- if (storePath && context.count(std::string(s))) {
- return {{
- .path = DerivedPath::Opaque {
- .path = std::move(*storePath),
- },
- .info = make_ref(),
- }};
- } else
- throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
- }
-
else
throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
}
@@ -235,7 +216,7 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const
}
}
- return InstallableValue::nixpkgsFlakeRef();
+ return defaultNixpkgsFlakeRef();
}
}
diff --git a/src/libcmd/installable-flake.hh b/src/libcmd/installable-flake.hh
index afe64d977..7ac4358d2 100644
--- a/src/libcmd/installable-flake.hh
+++ b/src/libcmd/installable-flake.hh
@@ -67,9 +67,22 @@ struct InstallableFlake : InstallableValue
std::shared_ptr getLockedFlake() const;
- FlakeRef nixpkgsFlakeRef() const override;
+ FlakeRef nixpkgsFlakeRef() const;
};
+/**
+ * Default flake ref for referring to Nixpkgs. For flakes that don't
+ * have their own Nixpkgs input, or other installables.
+ *
+ * It is a layer violation for Nix to know about Nixpkgs; currently just
+ * `nix develop` does. Be wary of using this /
+ * `InstallableFlake::nixpkgsFlakeRef` more places.
+ */
+static inline FlakeRef defaultNixpkgsFlakeRef()
+{
+ return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
+}
+
ref openEvalCache(
EvalState & state,
std::shared_ptr lockedFlake);
diff --git a/src/libcmd/installable-value.cc b/src/libcmd/installable-value.cc
index 3a7ede4e2..1eff293cc 100644
--- a/src/libcmd/installable-value.cc
+++ b/src/libcmd/installable-value.cc
@@ -41,4 +41,26 @@ ref InstallableValue::require(ref installable)
return ref { castedInstallable };
}
+std::optional InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
+{
+ if (v.type() == nPath) {
+ auto storePath = v.path().fetchToStore(state->store);
+ return {{
+ .path = DerivedPath::Opaque {
+ .path = std::move(storePath),
+ },
+ .info = make_ref(),
+ }};
+ }
+
+ else if (v.type() == nString) {
+ return {{
+ .path = state->coerceToDerivedPath(pos, v, errorCtx),
+ .info = make_ref(),
+ }};
+ }
+
+ else return std::nullopt;
+}
+
}
diff --git a/src/libcmd/installable-value.hh b/src/libcmd/installable-value.hh
index bfb3bfeed..3138ce8ec 100644
--- a/src/libcmd/installable-value.hh
+++ b/src/libcmd/installable-value.hh
@@ -96,13 +96,26 @@ struct InstallableValue : Installable
UnresolvedApp toApp(EvalState & state);
- virtual FlakeRef nixpkgsFlakeRef() const
- {
- return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
- }
-
static InstallableValue & require(Installable & installable);
static ref require(ref installable);
+
+protected:
+
+ /**
+ * Handles either a plain path, or a string with a single string
+ * context elem in the right format. The latter case is handled by
+ * `EvalState::coerceToDerivedPath()`; see it for details.
+ *
+ * @param v Value that is hopefully a string or path per the above.
+ *
+ * @param pos Position of value to aid with diagnostics.
+ *
+ * @param errorCtx Arbitrary message for use in potential error message when something is wrong with `v`.
+ *
+ * @result A derived path (with empty info, for now) if the value
+ * matched the above criteria.
+ */
+ std::optional trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx);
};
}
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 0a2fe0073..a2b882355 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -449,7 +449,7 @@ Installables SourceExprCommand::parseInstallables(
else if (file)
state->evalFile(lookupFileArg(*state, *file), *vFile);
else {
- auto e = state->parseExprFromString(*expr, absPath("."));
+ auto e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
state->eval(e, *vFile);
}
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 80c08bf1c..4b160a100 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -55,8 +55,6 @@ struct NixRepl
, gc
#endif
{
- std::string curDir;
-
size_t debugTraceIndex;
Strings loadedFiles;
@@ -114,7 +112,6 @@ NixRepl::NixRepl(const Strings & searchPath, nix::ref store, refstaticBaseEnv.get()))
, historyFile(getDataDir() + "/nix/repl-history")
{
- curDir = absPath(".");
}
@@ -594,14 +591,14 @@ bool NixRepl::processLine(std::string line)
Value v;
evalString(arg, v);
- const auto [path, line] = [&] () -> std::pair {
+ const auto [path, line] = [&] () -> std::pair {
if (v.type() == nPath || v.type() == nString) {
- PathSet context;
+ NixStringContext context;
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
return {path, 0};
} else if (v.isLambda()) {
auto pos = state->positions[v.lambda.fun->pos];
- if (auto path = std::get_if(&pos.origin))
+ if (auto path = std::get_if(&pos.origin))
return {*path, pos.line};
else
throw Error("'%s' cannot be shown in an editor", pos);
@@ -876,8 +873,7 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
Expr * NixRepl::parseString(std::string s)
{
- Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv);
- return e;
+ return state->parseExprFromString(std::move(s), state->rootPath(CanonPath::fromCwd()), staticEnv);
}
@@ -925,7 +921,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
break;
case nPath:
- str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping?
+ str << ANSI_GREEN << v.path().to_string() << ANSI_NORMAL; // !!! escaping?
break;
case nNull:
@@ -940,7 +936,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
if (isDrv) {
str << "«derivation ";
Bindings::iterator i = v.attrs->find(state->sDrvPath);
- PathSet context;
+ NixStringContext context;
if (i != v.attrs->end())
str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
else
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index 7c0705091..ab654c1b0 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -106,7 +106,7 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin
}
-std::pair findPackageFilename(EvalState & state, Value & v, std::string what)
+std::pair findPackageFilename(EvalState & state, Value & v, std::string what)
{
Value * v2;
try {
@@ -118,21 +118,25 @@ std::pair findPackageFilename(EvalState & state, Value &
// FIXME: is it possible to extract the Pos object instead of doing this
// toString + parsing?
- auto pos = state.forceString(*v2, noPos, "while evaluating the 'meta.position' attribute of a derivation");
+ NixStringContext context;
+ auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
- auto colon = pos.rfind(':');
- if (colon == std::string::npos)
- throw ParseError("cannot parse meta.position attribute '%s'", pos);
+ auto fn = path.path.abs();
+
+ auto fail = [fn]() {
+ throw ParseError("cannot parse 'meta.position' attribute '%s'", fn);
+ };
- std::string filename(pos, 0, colon);
- unsigned int lineno;
try {
- lineno = std::stoi(std::string(pos, colon + 1, std::string::npos));
+ auto colon = fn.rfind(':');
+ if (colon == std::string::npos) fail();
+ std::string filename(fn, 0, colon);
+ auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
+ return {CanonPath(fn.substr(0, colon)), lineno};
} catch (std::invalid_argument & e) {
- throw ParseError("cannot parse line number '%s'", pos);
+ fail();
+ abort();
}
-
- return { std::move(filename), lineno };
}
diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh
index b2bfb5d04..eb00ffb93 100644
--- a/src/libexpr/attr-path.hh
+++ b/src/libexpr/attr-path.hh
@@ -20,7 +20,7 @@ std::pair findAlongAttrPath(
/**
* Heuristic to find the filename and lineno or a nix value.
*/
-std::pair findPackageFilename(EvalState & state, Value & v, std::string what);
+std::pair findPackageFilename(EvalState & state, Value & v, std::string what);
std::vector parseAttrPath(EvalState & state, std::string_view s);
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index 1219b2471..9e734e654 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -47,7 +47,7 @@ struct AttrDb
{
auto state(_state->lock());
- Path cacheDir = getCacheDir() + "/nix/eval-cache-v4";
+ Path cacheDir = getCacheDir() + "/nix/eval-cache-v5";
createDirs(cacheDir);
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
@@ -300,7 +300,7 @@ struct AttrDb
NixStringContext context;
if (!queryAttribute.isNull(3))
for (auto & s : tokenizeString>(queryAttribute.getStr(3), ";"))
- context.push_back(NixStringContextElem::parse(cfg, s));
+ context.insert(NixStringContextElem::parse(s));
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
}
case AttrType::Bool:
@@ -442,8 +442,10 @@ Value & AttrCursor::forceValue()
if (v.type() == nString)
cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context),
string_t{v.string.s, {}}};
- else if (v.type() == nPath)
- cachedValue = {root->db->setString(getKey(), v.path), string_t{v.path, {}}};
+ else if (v.type() == nPath) {
+ auto path = v.path().path;
+ cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
+ }
else if (v.type() == nBool)
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
else if (v.type() == nInt)
@@ -580,7 +582,7 @@ std::string AttrCursor::getString()
if (v.type() != nString && v.type() != nPath)
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow();
- return v.type() == nString ? v.string.s : v.path;
+ return v.type() == nString ? v.string.s : v.path().to_string();
}
string_t AttrCursor::getStringWithContext()
@@ -619,10 +621,13 @@ string_t AttrCursor::getStringWithContext()
auto & v = forceValue();
- if (v.type() == nString)
- return {v.string.s, v.getContext(*root->state.store)};
+ if (v.type() == nString) {
+ NixStringContext context;
+ copyContext(v, context);
+ return {v.string.s, std::move(context)};
+ }
else if (v.type() == nPath)
- return {v.path, {}};
+ return {v.path().to_string(), {}};
else
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow();
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 6668add8c..71fd6e6e4 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -4,6 +4,7 @@
#include "util.hh"
#include "store-api.hh"
#include "derivations.hh"
+#include "downstream-placeholder.hh"
#include "globals.hh"
#include "eval-inline.hh"
#include "filetransfer.hh"
@@ -94,7 +95,6 @@ RootValue allocRootValue(Value * v)
#endif
}
-
void Value::print(const SymbolTable & symbols, std::ostream & str,
std::set * seen) const
{
@@ -111,7 +111,7 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
printLiteralString(str, string.s);
break;
case tPath:
- str << path; // !!! escaping?
+ str << path().to_string(); // !!! escaping?
break;
case tNull:
str << "null";
@@ -535,6 +535,7 @@ EvalState::EvalState(
, sOutputSpecified(symbols.create("outputSpecified"))
, repair(NoRepair)
, emptyBindings(0)
+ , derivationInternal(rootPath(CanonPath("/builtin/derivation.nix")))
, store(store)
, buildStore(buildStore ? buildStore : store)
, debugRepl(nullptr)
@@ -609,15 +610,14 @@ void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value &
{
allowPath(storePath);
- auto path = store->printStorePath(storePath);
- v.mkString(path, PathSet({path}));
+ mkStorePathString(storePath, v);
}
-Path EvalState::checkSourcePath(const Path & path_)
+SourcePath EvalState::checkSourcePath(const SourcePath & path_)
{
if (!allowedPaths) return path_;
- auto i = resolvedPaths.find(path_);
+ auto i = resolvedPaths.find(path_.path.abs());
if (i != resolvedPaths.end())
return i->second;
@@ -627,9 +627,9 @@ Path EvalState::checkSourcePath(const Path & path_)
* attacker can't append ../../... to a path that would be in allowedPaths
* and thus leak symlink targets.
*/
- Path abspath = canonPath(path_);
+ Path abspath = canonPath(path_.path.abs());
- if (hasPrefix(abspath, corepkgsPrefix)) return abspath;
+ if (hasPrefix(abspath, corepkgsPrefix)) return CanonPath(abspath);
for (auto & i : *allowedPaths) {
if (isDirOrInDir(abspath, i)) {
@@ -647,11 +647,11 @@ Path EvalState::checkSourcePath(const Path & path_)
/* Resolve symlinks. */
debug("checking access to '%s'", abspath);
- Path path = canonPath(abspath, true);
+ SourcePath path = CanonPath(canonPath(abspath, true));
for (auto & i : *allowedPaths) {
- if (isDirOrInDir(path, i)) {
- resolvedPaths[path_] = path;
+ if (isDirOrInDir(path.path.abs(), i)) {
+ resolvedPaths.insert_or_assign(path_.path.abs(), path);
return path;
}
}
@@ -679,12 +679,12 @@ void EvalState::checkURI(const std::string & uri)
/* If the URI is a path, then check it against allowedPaths as
well. */
if (hasPrefix(uri, "/")) {
- checkSourcePath(uri);
+ checkSourcePath(CanonPath(uri));
return;
}
if (hasPrefix(uri, "file://")) {
- checkSourcePath(std::string(uri, 7));
+ checkSourcePath(CanonPath(std::string(uri, 7)));
return;
}
@@ -692,7 +692,7 @@ void EvalState::checkURI(const std::string & uri)
}
-Path EvalState::toRealPath(const Path & path, const PathSet & context)
+Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
{
// FIXME: check whether 'path' is in 'context'.
return
@@ -944,34 +944,34 @@ void Value::mkString(std::string_view s)
}
-static void copyContextToValue(Value & v, const PathSet & context)
+static void copyContextToValue(Value & v, const NixStringContext & context)
{
if (!context.empty()) {
size_t n = 0;
v.string.context = (const char * *)
allocBytes((context.size() + 1) * sizeof(char *));
for (auto & i : context)
- v.string.context[n++] = dupString(i.c_str());
+ v.string.context[n++] = dupString(i.to_string().c_str());
v.string.context[n] = 0;
}
}
-void Value::mkString(std::string_view s, const PathSet & context)
+void Value::mkString(std::string_view s, const NixStringContext & context)
{
mkString(s);
copyContextToValue(*this, context);
}
-void Value::mkStringMove(const char * s, const PathSet & context)
+void Value::mkStringMove(const char * s, const NixStringContext & context)
{
mkString(s);
copyContextToValue(*this, context);
}
-void Value::mkPath(std::string_view s)
+void Value::mkPath(const SourcePath & path)
{
- mkPath(makeImmutableString(s));
+ mkPath(makeImmutableString(path.path.abs()));
}
@@ -1027,9 +1027,9 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
void EvalState::mkPos(Value & v, PosIdx p)
{
auto pos = positions[p];
- if (auto path = std::get_if(&pos.origin)) {
+ if (auto path = std::get_if(&pos.origin)) {
auto attrs = buildBindings(3);
- attrs.alloc(sFile).mkString(*path);
+ attrs.alloc(sFile).mkString(path->path.abs());
attrs.alloc(sLine).mkInt(pos.line);
attrs.alloc(sColumn).mkInt(pos.column);
v.mkAttrs(attrs);
@@ -1038,6 +1038,37 @@ void EvalState::mkPos(Value & v, PosIdx p)
}
+void EvalState::mkStorePathString(const StorePath & p, Value & v)
+{
+ v.mkString(
+ store->printStorePath(p),
+ NixStringContext {
+ NixStringContextElem::Opaque { .path = p },
+ });
+}
+
+
+void EvalState::mkOutputString(
+ Value & value,
+ const StorePath & drvPath,
+ const std::string outputName,
+ std::optional optOutputPath)
+{
+ value.mkString(
+ optOutputPath
+ ? store->printStorePath(*std::move(optOutputPath))
+ /* Downstream we would substitute this for an actual path once
+ we build the floating CA derivation */
+ : DownstreamPlaceholder::unknownCaOutput(drvPath, outputName).render(),
+ NixStringContext {
+ NixStringContextElem::Built {
+ .drvPath = drvPath,
+ .output = outputName,
+ }
+ });
+}
+
+
/* Create a thunk for the delayed computation of the given expression
in the given environment. But if the expression is a variable,
then look it up right away. This significantly reduces the number
@@ -1085,7 +1116,7 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
}
-void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial)
+void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial)
{
auto path = checkSourcePath(path_);
@@ -1095,7 +1126,7 @@ void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial)
return;
}
- Path resolvedPath = resolveExprPath(path);
+ auto resolvedPath = resolveExprPath(path);
if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) {
v = i->second;
return;
@@ -1123,8 +1154,8 @@ void EvalState::resetFileCache()
void EvalState::cacheFile(
- const Path & path,
- const Path & resolvedPath,
+ const SourcePath & path,
+ const SourcePath & resolvedPath,
Expr * e,
Value & v,
bool mustBeTrivial)
@@ -1138,7 +1169,7 @@ void EvalState::cacheFile(
*e,
this->baseEnv,
e->getPos() ? static_cast>(positions[e->getPos()]) : nullptr,
- "while evaluating the file '%1%':", resolvedPath)
+ "while evaluating the file '%1%':", resolvedPath.to_string())
: nullptr;
// Enforce that 'flake.nix' is a direct attrset, not a
@@ -1148,7 +1179,7 @@ void EvalState::cacheFile(
error("file '%s' must be an attribute set", path).debugThrow();
eval(e, v);
} catch (Error & e) {
- addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath);
+ addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
throw;
}
@@ -1409,8 +1440,8 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} catch (Error & e) {
if (pos2) {
auto pos2r = state.positions[pos2];
- auto origin = std::get_if(&pos2r.origin);
- if (!(origin && *origin == state.derivationNixPath))
+ auto origin = std::get_if(&pos2r.origin);
+ if (!(origin && *origin == state.derivationInternal))
state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'",
showAttrPath(state, env, attrPath));
}
@@ -1900,7 +1931,7 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po
void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
{
- PathSet context;
+ NixStringContext context;
std::vector s;
size_t sSize = 0;
NixInt n = 0;
@@ -1983,7 +2014,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
else if (firstType == nPath) {
if (!context.empty())
state.error("a string that refers to a store path cannot be appended to a path").atPos(pos).withFrame(env, *this).debugThrow();
- v.mkPath(canonPath(str()));
+ v.mkPath(CanonPath(canonPath(str())));
} else
v.mkStringMove(c_str(), context);
}
@@ -2109,26 +2140,15 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos, std::string
}
-void copyContext(const Value & v, PathSet & context)
+void copyContext(const Value & v, NixStringContext & context)
{
if (v.string.context)
for (const char * * p = v.string.context; *p; ++p)
- context.insert(*p);
+ context.insert(NixStringContextElem::parse(*p));
}
-NixStringContext Value::getContext(const Store & store)
-{
- NixStringContext res;
- assert(internalType == tString);
- if (string.context)
- for (const char * * p = string.context; *p; ++p)
- res.push_back(NixStringContextElem::parse(store, *p));
- return res;
-}
-
-
-std::string_view EvalState::forceString(Value & v, PathSet & context, const PosIdx pos, std::string_view errorCtx)
+std::string_view EvalState::forceString(Value & v, NixStringContext & context, const PosIdx pos, std::string_view errorCtx)
{
auto s = forceString(v, pos, errorCtx);
copyContext(v, context);
@@ -2158,7 +2178,7 @@ bool EvalState::isDerivation(Value & v)
std::optional EvalState::tryAttrsToString(const PosIdx pos, Value & v,
- PathSet & context, bool coerceMore, bool copyToStore)
+ NixStringContext & context, bool coerceMore, bool copyToStore)
{
auto i = v.attrs->find(sToString);
if (i != v.attrs->end()) {
@@ -2172,8 +2192,14 @@ std::optional EvalState::tryAttrsToString(const PosIdx pos, Value &
return {};
}
-BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, PathSet &context,
- std::string_view errorCtx, bool coerceMore, bool copyToStore, bool canonicalizePath)
+BackedStringView EvalState::coerceToString(
+ const PosIdx pos,
+ Value & v,
+ NixStringContext & context,
+ std::string_view errorCtx,
+ bool coerceMore,
+ bool copyToStore,
+ bool canonicalizePath)
{
forceValue(v, pos);
@@ -2183,12 +2209,14 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, PathSet &
}
if (v.type() == nPath) {
- BackedStringView path(PathView(v.path));
- if (canonicalizePath)
- path = canonPath(*path);
- if (copyToStore)
- path = store->printStorePath(copyPathToStore(context, std::move(path).toOwned()));
- return path;
+ return
+ !canonicalizePath && !copyToStore
+ ? // FIXME: hack to preserve path literals that end in a
+ // slash, as in /foo/${x}.
+ v._path
+ : copyToStore
+ ? store->printStorePath(copyPathToStore(context, v.path()))
+ : std::string(v.path().path.abs());
}
if (v.type() == nAttrs) {
@@ -2249,40 +2277,40 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value &v, PathSet &
}
-StorePath EvalState::copyPathToStore(PathSet & context, const Path & path)
+StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path)
{
- if (nix::isDerivation(path))
+ if (nix::isDerivation(path.path.abs()))
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
- auto dstPath = [&]() -> StorePath
- {
- auto i = srcToStore.find(path);
- if (i != srcToStore.end()) return i->second;
+ auto i = srcToStore.find(path);
- auto dstPath = settings.readOnlyMode
- ? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first
- : store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
- allowPath(dstPath);
- srcToStore.insert_or_assign(path, dstPath);
- printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
- return dstPath;
- }();
+ auto dstPath = i != srcToStore.end()
+ ? i->second
+ : [&]() {
+ auto dstPath = path.fetchToStore(store, path.baseName(), nullptr, repair);
+ allowPath(dstPath);
+ srcToStore.insert_or_assign(path, dstPath);
+ printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
+ return dstPath;
+ }();
- context.insert(store->printStorePath(dstPath));
+ context.insert(NixStringContextElem::Opaque {
+ .path = dstPath
+ });
return dstPath;
}
-Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx)
+SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)
{
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (path == "" || path[0] != '/')
error("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow();
- return path;
+ return CanonPath(path);
}
-StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, PathSet & context, std::string_view errorCtx)
+StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)
{
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (auto storePath = store->maybeParseStorePath(path))
@@ -2291,6 +2319,80 @@ StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, PathSet & co
}
+std::pair EvalState::coerceToDerivedPathUnchecked(const PosIdx pos, Value & v, std::string_view errorCtx)
+{
+ NixStringContext context;
+ auto s = forceString(v, context, pos, errorCtx);
+ auto csize = context.size();
+ if (csize != 1)
+ error(
+ "string '%s' has %d entries in its context. It should only have exactly one entry",
+ s, csize)
+ .withTrace(pos, errorCtx).debugThrow();
+ auto derivedPath = std::visit(overloaded {
+ [&](NixStringContextElem::Opaque && o) -> DerivedPath {
+ return DerivedPath::Opaque {
+ .path = std::move(o.path),
+ };
+ },
+ [&](NixStringContextElem::DrvDeep &&) -> DerivedPath {
+ error(
+ "string '%s' has a context which refers to a complete source and binary closure. This is not supported at this time",
+ s).withTrace(pos, errorCtx).debugThrow();
+ },
+ [&](NixStringContextElem::Built && b) -> DerivedPath {
+ return DerivedPath::Built {
+ .drvPath = std::move(b.drvPath),
+ .outputs = OutputsSpec::Names { std::move(b.output) },
+ };
+ },
+ }, ((NixStringContextElem &&) *context.begin()).raw());
+ return {
+ std::move(derivedPath),
+ std::move(s),
+ };
+}
+
+
+DerivedPath EvalState::coerceToDerivedPath(const PosIdx pos, Value & v, std::string_view errorCtx)
+{
+ auto [derivedPath, s_] = coerceToDerivedPathUnchecked(pos, v, errorCtx);
+ auto s = s_;
+ std::visit(overloaded {
+ [&](const DerivedPath::Opaque & o) {
+ auto sExpected = store->printStorePath(o.path);
+ if (s != sExpected)
+ error(
+ "path string '%s' has context with the different path '%s'",
+ s, sExpected)
+ .withTrace(pos, errorCtx).debugThrow();
+ },
+ [&](const DerivedPath::Built & b) {
+ // TODO need derived path with single output to make this
+ // total. Will add as part of RFC 92 work and then this is
+ // cleaned up.
+ auto output = *std::get(b.outputs).begin();
+
+ auto drv = store->readDerivation(b.drvPath);
+ auto i = drv.outputs.find(output);
+ if (i == drv.outputs.end())
+ throw Error("derivation '%s' does not have output '%s'", store->printStorePath(b.drvPath), output);
+ auto optOutputPath = i->second.path(*store, drv.name, output);
+ // This is testing for the case of CA derivations
+ auto sExpected = optOutputPath
+ ? store->printStorePath(*optOutputPath)
+ : DownstreamPlaceholder::unknownCaOutput(b.drvPath, output).render();
+ if (s != sExpected)
+ error(
+ "string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
+ s, output, store->printStorePath(b.drvPath), sExpected)
+ .withTrace(pos, errorCtx).debugThrow();
+ }
+ }, derivedPath.raw());
+ return derivedPath;
+}
+
+
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
{
forceValue(v1, noPos);
@@ -2321,7 +2423,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
return strcmp(v1.string.s, v2.string.s) == 0;
case nPath:
- return strcmp(v1.path, v2.path) == 0;
+ return strcmp(v1._path, v2._path) == 0;
case nNull:
return true;
@@ -2448,8 +2550,8 @@ void EvalState::printStats()
else
obj["name"] = nullptr;
if (auto pos = positions[fun->pos]) {
- if (auto path = std::get_if(&pos.origin))
- obj["file"] = *path;
+ if (auto path = std::get_if(&pos.origin))
+ obj["file"] = path->to_string();
obj["line"] = pos.line;
obj["column"] = pos.column;
}
@@ -2463,8 +2565,8 @@ void EvalState::printStats()
for (auto & i : attrSelects) {
json obj = json::object();
if (auto pos = positions[i.first]) {
- if (auto path = std::get_if(&pos.origin))
- obj["file"] = *path;
+ if (auto path = std::get_if(&pos.origin))
+ obj["file"] = path->to_string();
obj["line"] = pos.line;
obj["column"] = pos.column;
}
@@ -2489,7 +2591,7 @@ void EvalState::printStats()
}
-std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
+std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
{
throw TypeError({
.msg = hintfmt("cannot coerce %1% to a string", showType())
@@ -2518,7 +2620,7 @@ Strings EvalSettings::getDefaultNixPath()
{
Strings res;
auto add = [&](const Path & p, const std::string & s = std::string()) {
- if (pathExists(p)) {
+ if (pathAccessible(p)) {
if (s.empty()) {
res.push_back(p);
} else {
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index b3b985683..d6f4560a5 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -8,6 +8,7 @@
#include "symbol-table.hh"
#include "config.hh"
#include "experimental-features.hh"
+#include "input-accessor.hh"
#include