diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..d58577551
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,15 @@
+# Pull requests concerning the listed files will automatically invite the respective maintainers as reviewers.
+# This file is not used for denoting any kind of ownership, but is merely a tool for handling notifications.
+#
+# Merge permissions are required for maintaining an entry in this file.
+# For documentation on this mechanism, see https://help.github.com/articles/about-codeowners/
+
+# Default reviewers if nothing else matches
+* @edolstra @thufschmitt
+
+# This file
+.github/CODEOWNERS @edolstra
+
+# Public documentation
+/doc @fricklerhandwerk
+*.md @fricklerhandwerk
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index e6d346bc1..984f9a9ea 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -30,3 +30,7 @@ A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.
+
+**Priorities**
+
+Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 4fe86d5ec..42c658b52 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -18,3 +18,7 @@ A clear and concise description of any alternative solutions or features you've
**Additional context**
Add any other context or screenshots about the feature request here.
+
+**Priorities**
+
+Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/ISSUE_TEMPLATE/installer.md b/.github/ISSUE_TEMPLATE/installer.md
new file mode 100644
index 000000000..3768a49c9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/installer.md
@@ -0,0 +1,36 @@
+---
+name: Installer issue
+about: Report problems with installation
+title: ''
+labels: installer
+assignees: ''
+
+---
+
+## Platform
+
+
+
+- [ ] Linux:
+- [ ] macOS
+- [ ] WSL
+
+## Additional information
+
+
+
+## Output
+
+Output
+
+```log
+
+
+
+```
+
+
+
+## Priorities
+
+Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/ISSUE_TEMPLATE/missing_documentation.md b/.github/ISSUE_TEMPLATE/missing_documentation.md
index fbabd868e..942d7a971 100644
--- a/.github/ISSUE_TEMPLATE/missing_documentation.md
+++ b/.github/ISSUE_TEMPLATE/missing_documentation.md
@@ -26,3 +26,6 @@ assignees: ''
+## Priorities
+
+Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
index 537aa0909..5311be01f 100644
--- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
+++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
@@ -5,3 +5,7 @@ Please include relevant [release notes](https://github.com/NixOS/nix/blob/master
**Testing**
If this issue is a regression or something that should block release, please consider including a test either in the [testsuite](https://github.com/NixOS/nix/tree/master/tests) or as a [hydraJob]( https://github.com/NixOS/nix/blob/master/flake.nix#L396) so that it can be part of the [automatic checks](https://hydra.nixos.org/jobset/nix/master).
+
+**Priorities**
+
+Add :+1: to [pull requests you find important](https://github.com/NixOS/nix/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 75be788ef..7568145b6 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@v0.0.8
+ uses: zeebe-io/backport-action@v0.0.9
with:
# Config README: https://github.com/zeebe-io/backport-action#backport-action
github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.version b/.version
index 3ca2c9b2c..fb2c0766b 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-2.12.0
\ No newline at end of file
+2.13.0
diff --git a/doc/manual/generate-builtins.nix b/doc/manual/generate-builtins.nix
index 6c8b88da2..115bb3f94 100644
--- a/doc/manual/generate-builtins.nix
+++ b/doc/manual/generate-builtins.nix
@@ -1,16 +1,20 @@
-with builtins;
-with import ./utils.nix;
+builtinsDump:
+let
+ showBuiltin = name:
+ let
+ inherit (builtinsDump.${name}) doc args;
+ in
+ ''
+
+ ${name} ${listArgs args}
+
+
-builtins:
+ ${doc}
+
+
+ '';
+ listArgs = args: builtins.concatStringsSep " " (map (s: "${s}") args);
+in
+with builtins; concatStringsSep "\n" (map showBuiltin (attrNames builtinsDump))
-concatStrings (map
- (name:
- let builtin = builtins.${name}; in
- "${name} "
- + concatStringsSep " " (map (s: "${s}") builtin.args)
- + "
"
- + "\n\n"
- + builtin.doc
- + "\n\n"
- )
- (attrNames builtins))
diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix
index 057719e34..8c7c4d358 100644
--- a/doc/manual/generate-manpage.nix
+++ b/doc/manual/generate-manpage.nix
@@ -99,6 +99,7 @@ let
in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {});
parsedToplevel = builtins.fromJSON toplevel;
+
manpages = processCommand {
command = "nix";
details = parsedToplevel;
diff --git a/doc/manual/generate-options.nix b/doc/manual/generate-options.nix
index 680b709c8..a4ec36477 100644
--- a/doc/manual/generate-options.nix
+++ b/doc/manual/generate-options.nix
@@ -1,29 +1,41 @@
-with builtins;
-with import ./utils.nix;
+let
+ inherit (builtins) attrNames concatStringsSep isAttrs isBool;
+ inherit (import ./utils.nix) concatStrings squash splitLines;
+in
-options:
+optionsInfo:
+let
+ showOption = name:
+ let
+ inherit (optionsInfo.${name}) description documentDefault defaultValue aliases;
+ result = squash ''
+ - [`${name}`](#conf-${name})
-concatStrings (map
- (name:
- let option = options.${name}; in
- " - [`${name}`](#conf-${name})"
- + "\n\n"
- + concatStrings (map (s: " ${s}\n") (splitLines option.description)) + "\n\n"
- + (if option.documentDefault
- then " **Default:** " + (
- if option.defaultValue == "" || option.defaultValue == []
- then "*empty*"
- else if isBool option.defaultValue
- then (if option.defaultValue then "`true`" else "`false`")
- else
- # n.b. a StringMap value type is specified as a string, but
- # this shows the value type. The empty stringmap is "null" in
- # JSON, but that converts to "{ }" here.
- (if isAttrs option.defaultValue then "`\"\"`"
- else "`" + toString option.defaultValue + "`")) + "\n\n"
- else " **Default:** *machine-specific*\n")
- + (if option.aliases != []
- then " **Deprecated alias:** " + (concatStringsSep ", " (map (s: "`${s}`") option.aliases)) + "\n\n"
- else "")
- )
- (attrNames options))
+ ${indent " " body}
+ '';
+ # separate body to cleanly handle indentation
+ body = ''
+ ${description}
+
+ **Default:** ${showDefault documentDefault defaultValue}
+
+ ${showAliases aliases}
+ '';
+ showDefault = documentDefault: defaultValue:
+ if documentDefault then
+ # a StringMap value type is specified as a string, but
+ # this shows the value type. The empty stringmap is `null` in
+ # JSON, but that converts to `{ }` here.
+ if defaultValue == "" || defaultValue == [] || isAttrs defaultValue
+ then "*empty*"
+ else if isBool defaultValue then
+ if defaultValue then "`true`" else "`false`"
+ else "`${toString defaultValue}`"
+ else "*machine-specific*";
+ showAliases = aliases:
+ if aliases == [] then "" else
+ "**Deprecated alias:** ${(concatStringsSep ", " (map (s: "`${s}`") aliases))}";
+ indent = prefix: s:
+ concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s));
+ in result;
+in concatStrings (map showOption (attrNames optionsInfo))
diff --git a/doc/manual/local.mk b/doc/manual/local.mk
index 486dbd7a2..c0f69e00f 100644
--- a/doc/manual/local.mk
+++ b/doc/manual/local.mk
@@ -29,19 +29,19 @@ nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -
$(d)/%.1: $(d)/src/command-ref/%.md
@printf "Title: %s\n\n" "$$(basename $@ .1)" > $^.tmp
@cat $^ >> $^.tmp
- $(trace-gen) lowdown -sT man -M section=1 $^.tmp -o $@
+ $(trace-gen) lowdown -sT man --nroff-nolinks -M section=1 $^.tmp -o $@
@rm $^.tmp
$(d)/%.8: $(d)/src/command-ref/%.md
@printf "Title: %s\n\n" "$$(basename $@ .8)" > $^.tmp
@cat $^ >> $^.tmp
- $(trace-gen) lowdown -sT man -M section=8 $^.tmp -o $@
+ $(trace-gen) lowdown -sT man --nroff-nolinks -M section=8 $^.tmp -o $@
@rm $^.tmp
$(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md
@printf "Title: %s\n\n" "$$(basename $@ .5)" > $^.tmp
@cat $^ >> $^.tmp
- $(trace-gen) lowdown -sT man -M section=5 $^.tmp -o $@
+ $(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
diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js
index 2e77edd0f..69f75d3a0 100644
--- a/doc/manual/redirects.js
+++ b/doc/manual/redirects.js
@@ -35,7 +35,6 @@ const redirects = {
"conf-build-max-jobs": "command-ref/conf-file.html#conf-build-max-jobs",
"conf-build-max-log-size": "command-ref/conf-file.html#conf-build-max-log-size",
"conf-build-max-silent-time": "command-ref/conf-file.html#conf-build-max-silent-time",
- "conf-build-repeat": "command-ref/conf-file.html#conf-build-repeat",
"conf-build-timeout": "command-ref/conf-file.html#conf-build-timeout",
"conf-build-use-chroot": "command-ref/conf-file.html#conf-build-use-chroot",
"conf-build-use-sandbox": "command-ref/conf-file.html#conf-build-use-sandbox",
@@ -47,7 +46,6 @@ const redirects = {
"conf-connect-timeout": "command-ref/conf-file.html#conf-connect-timeout",
"conf-cores": "command-ref/conf-file.html#conf-cores",
"conf-diff-hook": "command-ref/conf-file.html#conf-diff-hook",
- "conf-enforce-determinism": "command-ref/conf-file.html#conf-enforce-determinism",
"conf-env-keep-derivations": "command-ref/conf-file.html#conf-env-keep-derivations",
"conf-extra-binary-caches": "command-ref/conf-file.html#conf-extra-binary-caches",
"conf-extra-platforms": "command-ref/conf-file.html#conf-extra-platforms",
@@ -74,7 +72,6 @@ const redirects = {
"conf-plugin-files": "command-ref/conf-file.html#conf-plugin-files",
"conf-post-build-hook": "command-ref/conf-file.html#conf-post-build-hook",
"conf-pre-build-hook": "command-ref/conf-file.html#conf-pre-build-hook",
- "conf-repeat": "command-ref/conf-file.html#conf-repeat",
"conf-require-sigs": "command-ref/conf-file.html#conf-require-sigs",
"conf-restrict-eval": "command-ref/conf-file.html#conf-restrict-eval",
"conf-run-diff-hook": "command-ref/conf-file.html#conf-run-diff-hook",
diff --git a/doc/manual/src/SUMMARY.md.in b/doc/manual/src/SUMMARY.md.in
index 908e7e3d9..6a514fa2c 100644
--- a/doc/manual/src/SUMMARY.md.in
+++ b/doc/manual/src/SUMMARY.md.in
@@ -65,6 +65,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.12 (2022-12-06)](release-notes/rl-2.12.md)
- [Release 2.11 (2022-08-25)](release-notes/rl-2.11.md)
- [Release 2.10 (2022-07-11)](release-notes/rl-2.10.md)
- [Release 2.9 (2022-05-30)](release-notes/rl-2.9.md)
diff --git a/doc/manual/src/advanced-topics/diff-hook.md b/doc/manual/src/advanced-topics/diff-hook.md
index 161e64b2a..4a742c160 100644
--- a/doc/manual/src/advanced-topics/diff-hook.md
+++ b/doc/manual/src/advanced-topics/diff-hook.md
@@ -121,37 +121,3 @@ error:
are not valid, so checking is not possible
Run the build without `--check`, and then try with `--check` again.
-
-# Automatic and Optionally Enforced Determinism Verification
-
-Automatically verify every build at build time by executing the build
-multiple times.
-
-Setting `repeat` and `enforce-determinism` in your `nix.conf` permits
-the automated verification of every build Nix performs.
-
-The following configuration will run each build three times, and will
-require the build to be deterministic:
-
- enforce-determinism = true
- repeat = 2
-
-Setting `enforce-determinism` to false as in the following
-configuration will run the build multiple times, execute the build
-hook, but will allow the build to succeed even if it does not build
-reproducibly:
-
- enforce-determinism = false
- repeat = 1
-
-An example output of this configuration:
-
-```console
-$ nix-build ./test.nix -A unstable
-this derivation will be built:
- /nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv
-building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 1/2)...
-building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 2/2)...
-output '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable' of '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' differs from '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable.check' from previous round
-/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable
-```
diff --git a/doc/manual/src/advanced-topics/post-build-hook.md b/doc/manual/src/advanced-topics/post-build-hook.md
index fcb52d878..1479cc3a4 100644
--- a/doc/manual/src/advanced-topics/post-build-hook.md
+++ b/doc/manual/src/advanced-topics/post-build-hook.md
@@ -33,12 +33,17 @@ distribute the public key for verifying the authenticity of the paths.
example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
```
-Then, add the public key and the cache URL to your `nix.conf`'s
-`trusted-public-keys` and `substituters` options:
+Then update [`nix.conf`](../command-ref/conf-file.md) on any machine that will access the cache.
+Add the cache URL to [`substituters`](../command-ref/conf-file.md#conf-substituters) and the public key to [`trusted-public-keys`](../command-ref/conf-file.md#conf-trusted-public-keys):
substituters = https://cache.nixos.org/ s3://example-nix-cache
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
+Machines that build for the cache must sign derivations using the private key.
+On those machines, add the path to the key file to the [`secret-key-files`](../command-ref/conf-file.md#conf-secret-key-files) field in their [`nix.conf`](../command-ref/conf-file.md):
+
+ secret-key-files = /etc/nix/key.private
+
We will restart the Nix daemon in a later step.
# Implementing the build hook
@@ -52,14 +57,12 @@ set -eu
set -f # disable globbing
export IFS=' '
-echo "Signing paths" $OUT_PATHS
-nix store sign --key-file /etc/nix/key.private $OUT_PATHS
echo "Uploading paths" $OUT_PATHS
-exec nix copy --to 's3://example-nix-cache' $OUT_PATHS
+exec nix copy --to "s3://example-nix-cache" $OUT_PATHS
```
> **Note**
->
+>
> The `$OUT_PATHS` variable is a space-separated list of Nix store
> paths. In this case, we expect and want the shell to perform word
> splitting to make each output path its own argument to `nix
diff --git a/doc/manual/src/command-ref/nix-build.md b/doc/manual/src/command-ref/nix-build.md
index 49c6f3f55..3a47feaae 100644
--- a/doc/manual/src/command-ref/nix-build.md
+++ b/doc/manual/src/command-ref/nix-build.md
@@ -53,16 +53,18 @@ All options not listed here are passed to `nix-store
--realise`, except for `--arg` and `--attr` / `-A` which are passed to
`nix-instantiate`.
- - [`--no-out-link`]{#opt-no-out-link}\
+ - [`--no-out-link`](#opt-no-out-link)
+
Do not create a symlink to the output path. Note that as a result
the output does not become a root of the garbage collector, and so
- might be deleted by `nix-store
- --gc`.
+ might be deleted by `nix-store --gc`.
+
+ - [`--dry-run`](#opt-dry-run)
- - [`--dry-run`]{#opt-dry-run}\
Show what store paths would be built or downloaded.
- - [`--out-link`]{#opt-out-link} / `-o` *outlink*\
+ - [`--out-link`](#opt-out-link) / `-o` *outlink*
+
Change the name of the symlink to the output path created from
`result` to *outlink*.
diff --git a/doc/manual/src/command-ref/nix-store.md b/doc/manual/src/command-ref/nix-store.md
index 1251888e9..b712a7463 100644
--- a/doc/manual/src/command-ref/nix-store.md
+++ b/doc/manual/src/command-ref/nix-store.md
@@ -22,7 +22,8 @@ This section lists the options that are common to all operations. These
options are allowed for every subcommand, though they may not always
have an effect.
- - [`--add-root`]{#opt-add-root} *path*\
+ - [`--add-root`](#opt-add-root) *path*
+
Causes the result of a realisation (`--realise` and
`--force-realise`) to be registered as a root of the garbage
collector. *path* will be created as a symlink to the resulting
@@ -104,10 +105,6 @@ The following flags are available:
previous build, the new output path is left in
`/nix/store/name.check.`
- See also the `build-repeat` configuration option, which repeats a
- derivation a number of times and prevents its outputs from being
- registered as “valid” in the Nix store unless they are identical.
-
Special exit codes:
- `100`\
diff --git a/doc/manual/src/installation/installing-binary.md b/doc/manual/src/installation/installing-binary.md
index 31faeadc2..a9378681d 100644
--- a/doc/manual/src/installation/installing-binary.md
+++ b/doc/manual/src/installation/installing-binary.md
@@ -88,6 +88,29 @@ extension. The installer will also create `/etc/profile.d/nix.sh`.
### 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
@@ -103,16 +126,6 @@ done
sudo groupdel 30000
```
-If you are on Linux with systemd, remove the Nix daemon service:
-
-```console
-sudo systemctl stop nix-daemon.socket
-sudo systemctl stop nix-daemon.service
-sudo systemctl disable nix-daemon.socket
-sudo systemctl disable nix-daemon.service
-sudo systemctl daemon-reload
-```
-
There may also be references to Nix in
- `/etc/profile`
diff --git a/doc/manual/src/release-notes/rl-2.12.md b/doc/manual/src/release-notes/rl-2.12.md
new file mode 100644
index 000000000..82de22cb4
--- /dev/null
+++ b/doc/manual/src/release-notes/rl-2.12.md
@@ -0,0 +1,43 @@
+# Release 2.12 (2022-12-06)
+
+* On Linux, Nix can now run builds in a user namespace where they run
+ as root (UID 0) and have 65,536 UIDs available.
+
+ This is primarily useful for running containers such as `systemd-nspawn`
+ inside a Nix build. For an example, see [`tests/systemd-nspawn/nix`][nspawn].
+
+ [nspawn]: https://github.com/NixOS/nix/blob/67bcb99700a0da1395fa063d7c6586740b304598/tests/systemd-nspawn.nix.
+
+ A build can enable this by setting the derivation attribute:
+
+ ```
+ requiredSystemFeatures = [ "uid-range" ];
+ ```
+
+ The `uid-range` [system feature] requires the [`auto-allocate-uids`]
+ setting to be enabled.
+
+ [system feature]: (../command-ref/conf-file.md#conf-system-features)
+
+* Nix can now automatically pick UIDs for builds, removing the need to
+ create `nixbld*` user accounts. See [`auto-allocate-uids`].
+
+ [`auto-allocate-uids`]: (../command-ref/conf-file.md#conf-auto-allocate-uids)
+
+* On Linux, Nix has experimental support for running builds inside a
+ cgroup. See
+ [`use-cgroups`](../command-ref/conf-file.md#conf-use-cgroups).
+
+* `` now accepts an additional argument `impure` which
+ defaults to `false`. If it is set to `true`, the `hash` and `sha256`
+ arguments will be ignored and the resulting derivation will have
+ `__impure` set to `true`, making it an impure derivation.
+
+* If `builtins.readFile` is called on a file with context, then only
+ the parts of the context that appear in the content of the file are
+ retained. This avoids a lot of spurious errors where strings end up
+ having a context just because they are read from a store path
+ ([#7260](https://github.com/NixOS/nix/pull/7260)).
+
+* `nix build --json` now prints some statistics about top-level
+ derivations, such as CPU statistics when cgroups are enabled.
diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
index 9a13a808e..a56dc25a2 100644
--- a/doc/manual/src/release-notes/rl-next.md
+++ b/doc/manual/src/release-notes/rl-next.md
@@ -1,14 +1,6 @@
# Release X.Y (202?-??-??)
-* `` now accepts an additional argument `impure` which
- defaults to `false`. If it is set to `true`, the `hash` and `sha256`
- arguments will be ignored and the resulting derivation will have
- `__impure` set to `true`, making it an impure derivation.
-
-* If `builtins.readFile` is called on a file with context, then only the parts
- of that context that appear in the content of the file are retained.
- This avoids a lot of spurious errors where some benign strings end-up having
- a context just because they are read from a store path
- ([#7260](https://github.com/NixOS/nix/pull/7260)).
+* The `repeat` and `enforce-determinism` options have been removed
+ since they had been broken under many circumstances for a long time.
* Allow explicitly selecting outputs with *store derivations* installable syntax too.
\ No newline at end of file
diff --git a/docker.nix b/docker.nix
index bb2b4e7ff..203a06b53 100644
--- a/docker.nix
+++ b/docker.nix
@@ -36,6 +36,17 @@ let
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/root";
gid = 0;
+ groups = [ "root" ];
+ description = "System administrator";
+ };
+
+ nobody = {
+ uid = 65534;
+ shell = "${pkgs.shadow}/bin/nologin";
+ home = "/var/empty";
+ gid = 65534;
+ groups = [ "nobody" ];
+ description = "Unprivileged account (don't use!)";
};
} // lib.listToAttrs (
@@ -57,6 +68,7 @@ let
groups = {
root.gid = 0;
nixbld.gid = 30000;
+ nobody.gid = 65534;
};
userToPasswd = (
diff --git a/flake.nix b/flake.nix
index cc2a48d9c..5127ee2a3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -9,14 +9,14 @@
let
- version = builtins.readFile ./.version + versionSuffix;
+ officialRelease = false;
+
+ version = nixpkgs.lib.fileContents ./.version + versionSuffix;
versionSuffix =
if officialRelease
then ""
else "pre${builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}_${self.shortRev or "dirty"}";
- officialRelease = false;
-
linux64BitSystems = [ "x86_64-linux" "aarch64-linux" ];
linuxSystems = linux64BitSystems ++ [ "i686-linux" ];
systems = linuxSystems ++ [ "x86_64-darwin" "aarch64-darwin" ];
@@ -506,6 +506,12 @@
overlay = self.overlays.default;
});
+ tests.containers = (import ./tests/containers.nix rec {
+ system = "x86_64-linux";
+ inherit nixpkgs;
+ overlay = self.overlays.default;
+ });
+
tests.setuid = nixpkgs.lib.genAttrs
["i686-linux" "x86_64-linux"]
(system:
diff --git a/maintainers/README.md b/maintainers/README.md
new file mode 100644
index 000000000..60768db0a
--- /dev/null
+++ b/maintainers/README.md
@@ -0,0 +1,79 @@
+# Nix maintainers team
+
+## Motivation
+
+The goal of the team is to help other people to contribute to Nix.
+
+## Members
+
+- Eelco Dolstra (@edolstra) – Team lead
+- Théophane Hufschmitt (@thufschmitt)
+- Valentin Gagarin (@fricklerhandwerk)
+- Thomas Bereknyei (@tomberek)
+- Robert Hensing (@roberth)
+
+## Meeting protocol
+
+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)
+
+- 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_.
+ 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).
+
+## Project board protocol
+
+The team uses a [GitHub project board](https://github.com/orgs/NixOS/projects/19/views/1) for tracking its work.
+
+Issues on the board progress through the following states:
+
+- No Status
+
+ Team members can add pull requests or issues to discuss or review together.
+
+ During the discussion meeting, the team triages new items.
+ If there is disagreement on the general idea behind an issue or pull request, it is moved to _To discuss_, otherwise to _In review_.
+
+- To discuss
+
+ Pull requests and issues that are 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.
+
+- 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.
+
+ 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
+
+ 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.
+
+The process is illustrated in the following diagram:
+
+```mermaid
+flowchart TD
+ discuss[To discuss]
+
+ review[To review]
+
+ New --> |Disagreement on idea| discuss
+ New & discuss --> |Consensus on idea| review
+
+ review --> |Consensus on implementation| Assigned
+
+ Assigned --> |Implementation issues arise| review
+ Assigned --> |Remaining issues fixed| Merged
+```
diff --git a/misc/launchd/org.nixos.nix-daemon.plist.in b/misc/launchd/org.nixos.nix-daemon.plist.in
index da1970f69..5fa489b20 100644
--- a/misc/launchd/org.nixos.nix-daemon.plist.in
+++ b/misc/launchd/org.nixos.nix-daemon.plist.in
@@ -28,7 +28,7 @@
SoftResourceLimits
NumberOfFiles
- 4096
+ 1048576
diff --git a/misc/systemd/nix-daemon.service.in b/misc/systemd/nix-daemon.service.in
index e3ac42beb..f46413630 100644
--- a/misc/systemd/nix-daemon.service.in
+++ b/misc/systemd/nix-daemon.service.in
@@ -9,7 +9,7 @@ ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket
[Service]
ExecStart=@@bindir@/nix-daemon nix-daemon --daemon
KillMode=process
-LimitNOFILE=4096
+LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index 96c0f302b..ec82e0560 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -97,13 +97,10 @@ is_os_darwin() {
}
contact_us() {
- echo "You can open an issue at https://github.com/nixos/nix/issues"
+ echo "You can open an issue at"
+ echo "https://github.com/NixOS/nix/issues/new?labels=installer&template=installer.md"
echo ""
- echo "Or feel free to contact the team:"
- echo " - Matrix: #nix:nixos.org"
- echo " - IRC: in #nixos on irc.libera.chat"
- echo " - twitter: @nixos_org"
- echo " - forum: https://discourse.nixos.org"
+ echo "Or get in touch with the community: https://nixos.org/community"
}
get_help() {
echo "We'd love to help if you need it."
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 176d655be..301e7bf4b 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -958,7 +958,7 @@ std::vector, BuiltPathWithResult>> Instal
case Realise::Outputs: {
if (settings.printMissing)
- printMissing(store, pathsToBuild, lvlInfo);
+ printMissing(store, pathsToBuild, lvlInfo);
for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) {
if (!buildResult.success())
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index bb254ff8d..557952277 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -270,6 +270,7 @@ void NixRepl::mainLoop()
// ctrl-D should exit the debugger.
state->debugStop = false;
state->debugQuit = true;
+ logger->cout("");
break;
}
try {
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 563f24e48..76a10b9f8 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -7,7 +7,6 @@
#include "globals.hh"
#include "eval-inline.hh"
#include "filetransfer.hh"
-#include "json.hh"
#include "function-trace.hh"
#include
@@ -21,6 +20,7 @@
#include
#include
+#include
#if HAVE_BOEHMGC
@@ -35,6 +35,8 @@
#endif
+using json = nlohmann::json;
+
namespace nix {
static char * allocString(size_t size)
@@ -69,15 +71,11 @@ static char * dupString(const char * s)
// empty string.
static const char * makeImmutableStringWithLen(const char * s, size_t size)
{
- char * t;
if (size == 0)
return "";
-#if HAVE_BOEHMGC
- t = GC_STRNDUP(s, size);
-#else
- t = strndup(s, size);
-#endif
- if (!t) throw std::bad_alloc();
+ auto t = allocString(size + 1);
+ memcpy(t, s, size);
+ t[size] = 0;
return t;
}
@@ -1648,7 +1646,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
auto dts = debugRepl
? makeDebugTraceStacker(
*this, *lambda.body, env2, positions[lambda.pos],
- "while evaluating %s",
+ "while calling %s",
lambda.name
? concatStrings("'", symbols[lambda.name], "'")
: "anonymous lambda")
@@ -1657,7 +1655,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
lambda.body->eval(*this, env2, vCur);
} catch (Error & e) {
if (loggerSettings.showTrace.get()) {
- addErrorTrace(e, lambda.pos, "while evaluating %s",
+ addErrorTrace(e, lambda.pos, "while calling %s",
(lambda.name
? concatStrings("'", symbols[lambda.name], "'")
: "anonymous lambda"));
@@ -2441,97 +2439,97 @@ void EvalState::printStats()
std::fstream fs;
if (outPath != "-")
fs.open(outPath, std::fstream::out);
- JSONObject topObj(outPath == "-" ? std::cerr : fs, true);
- topObj.attr("cpuTime",cpuTime);
- {
- auto envs = topObj.object("envs");
- envs.attr("number", nrEnvs);
- envs.attr("elements", nrValuesInEnvs);
- envs.attr("bytes", bEnvs);
- }
- {
- auto lists = topObj.object("list");
- lists.attr("elements", nrListElems);
- lists.attr("bytes", bLists);
- lists.attr("concats", nrListConcats);
- }
- {
- auto values = topObj.object("values");
- values.attr("number", nrValues);
- values.attr("bytes", bValues);
- }
- {
- auto syms = topObj.object("symbols");
- syms.attr("number", symbols.size());
- syms.attr("bytes", symbols.totalSize());
- }
- {
- auto sets = topObj.object("sets");
- sets.attr("number", nrAttrsets);
- sets.attr("bytes", bAttrsets);
- sets.attr("elements", nrAttrsInAttrsets);
- }
- {
- auto sizes = topObj.object("sizes");
- sizes.attr("Env", sizeof(Env));
- sizes.attr("Value", sizeof(Value));
- sizes.attr("Bindings", sizeof(Bindings));
- sizes.attr("Attr", sizeof(Attr));
- }
- topObj.attr("nrOpUpdates", nrOpUpdates);
- topObj.attr("nrOpUpdateValuesCopied", nrOpUpdateValuesCopied);
- topObj.attr("nrThunks", nrThunks);
- topObj.attr("nrAvoided", nrAvoided);
- topObj.attr("nrLookups", nrLookups);
- topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
- topObj.attr("nrFunctionCalls", nrFunctionCalls);
+ json topObj = json::object();
+ topObj["cpuTime"] = cpuTime;
+ topObj["envs"] = {
+ {"number", nrEnvs},
+ {"elements", nrValuesInEnvs},
+ {"bytes", bEnvs},
+ };
+ topObj["list"] = {
+ {"elements", nrListElems},
+ {"bytes", bLists},
+ {"concats", nrListConcats},
+ };
+ topObj["values"] = {
+ {"number", nrValues},
+ {"bytes", bValues},
+ };
+ topObj["symbols"] = {
+ {"number", symbols.size()},
+ {"bytes", symbols.totalSize()},
+ };
+ topObj["sets"] = {
+ {"number", nrAttrsets},
+ {"bytes", bAttrsets},
+ {"elements", nrAttrsInAttrsets},
+ };
+ topObj["sizes"] = {
+ {"Env", sizeof(Env)},
+ {"Value", sizeof(Value)},
+ {"Bindings", sizeof(Bindings)},
+ {"Attr", sizeof(Attr)},
+ };
+ topObj["nrOpUpdates"] = nrOpUpdates;
+ topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied;
+ topObj["nrThunks"] = nrThunks;
+ topObj["nrAvoided"] = nrAvoided;
+ topObj["nrLookups"] = nrLookups;
+ topObj["nrPrimOpCalls"] = nrPrimOpCalls;
+ topObj["nrFunctionCalls"] = nrFunctionCalls;
#if HAVE_BOEHMGC
- {
- auto gc = topObj.object("gc");
- gc.attr("heapSize", heapSize);
- gc.attr("totalBytes", totalBytes);
- }
+ topObj["gc"] = {
+ {"heapSize", heapSize},
+ {"totalBytes", totalBytes},
+ };
#endif
if (countCalls) {
+ topObj["primops"] = primOpCalls;
{
- auto obj = topObj.object("primops");
- for (auto & i : primOpCalls)
- obj.attr(i.first, i.second);
- }
- {
- auto list = topObj.list("functions");
+ auto& list = topObj["functions"];
+ list = json::array();
for (auto & [fun, count] : functionCalls) {
- auto obj = list.object();
+ json obj = json::object();
if (fun->name)
- obj.attr("name", (std::string_view) symbols[fun->name]);
+ obj["name"] = (std::string_view) symbols[fun->name];
else
- obj.attr("name", nullptr);
+ obj["name"] = nullptr;
if (auto pos = positions[fun->pos]) {
- obj.attr("file", (std::string_view) pos.file);
- obj.attr("line", pos.line);
- obj.attr("column", pos.column);
+ obj["file"] = (std::string_view) pos.file;
+ obj["line"] = pos.line;
+ obj["column"] = pos.column;
}
- obj.attr("count", count);
+ obj["count"] = count;
+ list.push_back(obj);
}
}
{
- auto list = topObj.list("attributes");
+ auto list = topObj["attributes"];
+ list = json::array();
for (auto & i : attrSelects) {
- auto obj = list.object();
+ json obj = json::object();
if (auto pos = positions[i.first]) {
- obj.attr("file", (const std::string &) pos.file);
- obj.attr("line", pos.line);
- obj.attr("column", pos.column);
+ obj["file"] = (const std::string &) pos.file;
+ obj["line"] = pos.line;
+ obj["column"] = pos.column;
}
- obj.attr("count", i.second);
+ obj["count"] = i.second;
+ list.push_back(obj);
}
}
}
if (getEnv("NIX_SHOW_SYMBOLS").value_or("0") != "0") {
- auto list = topObj.list("symbols");
- symbols.dump([&](const std::string & s) { list.elem(s); });
+ // XXX: overrides earlier assignment
+ topObj["symbols"] = json::array();
+ auto &list = topObj["symbols"];
+ symbols.dump([&](const std::string & s) { list.emplace_back(s); });
+ }
+ if (outPath == "-") {
+ std::cerr << topObj.dump(2) << std::endl;
+ } else {
+ fs << topObj.dump(2) << std::endl;
}
}
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 22f6ad3cc..8a4c19f7c 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -8,12 +8,12 @@
#include "references.hh"
#include "store-api.hh"
#include "util.hh"
-#include "json.hh"
#include "value-to-json.hh"
#include "value-to-xml.hh"
#include "primops.hh"
#include
+#include
#include
#include
@@ -1011,6 +1011,7 @@ static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Val
derivation. */
static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
+ using nlohmann::json;
state.forceAttrs(*args[0], pos);
/* Figure out the name first (for stack backtraces). */
@@ -1032,11 +1033,10 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
}
/* Check whether attributes should be passed as a JSON file. */
- std::ostringstream jsonBuf;
- std::unique_ptr jsonObject;
+ std::optional jsonObject;
attr = args[0]->attrs->find(state.sStructuredAttrs);
if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos))
- jsonObject = std::make_unique(jsonBuf);
+ jsonObject = json::object();
/* Check whether null attributes should be ignored. */
bool ignoreNulls = false;
@@ -1138,8 +1138,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
if (i->name == state.sStructuredAttrs) continue;
- auto placeholder(jsonObject->placeholder(key));
- printValueAsJSON(state, true, *i->value, pos, placeholder, context);
+ (*jsonObject)[key] = printValueAsJSON(state, true, *i->value, pos, context);
if (i->name == state.sBuilder)
drv.builder = state.forceString(*i->value, context, posDrvName);
@@ -1183,8 +1182,8 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
}
if (jsonObject) {
+ drv.env.emplace("__json", jsonObject->dump());
jsonObject.reset();
- drv.env.emplace("__json", jsonBuf.str());
}
/* Everything in the context of the strings in the derivation
@@ -2421,12 +2420,18 @@ static RegisterPrimOp primop_listToAttrs({
Construct a set from a list specifying the names and values of each
attribute. Each element of the list should be a set consisting of a
string-valued attribute `name` specifying the name of the attribute,
- and an attribute `value` specifying its value. Example:
+ and an attribute `value` specifying its value.
+
+ In case of duplicate occurrences of the same name, the first
+ takes precedence.
+
+ Example:
```nix
builtins.listToAttrs
[ { name = "foo"; value = 123; }
{ name = "bar"; value = 456; }
+ { name = "bar"; value = 420; }
]
```
diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc
index 4d63d8b49..5dc453b2e 100644
--- a/src/libexpr/value-to-json.cc
+++ b/src/libexpr/value-to-json.cc
@@ -1,84 +1,82 @@
#include "value-to-json.hh"
-#include "json.hh"
#include "eval-inline.hh"
#include "util.hh"
#include
#include
+#include
namespace nix {
-
-void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context, bool copyToStore)
+using json = nlohmann::json;
+json printValueAsJSON(EvalState & state, bool strict,
+ Value & v, const PosIdx pos, PathSet & context, bool copyToStore)
{
checkInterrupt();
if (strict) state.forceValue(v, pos);
+ json out;
+
switch (v.type()) {
case nInt:
- out.write(v.integer);
+ out = v.integer;
break;
case nBool:
- out.write(v.boolean);
+ out = v.boolean;
break;
case nString:
copyContext(v, context);
- out.write(v.string.s);
+ out = v.string.s;
break;
case nPath:
if (copyToStore)
- out.write(state.copyPathToStore(context, v.path));
+ out = state.copyPathToStore(context, v.path);
else
- out.write(v.path);
+ out = v.path;
break;
case nNull:
- out.write(nullptr);
break;
case nAttrs: {
auto maybeString = state.tryAttrsToString(pos, v, context, false, false);
if (maybeString) {
- out.write(*maybeString);
+ out = *maybeString;
break;
}
auto i = v.attrs->find(state.sOutPath);
if (i == v.attrs->end()) {
- auto obj(out.object());
+ out = json::object();
StringSet names;
for (auto & j : *v.attrs)
names.emplace(state.symbols[j.name]);
for (auto & j : names) {
Attr & a(*v.attrs->find(state.symbols.create(j)));
- auto placeholder(obj.placeholder(j));
- printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context, copyToStore);
+ out[j] = printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore);
}
} else
- printValueAsJSON(state, strict, *i->value, i->pos, out, context, copyToStore);
+ return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
break;
}
case nList: {
- auto list(out.list());
- for (auto elem : v.listItems()) {
- auto placeholder(list.placeholder());
- printValueAsJSON(state, strict, *elem, pos, placeholder, context, copyToStore);
- }
+ out = json::array();
+ for (auto elem : v.listItems())
+ out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore));
break;
}
case nExternal:
- v.external->printValueAsJSON(state, strict, out, context, copyToStore);
+ return v.external->printValueAsJSON(state, strict, context, copyToStore);
break;
case nFloat:
- out.write(v.fpoint);
+ out = v.fpoint;
break;
case nThunk:
@@ -91,17 +89,17 @@ void printValueAsJSON(EvalState & state, bool strict,
state.debugThrowLastTrace(e);
throw e;
}
+ return out;
}
void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore)
{
- JSONPlaceholder out(str);
- printValueAsJSON(state, strict, v, pos, out, context, copyToStore);
+ str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
}
-void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
- JSONPlaceholder & out, PathSet & context, bool copyToStore) const
+json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
+ PathSet & context, bool copyToStore) const
{
state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType()));
}
diff --git a/src/libexpr/value-to-json.hh b/src/libexpr/value-to-json.hh
index 7ddc8a5b1..22f26b790 100644
--- a/src/libexpr/value-to-json.hh
+++ b/src/libexpr/value-to-json.hh
@@ -5,13 +5,12 @@
#include
#include