diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index 763c5f27ee6..00000000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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
-
-# This file
-.github/CODEOWNERS @edolstra
-
-# Documentation of built-in functions
-src/libexpr/primops.cc @roberth
-
-# Libstore layer
-/src/libstore @ericson2314
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index af94c3e9e5b..08a5851748d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,10 +1,9 @@
---
name: Bug report
about: Report unexpected or incorrect behaviour
-title: ''
+title: ""
labels: bug
-assignees: ''
-
+assignees: ""
---
## Describe the bug
@@ -32,7 +31,9 @@ assignees: ''
## Metadata
-
+
+
+
## Additional context
@@ -42,13 +43,9 @@ assignees: ''
-- [ ] checked [latest Nix manual] \([source])
+- [ ] checked [latest Determinate Nix manual] \([source])
- [ ] checked [open bug issues and pull requests] for possible duplicates
-[latest Nix manual]: https://nix.dev/manual/nix/development/
-[source]: https://github.com/NixOS/nix/tree/master/doc/manual/source
-[open bug issues and pull requests]: https://github.com/NixOS/nix/labels/bug
-
----
-
-Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
+[latest Determinate Nix manual]: https://manual.determinate.systems/
+[source]: https://github.com/DeterminateSystems/nix-src/tree/main/doc/manual/source
+[open bug issues and pull requests]: https://github.com/DeterminateSystems/nix-src/labels/bug
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index fe9f9dd209d..b88e1093798 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,10 +1,9 @@
---
name: Feature request
about: Suggest a new feature
-title: ''
+title: ""
labels: feature
-assignees: ''
-
+assignees: ""
---
## Is your feature request related to a problem?
@@ -27,13 +26,9 @@ assignees: ''
-- [ ] checked [latest Nix manual] \([source])
-- [ ] checked [open feature issues and pull requests] for possible duplicates
-
-[latest Nix manual]: https://nix.dev/manual/nix/development/
-[source]: https://github.com/NixOS/nix/tree/master/doc/manual/source
-[open feature issues and pull requests]: https://github.com/NixOS/nix/labels/feature
-
----
+- [ ] checked [latest Determinate Nix manual] \([source])
+- [ ] checked [open bug issues and pull requests] for possible duplicates
-Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
+[latest Determinate Nix manual]: https://manual.determinate.systems/
+[source]: https://github.com/DeterminateSystems/nix-src/tree/main/doc/manual/source
+[open bug issues and pull requests]: https://github.com/DeterminateSystems/nix-src/labels/bug
diff --git a/.github/ISSUE_TEMPLATE/installer.md b/.github/ISSUE_TEMPLATE/installer.md
index 070e0bd9b25..430bef971aa 100644
--- a/.github/ISSUE_TEMPLATE/installer.md
+++ b/.github/ISSUE_TEMPLATE/installer.md
@@ -1,18 +1,17 @@
---
name: Installer issue
about: Report problems with installation
-title: ''
+title: ""
labels: installer
-assignees: ''
-
+assignees: ""
---
## Platform
-
+
-- [ ] Linux:
- [ ] macOS
+- [ ] Linux:
- [ ] WSL
## Additional information
@@ -35,13 +34,9 @@ assignees: ''
-- [ ] checked [latest Nix manual] \([source])
-- [ ] checked [open installer issues and pull requests] for possible duplicates
-
-[latest Nix manual]: https://nix.dev/manual/nix/development/
-[source]: https://github.com/NixOS/nix/tree/master/doc/manual/source
-[open installer issues and pull requests]: https://github.com/NixOS/nix/labels/installer
-
----
+- [ ] checked [latest Determinate Nix manual] \([source])
+- [ ] checked [open bug issues and pull requests] for possible duplicates
-Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
+[latest Determinate Nix manual]: https://manual.determinate.systems/
+[source]: https://github.com/DeterminateSystems/nix-src/tree/main/doc/manual/source
+[open bug issues and pull requests]: https://github.com/DeterminateSystems/nix-src/labels/bug
diff --git a/.github/ISSUE_TEMPLATE/missing_documentation.md b/.github/ISSUE_TEMPLATE/missing_documentation.md
index 4e05b626d39..fcdd0d20135 100644
--- a/.github/ISSUE_TEMPLATE/missing_documentation.md
+++ b/.github/ISSUE_TEMPLATE/missing_documentation.md
@@ -1,10 +1,9 @@
---
name: Missing or incorrect documentation
about: Help us improve the reference manual
-title: ''
+title: ""
labels: documentation
-assignees: ''
-
+assignees: ""
---
## Problem
@@ -19,13 +18,9 @@ assignees: ''
-- [ ] checked [latest Nix manual] \([source])
-- [ ] checked [open documentation issues and pull requests] for possible duplicates
-
-[latest Nix manual]: https://nix.dev/manual/nix/development/
-[source]: https://github.com/NixOS/nix/tree/master/doc/manual/source
-[open documentation issues and pull requests]: https://github.com/NixOS/nix/labels/documentation
-
----
+- [ ] checked [latest Determinate Nix manual] \([source])
+- [ ] checked [open bug issues and pull requests] for possible duplicates
-Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
+[latest Determinate Nix manual]: https://manual.determinate.systems/
+[source]: https://github.com/DeterminateSystems/nix-src/tree/main/doc/manual/source
+[open bug issues and pull requests]: https://github.com/DeterminateSystems/nix-src/labels/bug
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index c6843d86fa7..d3e1f817736 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,22 +1,3 @@
-
-
## Motivation
@@ -30,9 +11,3 @@ so you understand the process and the expectations.
-
----
-
-Add :+1: to [pull requests you find important](https://github.com/NixOS/nix/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc).
-
-The Nix maintainer team uses a [GitHub project board](https://github.com/orgs/NixOS/projects/19) to [schedule and track reviews](https://github.com/NixOS/nix/tree/master/maintainers#project-board-protocol).
diff --git a/.github/STALE-BOT.md b/.github/STALE-BOT.md
index bc0005413f1..281d0f79a8b 100644
--- a/.github/STALE-BOT.md
+++ b/.github/STALE-BOT.md
@@ -2,34 +2,21 @@
- Thanks for your contribution!
- To remove the stale label, just leave a new comment.
-- _How to find the right people to ping?_ → [`git blame`](https://git-scm.com/docs/git-blame) to the rescue! (or GitHub's history and blame buttons.)
-- You can always ask for help on [our Discourse Forum](https://discourse.nixos.org/) or on [Matrix - #users:nixos.org](https://matrix.to/#/#users:nixos.org).
+- You can always ask for help on [Discord](https://determinate.systems/discord).
## Suggestions for PRs
-1. GitHub sometimes doesn't notify people who commented / reviewed a PR previously, when you (force) push commits. If you have addressed the reviews you can [officially ask for a review](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/requesting-a-pull-request-review) from those who commented to you or anyone else.
-2. If it is unfinished but you plan to finish it, please mark it as a draft.
-3. If you don't expect to work on it any time soon, closing it with a short comment may encourage someone else to pick up your work.
-4. To get things rolling again, rebase the PR against the target branch and address valid comments.
-5. If you need a review to move forward, ask in [the Discourse thread for PRs that need help](https://discourse.nixos.org/t/prs-in-distress/3604).
-6. If all you need is a merge, check the git history to find and [request reviews](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/requesting-a-pull-request-review) from people who usually merge related contributions.
+1. If it is unfinished but you plan to finish it, please mark it as a draft.
+1. If you don't expect to work on it any time soon, closing it with a short comment may encourage someone else to pick up your work.
+1. To get things rolling again, rebase the PR against the target branch and address valid comments.
+1. If you need a review to move forward, ask in [Discord](https://determinate.systems/discord).
## Suggestions for issues
1. If it is resolved (either for you personally, or in general), please consider closing it.
2. If this might still be an issue, but you are not interested in promoting its resolution, please consider closing it while encouraging others to take over and reopen an issue if they care enough.
-3. If you still have interest in resolving it, try to ping somebody who you believe might have an interest in the topic. Consider discussing the problem in [our Discourse Forum](https://discourse.nixos.org/).
-4. As with all open source projects, your best option is to submit a Pull Request that addresses this issue. We :heart: this attitude!
+3. If you still have interest in resolving it, try to ping somebody who you believe might have an interest in the topic. Consider discussing the problem in [Discord](https://determinate.systems/discord).
**Memorandum on closing issues**
Don't be afraid to close an issue that holds valuable information. Closed issues stay in the system for people to search, read, cross-reference, or even reopen--nothing is lost! Closing obsolete issues is an important way to help maintainers focus their time and effort.
-
-## Useful GitHub search queries
-
-- [Open PRs with any stale-bot interaction](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+commenter%3Aapp%2Fstale+)
-- [Open PRs with any stale-bot interaction and `stale`](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+commenter%3Aapp%2Fstale+label%3A%22stale%22)
-- [Open PRs with any stale-bot interaction and NOT `stale`](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+commenter%3Aapp%2Fstale+-label%3A%22stale%22+)
-- [Open Issues with any stale-bot interaction](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+commenter%3Aapp%2Fstale+)
-- [Open Issues with any stale-bot interaction and `stale`](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+commenter%3Aapp%2Fstale+label%3A%22stale%22+)
-- [Open Issues with any stale-bot interaction and NOT `stale`](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+commenter%3Aapp%2Fstale+-label%3A%22stale%22+)
diff --git a/.github/release-notes.sh b/.github/release-notes.sh
new file mode 100755
index 00000000000..f641e146d2e
--- /dev/null
+++ b/.github/release-notes.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+
+# SC2002 disables "useless cat" warnings.
+# I prefer pipelines that start with an explicit input, and go from there.
+# Overly fussy.
+# shellcheck disable=SC2002
+
+scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
+finish() {
+ rm -rf "$scratch"
+}
+trap finish EXIT
+
+DATE=$(date +%Y-%m-%d)
+DETERMINATE_NIX_VERSION=$(cat .version-determinate)
+TAG_NAME="v${DETERMINATE_NIX_VERSION}"
+NIX_VERSION=$(cat .version)
+NIX_VERSION_MAJOR_MINOR=$(echo "$NIX_VERSION" | cut -d. -f1,2)
+GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-DeterminateSystems/nix-src}"
+
+gh api "/repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
+ -f "tag_name=${TAG_NAME}" > "$scratch/notes.json"
+
+trim_trailing_newlines() {
+ local text
+ text="$(cat)"
+ echo -n "${text}"
+}
+
+linkify_gh() {
+ sed \
+ -e 's!\(https://github.com/DeterminateSystems/nix-src/\(pull\|issue\)/\([[:digit:]]\+\)\)!' \
+ -e 's#\(https://github.com/DeterminateSystems/nix-src/compare/\([^ ]\+\)\)#[\2](\1)#'
+}
+
+(
+ cat doc/manual/source/release-notes-determinate/changes.md \
+ | sed 's/^.*\(\)$/This section lists the differences between upstream Nix '"$NIX_VERSION_MAJOR_MINOR"' and Determinate Nix '"$DETERMINATE_NIX_VERSION"'.\1/' \
+
+ printf "\n\n" "$DETERMINATE_NIX_VERSION"
+ cat "$scratch/notes.json" \
+ | jq -r .body \
+ | grep -v '^#' \
+ | grep -v "Full Changelog" \
+ | trim_trailing_newlines \
+ | sed -e 's/^\* /\n* /' \
+ | linkify_gh
+ echo "" # final newline
+) > "$scratch/changes.md"
+
+(
+ printf "# Release %s (%s)\n\n" \
+ "$DETERMINATE_NIX_VERSION" \
+ "$DATE"
+ printf "* Based on [upstream Nix %s](../release-notes/rl-%s.md).\n\n" \
+ "$NIX_VERSION" \
+ "$NIX_VERSION_MAJOR_MINOR"
+
+ cat "$scratch/notes.json" | jq -r .body | linkify_gh
+) > "$scratch/rl.md"
+
+(
+ cat doc/manual/source/SUMMARY.md.in \
+ | sed 's/\(\)$/\1\n - [Release '"$DETERMINATE_NIX_VERSION"' ('"$DATE"')](release-notes-determinate\/'"$TAG_NAME"'.md)/'
+) > "$scratch/summary.md"
+
+mv "$scratch/changes.md" doc/manual/source/release-notes-determinate/changes.md
+mv "$scratch/rl.md" "doc/manual/source/release-notes-determinate/v${DETERMINATE_NIX_VERSION}.md"
+mv "$scratch/summary.md" doc/manual/source/SUMMARY.md.in
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000000..dd98d0d00f9
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,241 @@
+on:
+ workflow_call:
+ inputs:
+ system:
+ required: true
+ type: string
+ runner:
+ required: true
+ type: string
+ runner_for_virt:
+ required: true
+ type: string
+ runner_small:
+ required: true
+ type: string
+ if:
+ required: false
+ default: true
+ type: boolean
+ run_tests:
+ required: false
+ default: true
+ type: boolean
+ run_vm_tests:
+ required: false
+ default: false
+ type: boolean
+ run_regression_tests:
+ required: false
+ default: false
+ type: boolean
+ publish_manual:
+ required: false
+ default: false
+ type: boolean
+ secrets:
+ manual_netlify_auth_token:
+ required: false
+ manual_netlify_site_id:
+ required: false
+
+jobs:
+ build:
+ if: ${{ inputs.if }}
+ strategy:
+ fail-fast: false
+ runs-on: ${{ inputs.runner }}
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - run: nix build .#packages.${{ inputs.system }}.default .#packages.${{ inputs.system }}.binaryTarball --no-link -L
+ - run: nix build .#packages.${{ inputs.system }}.binaryTarball --out-link tarball
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ inputs.system }}
+ path: ./tarball/*.xz
+
+ test:
+ if: ${{ inputs.if && inputs.run_tests}}
+ needs: build
+ strategy:
+ fail-fast: false
+ runs-on: ${{ inputs.runner }}
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - run: nix flake check -L --system ${{ inputs.system }}
+
+ vm_tests_smoke:
+ if: inputs.run_vm_tests && github.event_name != 'merge_group'
+ needs: build
+ runs-on: ${{ inputs.runner_for_virt }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - run: |
+ nix build -L \
+ .#hydraJobs.tests.functional_user \
+ .#hydraJobs.tests.githubFlakes \
+ .#hydraJobs.tests.nix-docker \
+ .#hydraJobs.tests.tarballFlakes \
+ ;
+
+ vm_tests_all:
+ if: inputs.run_vm_tests && github.event_name == 'merge_group'
+ needs: build
+ runs-on: ${{ inputs.runner_for_virt }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - run: |
+ cmd() {
+ nix build -L --keep-going --timeout 600 \
+ $(nix flake show --json \
+ | jq -r '
+ .hydraJobs.tests
+ | with_entries(select(.value.type == "derivation"))
+ | keys[]
+ | ".#hydraJobs.tests." + .')
+ }
+
+ if ! cmd; then
+ echo "failed, retrying once ..."
+ printf "\n\n\n\n\n\n\n\n"
+ cmd
+ fi
+
+ flake_regressions:
+ if: |
+ (inputs.run_regression_tests && github.event_name == 'merge_group')
+ || (
+ inputs.run_regression_tests
+ && github.event.pull_request.head.repo.full_name == 'DeterminateSystems/nix-src'
+ && (
+ (github.event.action == 'labeled' && github.event.label.name == 'flake-regression-test')
+ || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'flake-regression-test'))
+ )
+ )
+ needs: build
+ runs-on: ${{ inputs.runner }}
+ strategy:
+ matrix:
+ nix_config:
+ - "lazy-trees = true"
+ - "lazy-trees = false"
+ - "eval-cores = 24"
+ glob:
+ - "[0-d]*"
+ - "[e-l]*"
+ - "[m]*"
+ - "[n-r]*"
+ - "[s-z]*"
+
+ steps:
+ - name: Checkout nix
+ uses: actions/checkout@v4
+ - name: Checkout flake-regressions
+ uses: actions/checkout@v4
+ with:
+ repository: DeterminateSystems/flake-regressions
+ path: flake-regressions
+ - name: Checkout flake-regressions-data
+ uses: actions/checkout@v4
+ with:
+ repository: DeterminateSystems/flake-regressions-data
+ path: flake-regressions/tests
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - name: Run flake regression tests
+ env:
+ #PARALLEL: ${{ !contains(matrix.nix_config, 'eval-cores') && '-P 50%' || '-P 1' }}
+ PARALLEL: '-P 1'
+ FLAKE_REGRESSION_GLOB: ${{ matrix.glob }}
+ NIX_CONFIG: ${{ matrix.nix_config }}
+ PREFETCH: "1"
+ run: |
+ set -x
+ echo "PARALLEL: $PARALLEL"
+ echo "NIX_CONFIG: $NIX_CONFIG"
+ if [ ! -z "${NSC_CACHE_PATH:-}" ]; then
+ mkdir -p "${NSC_CACHE_PATH}/nix/xdg-cache"
+ export XDG_CACHE_HOME="${NSC_CACHE_PATH}/nix/xdg-cache"
+ fi
+ nix build -L --out-link ./new-nix
+ export PATH=$(pwd)/new-nix/bin:$PATH
+ [[ $(type -p nix) = $(pwd)/new-nix/bin/nix ]]
+
+ nix config show lazy-trees
+ nix config show eval-cores
+ lscpu
+ nproc
+
+ if ! flake-regressions/eval-all.sh; then
+ echo "Some failed, trying again"
+ printf "\n\n\n\n\n\n\n\n"
+ NIX_REMOTE=/tmp/nix flake-regressions/eval-all.sh
+ fi
+
+ manual:
+ if: github.event_name != 'merge_group'
+ needs: build
+ runs-on: ${{ inputs.runner_small }}
+ permissions:
+ id-token: "write"
+ contents: "read"
+ pull-requests: "write"
+ statuses: "write"
+ deployments: "write"
+ steps:
+ - name: Checkout nix
+ uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-cache-action@main
+ - name: Build manual
+ if: inputs.system == 'x86_64-linux'
+ run: nix build .#hydraJobs.manual
+ - uses: nwtgck/actions-netlify@v3.0
+ if: inputs.publish_manual && inputs.system == 'x86_64-linux'
+ with:
+ publish-dir: "./result/share/doc/nix/manual"
+ production-branch: main
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ deploy-message: "Deploy from GitHub Actions"
+ # NOTE(cole-h): We have a perpetual PR displaying our changes against upstream open, but
+ # its conversation is locked, so this PR comment can never be posted.
+ # https://github.com/DeterminateSystems/nix-src/pull/165
+ enable-pull-request-comment: ${{ github.event.pull_request.number != 165 }}
+ enable-commit-comment: true
+ enable-commit-status: true
+ overwrites-pull-request-comment: true
+ env:
+ NETLIFY_AUTH_TOKEN: ${{ secrets.manual_netlify_auth_token }}
+ NETLIFY_SITE_ID: ${{ secrets.manual_netlify_site_id }}
+
+ success:
+ needs:
+ - build
+ - test
+ - vm_tests_smoke
+ - vm_tests_all
+ - flake_regressions
+ - manual
+ if: ${{ always() }}
+ runs-on: ubuntu-latest
+ steps:
+ - run: "true"
+ - run: |
+ echo "A dependent in the build matrix failed:"
+ echo "$needs"
+ exit 1
+ env:
+ needs: ${{ toJSON(needs) }}
+ if: |
+ contains(needs.*.result, 'failure') ||
+ contains(needs.*.result, 'cancelled')
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e7e103b6320..29b6cbf36ea 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,280 +2,178 @@ name: "CI"
on:
pull_request:
- merge_group:
push:
- workflow_dispatch:
- inputs:
- dogfood:
- description: 'Use dogfood Nix build'
- required: false
- default: true
- type: boolean
+ branches:
+ # NOTE: make sure any branches here are also valid directory names,
+ # otherwise creating the directory and uploading to s3 will fail
+ - main
+ - master
+ merge_group:
+ release:
+ types:
+ - published
-permissions: read-all
+permissions:
+ id-token: "write"
+ contents: "read"
+ pull-requests: "write"
+ statuses: "write"
+ deployments: "write"
jobs:
eval:
- runs-on: ubuntu-24.04
+ runs-on: UbuntuLatest32Cores128G
steps:
- - uses: actions/checkout@v5
- with:
- fetch-depth: 0
- - uses: ./.github/actions/install-nix-action
- with:
- dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
- extra_nix_config:
- experimental-features = nix-command flakes
- github_token: ${{ secrets.GITHUB_TOKEN }}
- - run: nix flake show --all-systems --json
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - run: nix flake show --all-systems --json
- tests:
- strategy:
- fail-fast: false
- matrix:
- include:
- - scenario: on ubuntu
- runs-on: ubuntu-24.04
- os: linux
- instrumented: false
- primary: true
- stdenv: stdenv
- - scenario: on macos
- runs-on: macos-14
- os: darwin
- instrumented: false
- primary: true
- stdenv: stdenv
- - scenario: on ubuntu (with sanitizers / coverage)
- runs-on: ubuntu-24.04
- os: linux
- instrumented: true
- primary: false
- stdenv: clangStdenv
- name: tests ${{ matrix.scenario }}
- runs-on: ${{ matrix.runs-on }}
- timeout-minutes: 60
- steps:
- - uses: actions/checkout@v5
- with:
- fetch-depth: 0
- - uses: ./.github/actions/install-nix-action
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
- # The sandbox would otherwise be disabled by default on Darwin
- extra_nix_config: "sandbox = true"
- - uses: DeterminateSystems/magic-nix-cache-action@main
- # Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
- # https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
- - run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- if: matrix.os == 'linux'
- - name: Run component tests
- run: |
- nix build --file ci/gha/tests/wrapper.nix componentTests -L \
- --arg withInstrumentation ${{ matrix.instrumented }} \
- --argstr stdenv "${{ matrix.stdenv }}"
- - name: Run flake checks and prepare the installer tarball
- run: |
- ci/gha/tests/build-checks
- ci/gha/tests/prepare-installer-for-github-actions
- if: ${{ matrix.primary }}
- - name: Collect code coverage
- run: |
- nix build --file ci/gha/tests/wrapper.nix codeCoverage.coverageReports -L \
- --arg withInstrumentation ${{ matrix.instrumented }} \
- --argstr stdenv "${{ matrix.stdenv }}" \
- --out-link coverage-reports
- cat coverage-reports/index.txt >> $GITHUB_STEP_SUMMARY
- if: ${{ matrix.instrumented }}
- - name: Upload coverage reports
- uses: actions/upload-artifact@v4
- with:
- name: coverage-reports
- path: coverage-reports/
- if: ${{ matrix.instrumented }}
- - name: Upload installer tarball
- uses: actions/upload-artifact@v4
- with:
- name: installer-${{matrix.os}}
- path: out/*
- if: ${{ matrix.primary }}
+ build_x86_64-linux:
+ uses: ./.github/workflows/build.yml
+ with:
+ system: x86_64-linux
+ runner: namespace-profile-linuxamd32c64g-cache
+ runner_for_virt: UbuntuLatest32Cores128G
+ runner_small: ubuntu-latest
+ run_tests: true
+ run_vm_tests: true
+ run_regression_tests: true
+ publish_manual: true
+ secrets:
+ manual_netlify_auth_token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
+ manual_netlify_site_id: ${{ secrets.NETLIFY_SITE_ID }}
- installer_test:
- needs: [tests]
- strategy:
- fail-fast: false
- matrix:
- include:
- - scenario: on ubuntu
- runs-on: ubuntu-24.04
- os: linux
- - scenario: on macos
- runs-on: macos-14
- os: darwin
- name: installer test ${{ matrix.scenario }}
- runs-on: ${{ matrix.runs-on }}
- steps:
- - uses: actions/checkout@v5
- - name: Download installer tarball
- uses: actions/download-artifact@v5
- with:
- name: installer-${{matrix.os}}
- path: out
- - name: Looking up the installer tarball URL
- id: installer-tarball-url
- run: echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
- - uses: cachix/install-nix-action@v31
- with:
- install_url: ${{ format('{0}/install', steps.installer-tarball-url.outputs.installer-url) }}
- install_options: ${{ format('--tarball-url-prefix {0}', steps.installer-tarball-url.outputs.installer-url) }}
- - run: sudo apt install fish zsh
- if: matrix.os == 'linux'
- - run: brew install fish
- if: matrix.os == 'darwin'
- - run: exec bash -c "nix-instantiate -E 'builtins.currentTime' --eval"
- - run: exec sh -c "nix-instantiate -E 'builtins.currentTime' --eval"
- - run: exec zsh -c "nix-instantiate -E 'builtins.currentTime' --eval"
- - run: exec fish -c "nix-instantiate -E 'builtins.currentTime' --eval"
- - run: exec bash -c "nix-channel --add https://releases.nixos.org/nixos/unstable/nixos-23.05pre466020.60c1d71f2ba nixpkgs"
- - run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"
+ build_aarch64-linux:
+ uses: ./.github/workflows/build.yml
+ with:
+ if: ${{
+ github.event_name != 'pull_request'
+ || (
+ github.event.pull_request.head.repo.full_name == 'DeterminateSystems/nix-src'
+ && (
+ (github.event.action == 'labeled' && github.event.label.name == 'upload to s3')
+ || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'upload to s3'))
+ )
+ )
+ }}
+ system: aarch64-linux
+ runner: UbuntuLatest32Cores128GArm
+ runner_for_virt: UbuntuLatest32Cores128GArm
+ runner_small: UbuntuLatest32Cores128GArm
- # Steps to test CI automation in your own fork.
- # 1. Sign-up for https://hub.docker.com/
- # 2. Store your dockerhub username as DOCKERHUB_USERNAME in "Repository secrets" of your fork repository settings (https://github.com/$githubuser/nix/settings/secrets/actions)
- # 3. Create an access token in https://hub.docker.com/settings/security and store it as DOCKERHUB_TOKEN in "Repository secrets" of your fork
- check_secrets:
- permissions:
- contents: none
- name: Check presence of secrets
- runs-on: ubuntu-24.04
- outputs:
- docker: ${{ steps.secret.outputs.docker }}
+ build_x86_64-darwin:
+ uses: ./.github/workflows/build.yml
+ with:
+ if: ${{
+ github.event_name != 'pull_request'
+ || (
+ github.event.pull_request.head.repo.full_name == 'DeterminateSystems/nix-src'
+ && (
+ (github.event.action == 'labeled' && github.event.label.name == 'upload to s3')
+ || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'upload to s3'))
+ )
+ )
+ }}
+ system: x86_64-darwin
+ runner: macos-latest-large
+ runner_for_virt: macos-latest-large
+ runner_small: macos-latest-large
+ run_tests: false
+
+ build_aarch64-darwin:
+ uses: ./.github/workflows/build.yml
+ with:
+ system: aarch64-darwin
+ runner: namespace-profile-mac-m2-12c28g
+ runner_for_virt: namespace-profile-mac-m2-12c28g
+ runner_small: macos-latest-xlarge
+
+ success:
+ runs-on: ubuntu-latest
+ needs:
+ - eval
+ - build_x86_64-linux
+ - build_aarch64-linux
+ - build_x86_64-darwin
+ - build_aarch64-darwin
+ if: ${{ always() }}
steps:
- - name: Check for DockerHub secrets
- id: secret
+ - run: "true"
+ - run: |
+ echo "A dependent in the build matrix failed:"
+ echo "$needs"
+ exit 1
env:
- _DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
- run: |
- echo "docker=${{ env._DOCKER_SECRETS != '' }}" >> $GITHUB_OUTPUT
+ needs: ${{ toJSON(needs) }}
+ if: |
+ contains(needs.*.result, 'failure') ||
+ contains(needs.*.result, 'cancelled')
- docker_push_image:
- needs: [tests, vm_tests, check_secrets]
- permissions:
- contents: read
- packages: write
- if: >-
- needs.check_secrets.outputs.docker == 'true' &&
- github.event_name == 'push' &&
- github.ref_name == 'master'
- runs-on: ubuntu-24.04
- steps:
- - uses: actions/checkout@v5
- with:
- fetch-depth: 0
- - uses: cachix/install-nix-action@v31
- with:
- install_url: https://releases.nixos.org/nix/nix-2.20.3/install
- - uses: DeterminateSystems/magic-nix-cache-action@main
- - run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
- - run: nix --experimental-features 'nix-command flakes' build .#dockerImage -L
- - run: docker load -i ./result/image.tar.gz
- - run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- - run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
- # We'll deploy the newly built image to both Docker Hub and Github Container Registry.
- #
- # Push to Docker Hub first
- - name: Login to Docker Hub
- uses: docker/login-action@v3
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
- - run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- - run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
- # Push to GitHub Container Registry as well
- - name: Login to GitHub Container Registry
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
- - name: Push image
- run: |
- IMAGE_ID=ghcr.io/${{ github.repository_owner }}/nix
- # Change all uppercase to lowercase
- IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
- docker tag nix:$NIX_VERSION $IMAGE_ID:$NIX_VERSION
- docker tag nix:$NIX_VERSION $IMAGE_ID:latest
- docker push $IMAGE_ID:$NIX_VERSION
- docker push $IMAGE_ID:latest
- # deprecated 2024-02-24
- docker tag nix:$NIX_VERSION $IMAGE_ID:master
- docker push $IMAGE_ID:master
+ - name: Create artifacts directory
+ run: mkdir -p ./artifacts
- vm_tests:
- runs-on: ubuntu-24.04
- steps:
- - uses: actions/checkout@v5
- - uses: ./.github/actions/install-nix-action
+ - name: Fetch artifacts
+ uses: actions/download-artifact@v4
with:
- dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
- extra_nix_config:
- experimental-features = nix-command flakes
- github_token: ${{ secrets.GITHUB_TOKEN }}
- - uses: DeterminateSystems/magic-nix-cache-action@main
- - run: |
- nix build -L \
- .#hydraJobs.tests.functional_user \
- .#hydraJobs.tests.githubFlakes \
- .#hydraJobs.tests.nix-docker \
- .#hydraJobs.tests.tarballFlakes \
- ;
+ path: downloaded
+ - name: Move downloaded artifacts to artifacts directory
+ run: |
+ for dir in ./downloaded/*; do
+ arch="$(basename "$dir")"
+ mv "$dir"/*.xz ./artifacts/"${arch}"
+ done
- flake_regressions:
- needs: vm_tests
- runs-on: ubuntu-24.04
- steps:
- - name: Checkout nix
- uses: actions/checkout@v5
- - name: Checkout flake-regressions
- uses: actions/checkout@v5
- with:
- repository: NixOS/flake-regressions
- path: flake-regressions
- - name: Checkout flake-regressions-data
- uses: actions/checkout@v5
- with:
- repository: NixOS/flake-regressions-data
- path: flake-regressions/tests
- - uses: ./.github/actions/install-nix-action
+ - name: Build fallback-paths.nix
+ if: ${{
+ github.event_name != 'pull_request'
+ || (
+ github.event.pull_request.head.repo.full_name == 'DeterminateSystems/nix-src'
+ && (
+ (github.event.action == 'labeled' && github.event.label.name == 'upload to s3')
+ || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'upload to s3'))
+ )
+ )
+ }}
+ run: |
+ nix build .#fallbackPathsNix --out-link fallback
+ cat fallback > ./artifacts/fallback-paths.nix
+
+ - uses: DeterminateSystems/push-artifact-ids@main
with:
- dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
- extra_nix_config:
- experimental-features = nix-command flakes
- github_token: ${{ secrets.GITHUB_TOKEN }}
- - uses: DeterminateSystems/magic-nix-cache-action@main
- - run: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh
+ s3_upload_role: ${{ secrets.AWS_S3_UPLOAD_ROLE_ARN }}
+ bucket: ${{ secrets.AWS_S3_UPLOAD_BUCKET_NAME }}
+ directory: ./artifacts
+ ids_project_name: determinate-nix
+ ids_binary_prefix: determinate-nix
+ skip_acl: true
+ allowed_branches: '["main"]'
- profile_build:
- needs: tests
- runs-on: ubuntu-24.04
- timeout-minutes: 60
- if: >-
- github.event_name == 'push' &&
- github.ref_name == 'master'
+ publish:
+ needs:
+ - success
+ if: (!github.repository.fork && (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) || startsWith(github.ref, 'refs/tags/')))
+ environment: ${{ github.event_name == 'release' && 'production' || '' }}
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ id-token: write
steps:
- - uses: actions/checkout@v5
- with:
- fetch-depth: 0
- - uses: ./.github/actions/install-nix-action
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
- extra_nix_config: |
- experimental-features = flakes nix-command ca-derivations impure-derivations
- max-jobs = 1
- - uses: DeterminateSystems/magic-nix-cache-action@main
- - run: |
- nix build -L --file ./ci/gha/profile-build buildTimeReport --out-link build-time-report.md
- cat build-time-report.md >> $GITHUB_STEP_SUMMARY
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/determinate-nix-action@main
+ - uses: DeterminateSystems/flakehub-push@main
+ with:
+ rolling: ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
+ visibility: "public"
+ tag: "${{ github.ref_name }}"
+ - name: Update the release notes
+ if: startsWith(github.ref, 'refs/tags/')
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAG_NAME: ${{ github.ref_name }}
+ run: |
+ gh release edit "$TAG_NAME" --notes-file doc/manual/source/release-notes-determinate/"$TAG_NAME".md || true
diff --git a/.github/workflows/propose-release.yml b/.github/workflows/propose-release.yml
new file mode 100644
index 00000000000..ea01e4b7afe
--- /dev/null
+++ b/.github/workflows/propose-release.yml
@@ -0,0 +1,32 @@
+on:
+ workflow_dispatch:
+ inputs:
+ reference-id:
+ type: string
+ required: true
+ version:
+ type: string
+ required: true
+
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: true
+
+jobs:
+ propose-release:
+ uses: DeterminateSystems/propose-release/.github/workflows/workflow.yml@main
+ permissions:
+ id-token: write
+ contents: write
+ pull-requests: write
+ with:
+ update-flake: false
+ reference-id: ${{ inputs.reference-id }}
+ version: ${{ inputs.version }}
+ extra-commands-early: |
+ echo ${{ inputs.version }} > .version-determinate
+ git add .version-determinate
+ git commit -m "Set .version-determinate to ${{ inputs.version }}" || true
+ ./.github/release-notes.sh
+ git add doc
+ git commit -m "Generate release notes for ${{ inputs.version }}" || true
diff --git a/.version-determinate b/.version-determinate
new file mode 100644
index 00000000000..1e334568318
--- /dev/null
+++ b/.version-determinate
@@ -0,0 +1 @@
+3.11.2
diff --git a/README.md b/README.md
index 02498944cdb..4e304b28bf8 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,92 @@
-# Nix
+
+
+
+
+
+
+
+
+
+
-[](https://opencollective.com/nixos)
-[](https://github.com/NixOS/nix/actions/workflows/ci.yml)
+# Determinate Nix
-Nix is a powerful package manager for Linux and other Unix systems that makes package
-management reliable and reproducible. Please refer to the [Nix manual](https://nix.dev/reference/nix-manual)
-for more details.
+[](https://github.com/DeterminateSystems/nix-src/actions/workflows/ci.yml)
-## Installation and first steps
+This repository houses the source for [**Determinate Nix**][det-nix], a downstream distribution of [Nix][upstream] created and maintained by [Determinate Systems][detsys].
+Nix is a powerful [language], [package manager][package-management], and [CLI] for [macOS](#macos), [Linux](linux), and other Unix systems that enables you to create fully reproducible [development environments][envs], to build [packages] in sandboxed environments, to build entire Linux systems using [NixOS], and much more.
-Visit [nix.dev](https://nix.dev) for [installation instructions](https://nix.dev/tutorials/install-nix) and [beginner tutorials](https://nix.dev/tutorials/first-steps).
+Determinate Nix is part of the [Determinate platform][determinate], which also includes [FlakeHub], a secure flake repository with features like [FlakeHub Cache][cache], [private flakes][private-flakes], and [semantic versioning][semver] (SemVer) for [flakes].
-Full reference documentation can be found in the [Nix manual](https://nix.dev/reference/nix-manual).
+## Installing Determinate
-## Building and developing
+You can install Determinate on [macOS](#macos), non-NixOS [Linux](#linux) and WSL, and [NixOS](#nixos).
-Follow instructions in the Nix reference manual to [set up a development environment and build Nix from source](https://nix.dev/manual/nix/development/development/building.html).
+### macOS
-## Contributing
+On macOS, we recommend using the graphical installer from Determinate Systems.
+Click [here][gui] to download and run it.
+
+### Linux
+
+On Linux, including Windows Subsystem for Linux (WSL), we recommend installing Determinate Nix using [Determinate Nix Installer][installer]:
+
+```shell
+curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate
+```
+
+### NixOS
+
+On [NixOS], we recommend following our [dedicated installation guide][nixos-install].
-Check the [contributing guide](./CONTRIBUTING.md) if you want to get involved with developing Nix.
+## Other resources
-## Additional resources
+Nix was created by [Eelco Dolstra][eelco] and developed as the subject of his 2006 PhD thesis, [The Purely Functional Software Deployment Model][thesis].
+Today, a worldwide developer community contributes to Nix and the ecosystem that has grown around it.
-Nix was created by Eelco Dolstra and developed as the subject of his PhD thesis [The Purely Functional Software Deployment Model](https://edolstra.github.io/pubs/phd-thesis.pdf), published 2006.
-Today, a world-wide developer community contributes to Nix and the ecosystem that has grown around it.
+- [Zero to Nix][z2n], Determinate Systems' guide to Nix and [flakes] for beginners
+- [Nixpkgs], a collection of well over 100,000 software packages that you can build and manage using Nix
+- [NixOS] is a Linux distribution that can be configured fully declaratively
+- The Nix, Nixpkgs, and NixOS community on [nixos.org][website]
-- [The Nix, Nixpkgs, NixOS Community on nixos.org](https://nixos.org/)
-- [Official documentation on nix.dev](https://nix.dev)
-- [Nixpkgs](https://github.com/NixOS/nixpkgs) is [the largest, most up-to-date free software repository in the world](https://repology.org/repositories/graphs)
-- [NixOS](https://github.com/NixOS/nixpkgs/tree/master/nixos) is a Linux distribution that can be configured fully declaratively
-- [Discourse](https://discourse.nixos.org/)
-- Matrix: [#users:nixos.org](https://matrix.to/#/#users:nixos.org) for user support and [#nix-dev:nixos.org](https://matrix.to/#/#nix-dev:nixos.org) for development
+## Reference
+
+The primary documentation for Determinate and Determinate Nix is available at [docs.determinate.systems][determinate].
+For deeply technical reference material, see the [Determinate Nix manual][manual] which is based on the upstream Nix manual.
## License
-Nix is released under the [LGPL v2.1](./COPYING).
+[Upstream Nix][upstream] is released under the [LGPL v2.1][license] license.
+[Determinate Nix][det-nix] is also released under LGPL v2.1 in accordance with the terms of the upstream license.
+
+## Contributing
+
+Check the [contributing guide][contributing] if you want to get involved with developing Nix.
+
+[cache]: https://docs.determinate.systems/flakehub/cache
+[cli]: https://manual.determinate.systems/command-ref/new-cli/nix.html
+[contributing]: ./CONTRIBUTING.md
+[det-nix]: https://docs.determinate.systems/determinate-nix
+[determinate]: https://docs.determinate.systems
+[detsys]: https://determinate.systems
+[dnixd]: https://docs.determinate.systems/determinate-nix#determinate-nixd
+[eelco]: https://determinate.systems/people/eelco-dolstra
+[envs]: https://zero-to-nix.com/concepts/dev-env
+[flakehub]: https://flakehub.com
+[flakes]: https://zero-to-nix.com/concepts/flakes
+[gui]: https://install.determinate.systems/determinate-pkg/stable/Universal
+[installer]: https://github.com/DeterminateSystems/nix-installer
+[language]: https://zero-to-nix.com/concepts/nix-language
+[license]: ./COPYING
+[manual]: https://manual.determinate.systems
+[nixpkgs]: https://github.com/NixOS/nixpkgs
+[nixos]: https://github.com/NixOS/nixpkgs/tree/master/nixos
+[nixos-install]: https://docs.determinate.systems/guides/advanced-installation#nixos
+[packages]: https://zero-to-nix.com/concepts/packages
+[package-management]: https://zero-to-nix.com/concepts/package-management
+[private-flakes]: https://docs.determinate.systems/flakehub/private-flakes
+[semver]: https://docs.determinate.systems/flakehub/concepts/semver
+[thesis]: https://edolstra.github.io/pubs/phd-thesis.pdf
+[upstream]: https://github.com/NixOS/nix
+[website]: https://nixos.org
+[z2n]: https://zero-to-nix.com
diff --git a/ci/gha/tests/default.nix b/ci/gha/tests/default.nix
index 74d0b8c7ec2..8bf9f042922 100644
--- a/ci/gha/tests/default.nix
+++ b/ci/gha/tests/default.nix
@@ -82,7 +82,6 @@ rec {
*/
topLevel = {
installerScriptForGHA = hydraJobs.installerScriptForGHA.${system};
- installTests = hydraJobs.installTests.${system};
nixpkgsLibTests = hydraJobs.tests.nixpkgsLibTests.${system};
rl-next = pkgs.buildPackages.runCommand "test-rl-next-release-notes" { } ''
LANG=C.UTF-8 ${pkgs.changelog-d}/bin/changelog-d ${../../../doc/manual/rl-next} >$out
diff --git a/default.nix b/default.nix
deleted file mode 100644
index 6466507b714..00000000000
--- a/default.nix
+++ /dev/null
@@ -1,9 +0,0 @@
-(import (
- let
- lock = builtins.fromJSON (builtins.readFile ./flake.lock);
- in
- fetchTarball {
- url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
- sha256 = lock.nodes.flake-compat.locked.narHash;
- }
-) { src = ./.; }).defaultNix
diff --git a/doc/manual/book.toml.in b/doc/manual/book.toml.in
index 34acf642edb..f3fd2722f3c 100644
--- a/doc/manual/book.toml.in
+++ b/doc/manual/book.toml.in
@@ -1,12 +1,12 @@
[book]
-title = "Nix @version@ Reference Manual"
+title = "Determinate Nix @version@ Reference Manual"
src = "source"
[output.html]
additional-css = ["custom.css"]
additional-js = ["redirects.js"]
-edit-url-template = "https://github.com/NixOS/nix/tree/master/doc/manual/{path}"
-git-repository-url = "https://github.com/NixOS/nix"
+edit-url-template = "https://github.com/DeterminateSystems/nix-src/tree/master/doc/manual/{path}"
+git-repository-url = "https://github.com/DeterminateSystems/nix-src"
# Handles replacing @docroot@ with a path to ./source relative to that markdown file,
# {{#include handlebars}}, and the @generated@ syntax used within these. it mostly
diff --git a/doc/manual/custom.css b/doc/manual/custom.css
index 7af150be391..119c6d12543 100644
--- a/doc/manual/custom.css
+++ b/doc/manual/custom.css
@@ -1,5 +1,5 @@
:root {
- --sidebar-width: 23em;
+ --sidebar-width: 23em;
}
h1.menu-title::before {
@@ -7,11 +7,10 @@ h1.menu-title::before {
background-image: url("./favicon.svg");
padding: 1.25em;
background-position: center center;
- background-size: 2em;
+ background-size: 1.5em;
background-repeat: no-repeat;
}
-
.menu-bar {
padding: 0.5em 0em;
}
@@ -21,13 +20,13 @@ h1.menu-title::before {
}
h1:not(:first-of-type) {
- margin-top: 1.3em;
+ margin-top: 1.3em;
}
h2 {
- margin-top: 1em;
+ margin-top: 1em;
}
.hljs-meta {
- user-select: none;
+ user-select: none;
}
diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix
index 31e74e17d26..292cb283d3d 100644
--- a/doc/manual/generate-manpage.nix
+++ b/doc/manual/generate-manpage.nix
@@ -42,11 +42,6 @@ let
let
result = ''
- > **Warning** \
- > This program is
- > [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
- > and its interface is subject to change.
-
# Name
`${command}` - ${details.description}
diff --git a/doc/manual/meson.build b/doc/manual/meson.build
index 2e372deddee..05d4c377f1b 100644
--- a/doc/manual/meson.build
+++ b/doc/manual/meson.build
@@ -5,6 +5,8 @@ project(
license : 'LGPL-2.1-or-later',
)
+fs = import('fs')
+
nix = find_program('nix', native : true)
mdbook = find_program('mdbook', native : true)
@@ -22,7 +24,7 @@ nix_env_for_docs = {
'NIX_CONFIG' : 'cores = 0',
}
-nix_for_docs = [ nix, '--experimental-features', 'nix-command' ]
+nix_for_docs = [ nix ]
nix_eval_for_docs_common = nix_for_docs + [
'eval',
'-I',
@@ -97,7 +99,7 @@ manual = custom_target(
python.full_path(),
mdbook.full_path(),
meson.current_build_dir(),
- meson.project_version(),
+ fs.read('../../.version-determinate').strip(),
rsync.full_path(),
),
],
diff --git a/doc/manual/package.nix b/doc/manual/package.nix
index 69b7c0e49b0..a74ee3f57b2 100644
--- a/doc/manual/package.nix
+++ b/doc/manual/package.nix
@@ -24,7 +24,7 @@ let
in
mkMesonDerivation (finalAttrs: {
- pname = "nix-manual";
+ pname = "determinate-nix-manual";
inherit version;
workDir = ./.;
@@ -32,6 +32,7 @@ mkMesonDerivation (finalAttrs: {
fileset.difference
(fileset.unions [
../../.version
+ ../../.version-determinate
# Too many different types of files to filter for now
../../doc/manual
./.
diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js
index 9612438481f..b2295cf4fc5 100644
--- a/doc/manual/redirects.js
+++ b/doc/manual/redirects.js
@@ -271,14 +271,10 @@ const redirects = {
"sect-multi-user-installation": "installation/installing-binary.html#multi-user-installation",
"sect-nix-install-binary-tarball": "installation/installing-binary.html#installing-from-a-binary-tarball",
"sect-nix-install-pinned-version-url": "installation/installing-binary.html#installing-a-pinned-nix-version-from-a-url",
- "sect-single-user-installation": "installation/installing-binary.html#single-user-installation",
"ch-installing-source": "installation/installing-source.html",
"ssec-multi-user": "installation/multi-user.html",
- "ch-nix-security": "installation/nix-security.html",
"sec-obtaining-source": "installation/obtaining-source.html",
"sec-prerequisites-source": "installation/prerequisites-source.html",
- "sec-single-user": "installation/single-user.html",
- "ch-supported-platforms": "installation/supported-platforms.html",
"ch-upgrading-nix": "installation/upgrading.html",
"ch-about-nix": "introduction.html",
"chap-introduction": "introduction.html",
diff --git a/doc/manual/rl-next/shorter-build-dir-names.md b/doc/manual/rl-next/shorter-build-dir-names.md
new file mode 100644
index 00000000000..e87fa5d04fb
--- /dev/null
+++ b/doc/manual/rl-next/shorter-build-dir-names.md
@@ -0,0 +1,6 @@
+---
+synopsis: "Temporary build directories no longer include derivation names"
+prs: [13839]
+---
+
+Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`.
\ No newline at end of file
diff --git a/doc/manual/source/SUMMARY.md.in b/doc/manual/source/SUMMARY.md.in
index 8fed98c2c1b..45921f40b81 100644
--- a/doc/manual/source/SUMMARY.md.in
+++ b/doc/manual/source/SUMMARY.md.in
@@ -3,17 +3,12 @@
- [Introduction](introduction.md)
- [Quick Start](quick-start.md)
- [Installation](installation/index.md)
- - [Supported Platforms](installation/supported-platforms.md)
- - [Installing a Binary Distribution](installation/installing-binary.md)
- [Installing Nix from Source](installation/installing-source.md)
- [Prerequisites](installation/prerequisites-source.md)
- [Obtaining a Source Distribution](installation/obtaining-source.md)
- [Building Nix from Source](installation/building-source.md)
- [Using Nix within Docker](installation/installing-docker.md)
- [Security](installation/nix-security.md)
- - [Single-User Mode](installation/single-user.md)
- - [Multi-User Mode](installation/multi-user.md)
- - [Environment Variables](installation/env-variables.md)
- [Upgrading Nix](installation/upgrading.md)
- [Uninstalling Nix](installation/uninstall.md)
- [Nix Store](store/index.md)
@@ -61,8 +56,11 @@
- [Command Reference](command-ref/index.md)
- [Common Options](command-ref/opt-common.md)
- [Common Environment Variables](command-ref/env-common.md)
- - [Main Commands](command-ref/main-commands.md)
+ - [Subcommands](command-ref/subcommands.md)
+{{#include ./command-ref/new-cli/SUMMARY.md}}
+ - [Deprecated Commands](command-ref/main-commands.md)
- [nix-build](command-ref/nix-build.md)
+ - [nix-channel](command-ref/nix-channel.md)
- [nix-shell](command-ref/nix-shell.md)
- [nix-store](command-ref/nix-store.md)
- [nix-store --add-fixed](command-ref/nix-store/add-fixed.md)
@@ -98,22 +96,17 @@
- [nix-env --uninstall](command-ref/nix-env/uninstall.md)
- [nix-env --upgrade](command-ref/nix-env/upgrade.md)
- [Utilities](command-ref/utilities.md)
- - [nix-channel](command-ref/nix-channel.md)
- [nix-collect-garbage](command-ref/nix-collect-garbage.md)
- [nix-copy-closure](command-ref/nix-copy-closure.md)
- [nix-daemon](command-ref/nix-daemon.md)
- [nix-hash](command-ref/nix-hash.md)
- [nix-instantiate](command-ref/nix-instantiate.md)
- [nix-prefetch-url](command-ref/nix-prefetch-url.md)
- - [Experimental Commands](command-ref/experimental-commands.md)
-{{#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 and Design](architecture/architecture.md)
- [Formats and Protocols](protocols/index.md)
- [JSON Formats](protocols/json/index.md)
@@ -136,7 +129,39 @@
- [C++ style guide](development/cxx.md)
- [Experimental Features](development/experimental-features.md)
- [Contributing](development/contributing.md)
-- [Releases](release-notes/index.md)
+- [Determinate Nix Release Notes](release-notes-determinate/index.md)
+ - [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md)
+ - [Release 3.11.2 (2025-09-12)](release-notes-determinate/v3.11.2.md)
+ - [Release 3.11.1 (2025-09-04)](release-notes-determinate/v3.11.1.md)
+ - [Release 3.11.0 (2025-09-03)](release-notes-determinate/v3.11.0.md)
+ - [Release 3.10.1 (2025-09-02)](release-notes-determinate/v3.10.1.md)
+ - [Release 3.10.0 (2025-09-02)](release-notes-determinate/v3.10.0.md)
+ - [Release 3.9.1 (2025-08-28)](release-notes-determinate/v3.9.1.md)
+ - [Release 3.9.0 (2025-08-26)](release-notes-determinate/v3.9.0.md)
+ - [Release 3.8.6 (2025-08-19)](release-notes-determinate/v3.8.6.md)
+ - [Release 3.8.5 (2025-08-04)](release-notes-determinate/rl-3.8.5.md)
+ - [Release 3.8.4 (2025-07-21)](release-notes-determinate/rl-3.8.4.md)
+ - [Release 3.8.3 (2025-07-18)](release-notes-determinate/rl-3.8.3.md)
+ - [Release 3.8.2 (2025-07-12)](release-notes-determinate/rl-3.8.2.md)
+ - [Release 3.8.1 (2025-07-11)](release-notes-determinate/rl-3.8.1.md)
+ - [Release 3.8.0 (2025-07-10)](release-notes-determinate/rl-3.8.0.md)
+ - [Release 3.7.0 (2025-07-03)](release-notes-determinate/rl-3.7.0.md)
+ - [Release 3.6.8 (2025-06-25)](release-notes-determinate/rl-3.6.8.md)
+ - [Release 3.6.7 (2025-06-24)](release-notes-determinate/rl-3.6.7.md)
+ - [Release 3.6.6 (2025-06-17)](release-notes-determinate/rl-3.6.6.md)
+ - [Release 3.6.5 (2025-06-16)](release-notes-determinate/rl-3.6.5.md)
+ - [Release 3.6.2 (2025-06-02)](release-notes-determinate/rl-3.6.2.md)
+ - [Release 3.6.1 (2025-05-24)](release-notes-determinate/rl-3.6.1.md)
+ - [Release 3.6.0 (2025-05-22)](release-notes-determinate/rl-3.6.0.md)
+ - [Release 3.5.2 (2025-05-12)](release-notes-determinate/rl-3.5.2.md)
+ - [Release 3.5.1 (2025-05-09)](release-notes-determinate/rl-3.5.1.md)
+ - [~~Release 3.5.0 (2025-05-09)~~](release-notes-determinate/rl-3.5.0.md)
+ - [Release 3.4.2 (2025-05-05)](release-notes-determinate/rl-3.4.2.md)
+ - [Release 3.4.0 (2025-04-25)](release-notes-determinate/rl-3.4.0.md)
+ - [Release 3.3.0 (2025-04-11)](release-notes-determinate/rl-3.3.0.md)
+ - [Release 3.1.0 (2025-03-27)](release-notes-determinate/rl-3.1.0.md)
+ - [Release 3.0.0 (2025-03-04)](release-notes-determinate/rl-3.0.0.md)
+- [Nix Release Notes](release-notes/index.md)
{{#include ./SUMMARY-rl-next.md}}
- [Release 2.31 (2025-08-21)](release-notes/rl-2.31.md)
- [Release 2.30 (2025-07-07)](release-notes/rl-2.30.md)
@@ -144,60 +169,3 @@
- [Release 2.28 (2025-04-02)](release-notes/rl-2.28.md)
- [Release 2.27 (2025-03-03)](release-notes/rl-2.27.md)
- [Release 2.26 (2025-01-22)](release-notes/rl-2.26.md)
- - [Release 2.25 (2024-11-07)](release-notes/rl-2.25.md)
- - [Release 2.24 (2024-07-31)](release-notes/rl-2.24.md)
- - [Release 2.23 (2024-06-03)](release-notes/rl-2.23.md)
- - [Release 2.22 (2024-04-23)](release-notes/rl-2.22.md)
- - [Release 2.21 (2024-03-11)](release-notes/rl-2.21.md)
- - [Release 2.20 (2024-01-29)](release-notes/rl-2.20.md)
- - [Release 2.19 (2023-11-17)](release-notes/rl-2.19.md)
- - [Release 2.18 (2023-09-20)](release-notes/rl-2.18.md)
- - [Release 2.17 (2023-07-24)](release-notes/rl-2.17.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)
- - [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)
- - [Release 2.8 (2022-04-19)](release-notes/rl-2.8.md)
- - [Release 2.7 (2022-03-07)](release-notes/rl-2.7.md)
- - [Release 2.6 (2022-01-24)](release-notes/rl-2.6.md)
- - [Release 2.5 (2021-12-13)](release-notes/rl-2.5.md)
- - [Release 2.4 (2021-11-01)](release-notes/rl-2.4.md)
- - [Release 2.3 (2019-09-04)](release-notes/rl-2.3.md)
- - [Release 2.2 (2019-01-11)](release-notes/rl-2.2.md)
- - [Release 2.1 (2018-09-02)](release-notes/rl-2.1.md)
- - [Release 2.0 (2018-02-22)](release-notes/rl-2.0.md)
- - [Release 1.11.10 (2017-06-12)](release-notes/rl-1.11.10.md)
- - [Release 1.11 (2016-01-19)](release-notes/rl-1.11.md)
- - [Release 1.10 (2015-09-03)](release-notes/rl-1.10.md)
- - [Release 1.9 (2015-06-12)](release-notes/rl-1.9.md)
- - [Release 1.8 (2014-12-14)](release-notes/rl-1.8.md)
- - [Release 1.7 (2014-04-11)](release-notes/rl-1.7.md)
- - [Release 1.6.1 (2013-10-28)](release-notes/rl-1.6.1.md)
- - [Release 1.6 (2013-09-10)](release-notes/rl-1.6.md)
- - [Release 1.5.2 (2013-05-13)](release-notes/rl-1.5.2.md)
- - [Release 1.5 (2013-02-27)](release-notes/rl-1.5.md)
- - [Release 1.4 (2013-02-26)](release-notes/rl-1.4.md)
- - [Release 1.3 (2013-01-04)](release-notes/rl-1.3.md)
- - [Release 1.2 (2012-12-06)](release-notes/rl-1.2.md)
- - [Release 1.1 (2012-07-18)](release-notes/rl-1.1.md)
- - [Release 1.0 (2012-05-11)](release-notes/rl-1.0.md)
- - [Release 0.16 (2010-08-17)](release-notes/rl-0.16.md)
- - [Release 0.15 (2010-03-17)](release-notes/rl-0.15.md)
- - [Release 0.14 (2010-02-04)](release-notes/rl-0.14.md)
- - [Release 0.13 (2009-11-05)](release-notes/rl-0.13.md)
- - [Release 0.12 (2008-11-20)](release-notes/rl-0.12.md)
- - [Release 0.11 (2007-12-31)](release-notes/rl-0.11.md)
- - [Release 0.10.1 (2006-10-11)](release-notes/rl-0.10.1.md)
- - [Release 0.10 (2006-10-06)](release-notes/rl-0.10.md)
- - [Release 0.9.2 (2005-09-21)](release-notes/rl-0.9.2.md)
- - [Release 0.9.1 (2005-09-20)](release-notes/rl-0.9.1.md)
- - [Release 0.9 (2005-09-16)](release-notes/rl-0.9.md)
- - [Release 0.8.1 (2005-04-13)](release-notes/rl-0.8.1.md)
- - [Release 0.8 (2005-04-11)](release-notes/rl-0.8.md)
- - [Release 0.7 (2005-01-12)](release-notes/rl-0.7.md)
- - [Release 0.6 (2004-11-14)](release-notes/rl-0.6.md)
- - [Release 0.5 and earlier](release-notes/rl-0.5.md)
diff --git a/doc/manual/source/command-ref/env-common.md b/doc/manual/source/command-ref/env-common.md
index e0fd2b00eec..fe6e822ff16 100644
--- a/doc/manual/source/command-ref/env-common.md
+++ b/doc/manual/source/command-ref/env-common.md
@@ -102,7 +102,7 @@ Most Nix commands interpret the following environment variables:
This variable should be set to `daemon` if you want to use the Nix
daemon to execute Nix operations. This is necessary in [multi-user
- Nix installations](@docroot@/installation/multi-user.md). If the Nix
+ Nix installations](@docroot@/installation/nix-security.md#multi-user-model). If the Nix
daemon's Unix socket is at some non-standard path, this variable
should be set to `unix://path/to/socket`. Otherwise, it should be
left unset.
diff --git a/doc/manual/source/command-ref/experimental-commands.md b/doc/manual/source/command-ref/experimental-commands.md
deleted file mode 100644
index 1190729a230..00000000000
--- a/doc/manual/source/command-ref/experimental-commands.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# Experimental Commands
-
-This section lists [experimental commands](@docroot@/development/experimental-features.md#xp-feature-nix-command).
-
-> **Warning**
->
-> These commands may be removed in the future, or their syntax may
-> change in incompatible ways.
diff --git a/doc/manual/source/command-ref/files/default-nix-expression.md b/doc/manual/source/command-ref/files/default-nix-expression.md
index 2bd45ff5deb..e886e3ff499 100644
--- a/doc/manual/source/command-ref/files/default-nix-expression.md
+++ b/doc/manual/source/command-ref/files/default-nix-expression.md
@@ -31,12 +31,12 @@ Then, the resulting expression is interpreted like this:
The file [`manifest.nix`](@docroot@/command-ref/files/manifest.nix.md) is always ignored.
-The command [`nix-channel`] places a symlink to the current user's [channels] in this directory, the [user channel link](#user-channel-link).
+The command [`nix-channel`] places a symlink to the current user's channels in this directory, the [user channel link](#user-channel-link).
This makes all subscribed channels available as attributes in the default expression.
## User channel link
-A symlink that ensures that [`nix-env`] can find the current user's [channels]:
+A symlink that ensures that [`nix-env`] can find the current user's channels:
- `~/.nix-defexpr/channels`
- `$XDG_STATE_HOME/defexpr/channels` if [`use-xdg-base-directories`] is set to `true`.
@@ -51,4 +51,3 @@ In a multi-user installation, you may also have `~/.nix-defexpr/channels_root`,
[`nix-channel`]: @docroot@/command-ref/nix-channel.md
[`nix-env`]: @docroot@/command-ref/nix-env.md
[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
-[channels]: @docroot@/command-ref/files/channels.md
diff --git a/doc/manual/source/command-ref/files/profiles.md b/doc/manual/source/command-ref/files/profiles.md
index b5c7378800f..e46e2418b4c 100644
--- a/doc/manual/source/command-ref/files/profiles.md
+++ b/doc/manual/source/command-ref/files/profiles.md
@@ -67,7 +67,7 @@ By default, this symlink points to:
- `$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`].
+The installer 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
diff --git a/doc/manual/source/command-ref/nix-channel.md b/doc/manual/source/command-ref/nix-channel.md
index ed9cbb41fbf..a65ec97c558 100644
--- a/doc/manual/source/command-ref/nix-channel.md
+++ b/doc/manual/source/command-ref/nix-channel.md
@@ -8,6 +8,12 @@
# Description
+> **Warning**
+>
+> nix-channel is deprecated in favor of flakes in Determinate Nix.
+> For a guide on Nix flakes, see: .
+> For details and to offer feedback on the deprecation process, see: .
+
Channels are a mechanism for referencing remote Nix expressions and conveniently retrieving their latest version.
The moving parts of channels are:
diff --git a/doc/manual/source/command-ref/nix-env.md b/doc/manual/source/command-ref/nix-env.md
index bda02149ed0..d01caaf7f78 100644
--- a/doc/manual/source/command-ref/nix-env.md
+++ b/doc/manual/source/command-ref/nix-env.md
@@ -52,7 +52,7 @@ These pages can be viewed offline:
`nix-env` can obtain packages from multiple sources:
- An attribute set of derivations from:
- - The [default Nix expression](@docroot@/command-ref/files/default-nix-expression.md) (by default)
+ - The default Nix expression (by default)
- A Nix file, specified via `--file`
- A [profile](@docroot@/command-ref/files/profiles.md), specified via `--from-profile`
- A Nix expression that is a function which takes default expression as argument, specified via `--from-expression`
diff --git a/doc/manual/source/command-ref/nix-env/install.md b/doc/manual/source/command-ref/nix-env/install.md
index 527fd8f90d8..26a32aa6b6b 100644
--- a/doc/manual/source/command-ref/nix-env/install.md
+++ b/doc/manual/source/command-ref/nix-env/install.md
@@ -22,12 +22,11 @@ It is based on the current generation of the active [profile](@docroot@/command-
The arguments *args* map to store paths in a number of possible ways:
-- By default, *args* is a set of names denoting derivations in the [default Nix expression].
+- By default, *args* is a set of names denoting derivations in the default Nix expression.
These are [realised], and the resulting output paths are installed.
Currently installed derivations with a name equal to the name of a derivation being added are removed unless the option `--preserve-installed` is specified.
[derivation expression]: @docroot@/glossary.md#gloss-derivation-expression
- [default Nix expression]: @docroot@/command-ref/files/default-nix-expression.md
[realised]: @docroot@/glossary.md#gloss-realise
If there are multiple derivations matching a name in *args* that
@@ -45,7 +44,7 @@ The arguments *args* map to store paths in a number of possible ways:
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
probably cause a user environment conflict\!).
-- If [`--attr`](#opt-attr) / `-A` is specified, the arguments are *attribute paths* that select attributes from the [default Nix expression].
+- If [`--attr`](#opt-attr) / `-A` is specified, the arguments are *attribute paths* that select attributes from the default Nix expression.
This is faster than using derivation names and unambiguous.
Show the attribute paths of available packages with [`nix-env --query`](./query.md):
@@ -58,7 +57,7 @@ The arguments *args* map to store paths in a number of possible ways:
easy way to copy user environment elements from one profile to
another.
-- If `--from-expression` is given, *args* are [Nix language functions](@docroot@/language/syntax.md#functions) that are called with the [default Nix expression] as their single argument.
+- If `--from-expression` is given, *args* are [Nix language functions](@docroot@/language/syntax.md#functions) that are called with the default Nix expression as their single argument.
The derivations returned by those function calls are installed.
This allows derivations to be specified in an unambiguous way, which is necessary if there are multiple derivations with the same name.
diff --git a/doc/manual/source/command-ref/nix-store/query.md b/doc/manual/source/command-ref/nix-store/query.md
index b5ba63adae2..94eee05b8a8 100644
--- a/doc/manual/source/command-ref/nix-store/query.md
+++ b/doc/manual/source/command-ref/nix-store/query.md
@@ -103,6 +103,13 @@ symlink.
example when *paths* were substituted from a binary cache.
Use `--valid-derivers` instead to obtain valid paths only.
+ > **Note**
+ >
+ > `nix-store --query --deriver` is replaced with the following `nix` command:
+ >
+ > nix path-info --json ... | jq -r '.[].deriver'
+
+
[deriver]: @docroot@/glossary.md#gloss-deriver
- `--valid-derivers`
diff --git a/doc/manual/source/command-ref/subcommands.md b/doc/manual/source/command-ref/subcommands.md
new file mode 100644
index 00000000000..6a26732338d
--- /dev/null
+++ b/doc/manual/source/command-ref/subcommands.md
@@ -0,0 +1,3 @@
+# Subcommands
+
+This section lists all the subcommands of the `nix` CLI.
diff --git a/doc/manual/source/development/building.md b/doc/manual/source/development/building.md
index 33b7b2d5c56..111d46d7232 100644
--- a/doc/manual/source/development/building.md
+++ b/doc/manual/source/development/building.md
@@ -1,73 +1,5 @@
# Building Nix
-This section provides some notes on how to start hacking on Nix.
-To get the latest version of Nix from GitHub:
-
-```console
-$ git clone https://github.com/NixOS/nix.git
-$ cd nix
-```
-
-> **Note**
->
-> The following instructions assume you already have some version of Nix installed locally, so that you can use it to set up the development environment.
-> If you don't have it installed, follow the [installation instructions](../installation/index.md).
-
-
-To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:
-
-```console
-$ nix-shell
-```
-
-To get a shell with one of the other [supported compilation environments](#compilation-environments):
-
-```console
-$ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages
-```
-
-> **Note**
->
-> You can use `native-ccacheStdenv` to drastically improve rebuild time.
-> By default, [ccache](https://ccache.dev) keeps artifacts in `~/.cache/ccache/`.
-
-To build Nix itself in this shell:
-
-```console
-[nix-shell]$ mesonFlags+=" --prefix=$(pwd)/outputs/out"
-[nix-shell]$ dontAddPrefix=1 configurePhase
-[nix-shell]$ buildPhase
-```
-
-To test it:
-
-```console
-[nix-shell]$ checkPhase
-```
-
-To install it in `$(pwd)/outputs`:
-
-```console
-[nix-shell]$ installPhase
-[nix-shell]$ ./outputs/out/bin/nix --version
-nix (Nix) 2.12
-```
-
-To build a release version of Nix for the current operating system and CPU architecture:
-
-```console
-$ nix-build
-```
-
-You can also build Nix for one of the [supported platforms](#platforms).
-
-## Building Nix with flakes
-
-This section assumes you are using Nix with the [`flakes`] and [`nix-command`] experimental features enabled.
-
-[`flakes`]: @docroot@/development/experimental-features.md#xp-feature-flakes
-[`nix-command`]: @docroot@/development/experimental-features.md#xp-nix-command
-
To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:
```console
@@ -145,12 +77,6 @@ platform. Common solutions include [remote build machines] and [binary format em
Given such a setup, executing the build only requires selecting the respective attribute.
For example, to compile for `aarch64-linux`:
-```console
-$ nix-build --attr packages.aarch64-linux.default
-```
-
-or for Nix with the [`flakes`] and [`nix-command`] experimental features enabled:
-
```console
$ nix build .#packages.aarch64-linux.default
```
@@ -243,20 +169,12 @@ To build with one of those environments, you can use
$ nix build .#nix-cli-ccacheStdenv
```
-for flake-enabled Nix, or
-
-```console
-$ nix-build --attr nix-cli-ccacheStdenv
-```
-
-for classic Nix.
-
You can use any of the other supported environments in place of `nix-cli-ccacheStdenv`.
## Editor integration
The `clangd` LSP server is installed by default on the `clang`-based `devShell`s.
-See [supported compilation environments](#compilation-environments) and instructions how to set up a shell [with flakes](#nix-with-flakes) or in [classic Nix](#classic-nix).
+See [supported compilation environments](#compilation-environments) and instructions how to [set up a shell with flakes](#nix-with-flakes).
To use the LSP with your editor, you will want a `compile_commands.json` file telling `clangd` how we are compiling the code.
Meson's configure always produces this inside the build directory.
diff --git a/doc/manual/source/development/experimental-features.md b/doc/manual/source/development/experimental-features.md
index ad5cffa91ee..56a45b23890 100644
--- a/doc/manual/source/development/experimental-features.md
+++ b/doc/manual/source/development/experimental-features.md
@@ -6,7 +6,7 @@ Experimental features are considered unstable, which means that they can be chan
Users must explicitly enable them by toggling the associated [experimental feature flags](@docroot@/command-ref/conf-file.md#conf-experimental-features).
This allows accessing unstable functionality without unwittingly relying on it.
-Experimental feature flags were first introduced in [Nix 2.4](@docroot@/release-notes/rl-2.4.md).
+Experimental feature flags were first introduced in [Nix 2.4](https://nix.dev/manual/nix/latest/release-notes/rl-2.4).
Before that, Nix did have experimental features, but they were not guarded by flags and were merely documented as unstable.
This was a source of confusion and controversy.
diff --git a/doc/manual/source/favicon.png b/doc/manual/source/favicon.png
deleted file mode 100644
index 1ed2b5fe0fd..00000000000
Binary files a/doc/manual/source/favicon.png and /dev/null differ
diff --git a/doc/manual/source/favicon.svg b/doc/manual/source/favicon.svg
index 1d2a6e835d5..55fb9479b06 100644
--- a/doc/manual/source/favicon.svg
+++ b/doc/manual/source/favicon.svg
@@ -1 +1,29 @@
-
\ No newline at end of file
+
diff --git a/doc/manual/source/glossary.md b/doc/manual/source/glossary.md
index e6a294e7de7..9e76ad37b96 100644
--- a/doc/manual/source/glossary.md
+++ b/doc/manual/source/glossary.md
@@ -353,14 +353,6 @@
See [Nix Archive](store/file-system-object/content-address.html#serial-nix-archive) for details.
-- [`∅`]{#gloss-empty-set}
-
- The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile.
-
-- [`ε`]{#gloss-epsilon}
-
- The epsilon symbol. In the context of a package, this means the version is empty. More precisely, the derivation does not have a version attribute.
-
- [package]{#package}
A software package; files that belong together for a particular purpose, and metadata.
diff --git a/doc/manual/source/installation/env-variables.md b/doc/manual/source/installation/env-variables.md
deleted file mode 100644
index 0350904211a..00000000000
--- a/doc/manual/source/installation/env-variables.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Environment Variables
-
-To use Nix, some environment variables should be set. In particular,
-`PATH` should contain the directories `prefix/bin` and
-`~/.nix-profile/bin`. The first directory contains the Nix tools
-themselves, while `~/.nix-profile` is a symbolic link to the current
-*user environment* (an automatically generated package consisting of
-symlinks to installed packages). The simplest way to set the required
-environment variables is to include the file
-`prefix/etc/profile.d/nix.sh` in your `~/.profile` (or similar), like
-this:
-
-```bash
-source prefix/etc/profile.d/nix.sh
-```
-
-# `NIX_SSL_CERT_FILE`
-
-If you need to specify a custom certificate bundle to account for an
-HTTPS-intercepting man in the middle proxy, you must specify the path to
-the certificate bundle in the environment variable `NIX_SSL_CERT_FILE`.
-
-If you don't specify a `NIX_SSL_CERT_FILE` manually, Nix will install
-and use its own certificate bundle.
-
-Set the environment variable and install Nix
-
-```console
-$ export NIX_SSL_CERT_FILE=/etc/ssl/my-certificate-bundle.crt
-$ curl -L https://nixos.org/nix/install | sh
-```
-
-In the shell profile and rc files (for example, `/etc/bashrc`,
-`/etc/zshrc`), add the following line:
-
-```bash
-export NIX_SSL_CERT_FILE=/etc/ssl/my-certificate-bundle.crt
-```
-
-> **Note**
->
-> You must not add the export and then do the install, as the Nix
-> installer will detect the presence of Nix configuration, and abort.
-
-If you use the Nix daemon, you should also add the following to
-`/etc/nix/nix.conf`:
-
-```
-ssl-cert-file = /etc/ssl/my-certificate-bundle.crt
-```
-
-## Proxy Environment Variables
-
-The Nix installer has special handling for these proxy-related
-environment variables: `http_proxy`, `https_proxy`, `ftp_proxy`,
-`all_proxy`, `no_proxy`, `HTTP_PROXY`, `HTTPS_PROXY`, `FTP_PROXY`,
-`ALL_PROXY`, `NO_PROXY`.
-
-If any of these variables are set when running the Nix installer, then
-the installer will create an override file at
-`/etc/systemd/system/nix-daemon.service.d/override.conf` so `nix-daemon`
-will use them.
diff --git a/doc/manual/source/installation/index.md b/doc/manual/source/installation/index.md
index 3c09f103184..21aca146fd2 100644
--- a/doc/manual/source/installation/index.md
+++ b/doc/manual/source/installation/index.md
@@ -1,44 +1,11 @@
# Installation
-This section describes how to install and configure Nix for first-time use.
-
-The current recommended option on Linux and MacOS is [multi-user](#multi-user).
-
-## Multi-user
-
-This installation offers better sharing, improved isolation, and more security
-over a single user installation.
-
-This option requires either:
-
-* Linux running systemd, with SELinux disabled
-* MacOS
-
-> **Updating to macOS 15 Sequoia**
->
-> If you recently updated to macOS 15 Sequoia and are getting
-> ```console
-> error: the user '_nixbld1' in the group 'nixbld' does not exist
-> ```
-> when running Nix commands, refer to GitHub issue [NixOS/nix#10892](https://github.com/NixOS/nix/issues/10892) for instructions to fix your installation without reinstalling.
+We recommend that macOS users install Determinate Nix using our graphical installer, [Determinate.pkg][pkg].
+For Linux and Windows Subsystem for Linux (WSL) users:
```console
-$ curl -L https://nixos.org/nix/install | sh -s -- --daemon
-```
-
-## Single-user
-
-> Single-user is not supported on Mac.
-
-> `warning: installing Nix as root is not supported by this script!`
-
-This installation has less requirements than the multi-user install, however it
-cannot offer equivalent sharing, isolation, or security.
-
-This option is suitable for systems without systemd.
-
-```console
-$ curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
+curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | \
+ sh -s -- install --determinate
```
## Distributions
@@ -46,3 +13,5 @@ $ curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
The Nix community maintains installers for several distributions.
They can be found in the [`nix-community/nix-installers`](https://github.com/nix-community/nix-installers) repository.
+
+[pkg]: https://install.determinate.systems/determinate-pkg/stable/Universal
diff --git a/doc/manual/source/installation/installing-binary.md b/doc/manual/source/installation/installing-binary.md
deleted file mode 100644
index 21c15637437..00000000000
--- a/doc/manual/source/installation/installing-binary.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# Installing a Binary Distribution
-
-> **Updating to macOS 15 Sequoia**
->
-> If you recently updated to macOS 15 Sequoia and are getting
-> ```console
-> error: the user '_nixbld1' in the group 'nixbld' does not exist
-> ```
-> when running Nix commands, refer to GitHub issue [NixOS/nix#10892](https://github.com/NixOS/nix/issues/10892) for instructions to fix your installation without reinstalling.
-
-To install the latest version Nix, run the following command:
-
-```console
-$ curl -L https://nixos.org/nix/install | sh
-```
-
-This performs the default type of installation for your platform:
-
-- [Multi-user](#multi-user-installation):
- - Linux with systemd and without SELinux
- - macOS
-- [Single-user](#single-user-installation):
- - Linux without systemd
- - Linux with SELinux
-
-We recommend the multi-user installation if it supports your platform and you can authenticate with `sudo`.
-
-The installer can be configured with various command line arguments and environment variables.
-To show available command line flags:
-
-```console
-$ curl -L https://nixos.org/nix/install | sh -s -- --help
-```
-
-To check what it does and how it can be customised further, [download and edit the second-stage installation script](#installing-from-a-binary-tarball).
-
-# Installing a pinned Nix version from a URL
-
-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 directory for each version contains the corresponding SHA-256 hash.
-
-All installation scripts are invoked the same way:
-
-```console
-$ export VERSION=2.19.2
-$ curl -L https://releases.nixos.org/nix/nix-$VERSION/install | sh
-```
-
-# Multi User Installation
-
-The multi-user Nix installation creates system users and a system service for the Nix daemon.
-
-Supported systems:
-
-- Linux running systemd, with SELinux disabled
-- macOS
-
-To explicitly instruct the installer to perform a multi-user installation on your system:
-
-```console
-$ bash <(curl -L https://nixos.org/nix/install) --daemon
-```
-
-You can run this under your usual user account or `root`.
-The script will invoke `sudo` as needed.
-
-# Single User Installation
-
-To explicitly select a single-user installation on your system:
-
-```console
-$ bash <(curl -L https://nixos.org/nix/install) --no-daemon
-```
-
-In a single-user installation, `/nix` is owned by the invoking user.
-The script will invoke `sudo` to create `/nix` if it doesn’t already exist.
-If you don’t have `sudo`, manually create `/nix` as `root`:
-
-```console
-$ su root
-# mkdir /nix
-# chown alice /nix
-```
-
-# Installing from a binary tarball
-
-You can also download a binary tarball that contains Nix and all its dependencies:
-- Choose a [version](https://releases.nixos.org/?prefix=nix/) and [system type](../development/building.md#platforms)
-- Download and unpack the tarball
-- Run the installer
-
-> **Example**
->
-> ```console
-> $ pushd $(mktemp -d)
-> $ export VERSION=2.19.2
-> $ export SYSTEM=x86_64-linux
-> $ curl -LO https://releases.nixos.org/nix/nix-$VERSION/nix-$VERSION-$SYSTEM.tar.xz
-> $ tar xfj nix-$VERSION-$SYSTEM.tar.xz
-> $ cd nix-$VERSION-$SYSTEM
-> $ ./install
-> $ popd
-> ```
-
-The installer can be customised with the environment variables declared in the file named `install-multi-user`.
-
-## Native packages for Linux distributions
-
-The Nix community maintains installers for some Linux distributions in their native packaging format(https://nix-community.github.io/nix-installers/).
-
-# macOS Installation
-
-
-[]{#sect-macos-installation-change-store-prefix}[]{#sect-macos-installation-encrypted-volume}[]{#sect-macos-installation-symlink}[]{#sect-macos-installation-recommended-notes}
-
-We believe we have ironed out how to cleanly support the read-only root file system
-on modern macOS. New installs will do this automatically.
-
-This section previously detailed the situation, options, and trade-offs,
-but it now only outlines what the installer does. You don't need to know
-this to run the installer, but it may help if you run into trouble:
-
-- create a new APFS volume for your Nix store
-- update `/etc/synthetic.conf` to direct macOS to create a "synthetic"
- empty root directory to mount your volume
-- specify mount options for the volume in `/etc/fstab`
- - `rw`: read-write
- - `noauto`: prevent the system from auto-mounting the volume (so the
- LaunchDaemon mentioned below can control mounting it, and to avoid
- masking problems with that mounting service).
- - `nobrowse`: prevent the Nix Store volume from showing up on your
- desktop; also keeps Spotlight from spending resources to index
- this volume
-
-- if you have FileVault enabled
- - generate an encryption password
- - put it in your system Keychain
- - use it to encrypt the volume
-- create a system LaunchDaemon to mount this volume early enough in the
- boot process to avoid problems loading or restoring any programs that
- need access to your Nix store
-
diff --git a/doc/manual/source/installation/nix-security.md b/doc/manual/source/installation/nix-security.md
index 1e9036b68b2..61cad24c2b3 100644
--- a/doc/manual/source/installation/nix-security.md
+++ b/doc/manual/source/installation/nix-security.md
@@ -1,15 +1,85 @@
# Security
-Nix has two basic security models. First, it can be used in “single-user
-mode”, which is similar to what most other package management tools do:
-there is a single user (typically root) who performs all package
-management operations. All other users can then use the installed
-packages, but they cannot perform package management operations
-themselves.
-
-Alternatively, you can configure Nix in “multi-user mode”. In this
-model, all users can perform package management operations — for
-instance, every user can install software without requiring root
-privileges. Nix ensures that this is secure. For instance, it’s not
-possible for one user to overwrite a package used by another user with a
-Trojan horse.
+Nix follows a [**multi-user**](#multi-user-model) security model in which all
+users can perform package management operations. Every user can, for example,
+install software without requiring root privileges, and Nix ensures that this
+is secure. It's *not* possible for one user to, for example, overwrite a
+package used by another user with a Trojan horse.
+
+## Multi-User model
+
+To allow a Nix store to be shared safely among multiple users, it is
+important that users are not able to run builders that modify the Nix
+store or database in arbitrary ways, or that interfere with builds
+started by other users. If they could do so, they could install a Trojan
+horse in some package and compromise the accounts of other users.
+
+To prevent this, the Nix store and database are owned by some privileged
+user (usually `root`) and builders are executed under special user
+accounts (usually named `nixbld1`, `nixbld2`, etc.). When a unprivileged
+user runs a Nix command, actions that operate on the Nix store (such as
+builds) are forwarded to a *Nix daemon* running under the owner of the
+Nix store/database that performs the operation.
+
+> **Note**
+>
+> Multi-user mode has one important limitation: only root and a set of
+> trusted users specified in `nix.conf` can specify arbitrary binary
+> caches. So while unprivileged users may install packages from
+> arbitrary Nix expressions, they may not get pre-built binaries.
+
+### Setting up the build users
+
+The *build users* are the special UIDs under which builds are performed.
+They should all be members of the *build users group* `nixbld`. This
+group should have no other members. The build users should not be
+members of any other group. On Linux, you can create the group and users
+as follows:
+
+```console
+$ groupadd -r nixbld
+$ for n in $(seq 1 10); do useradd -c "Nix build user $n" \
+ -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(which nologin)" \
+ nixbld$n; done
+```
+
+This creates 10 build users. There can never be more concurrent builds
+than the number of build users, so you may want to increase this if you
+expect to do many builds at the same time.
+
+### Running the daemon
+
+The [Nix daemon](../command-ref/nix-daemon.md) should be started as
+follows (as `root`):
+
+```console
+$ nix-daemon
+```
+
+You’ll want to put that line somewhere in your system’s boot scripts.
+
+To let unprivileged users use the daemon, they should set the
+[`NIX_REMOTE` environment variable](../command-ref/env-common.md) to
+`daemon`. So you should put a line like
+
+```console
+export NIX_REMOTE=daemon
+```
+
+into the users’ login scripts.
+
+### Restricting access
+
+To limit which users can perform Nix operations, you can use the
+permissions on the directory `/nix/var/nix/daemon-socket`. For instance,
+if you want to restrict the use of Nix to the members of a group called
+`nix-users`, do
+
+```console
+$ chgrp nix-users /nix/var/nix/daemon-socket
+$ chmod ug=rwx,o= /nix/var/nix/daemon-socket
+```
+
+This way, users who are not in the `nix-users` group cannot connect to
+the Unix domain socket `/nix/var/nix/daemon-socket/socket`, so they
+cannot perform Nix operations.
diff --git a/doc/manual/source/installation/single-user.md b/doc/manual/source/installation/single-user.md
deleted file mode 100644
index f9a3b26edf4..00000000000
--- a/doc/manual/source/installation/single-user.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Single-User Mode
-
-In single-user mode, all Nix operations that access the database in
-`prefix/var/nix/db` or modify the Nix store in `prefix/store` must be
-performed under the user ID that owns those directories. This is
-typically root. (If you install from RPM packages, that’s in fact the
-default ownership.) However, on single-user machines, it is often
-convenient to `chown` those directories to your normal user account so
-that you don’t have to `su` to root all the time.
diff --git a/doc/manual/source/installation/supported-platforms.md b/doc/manual/source/installation/supported-platforms.md
deleted file mode 100644
index 8ca3ce8d445..00000000000
--- a/doc/manual/source/installation/supported-platforms.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Supported Platforms
-
-Nix is currently supported on the following platforms:
-
- - Linux (i686, x86\_64, aarch64).
-
- - macOS (x86\_64, aarch64).
diff --git a/doc/manual/source/installation/uninstall.md b/doc/manual/source/installation/uninstall.md
index 69d59847b6f..e95634c213a 100644
--- a/doc/manual/source/installation/uninstall.md
+++ b/doc/manual/source/installation/uninstall.md
@@ -1,197 +1,15 @@
# Uninstalling Nix
-## Multi User
-
-Removing a [multi-user installation](./installing-binary.md#multi-user-installation) 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:
+To uninstall Determinate Nix, use the uninstallation utility built into the [Determinate Nix Installer][installer]:
```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 ~root/.cache/nix
+$ /nix/nix-installer uninstall
```
-Remove build users and their group:
+If you're certain that you want to uninstall, you can skip the confirmation step:
```console
-for i in $(seq 1 32); do
- sudo userdel nixbld$i
-done
-sudo groupdel nixbld
+$ /nix/nix-installer uninstall --no-confirm
```
-There may also be references to Nix in
-
-- `/etc/bash.bashrc`
-- `/etc/bashrc`
-- `/etc/profile`
-- `/etc/zsh/zshrc`
-- `/etc/zshrc`
-
-which you may remove.
-
-### FreeBSD
-
-1. Stop and remove the Nix daemon service:
-
- ```console
- sudo service nix-daemon stop
- sudo rm -f /usr/local/etc/rc.d/nix-daemon
- sudo sysrc -x nix_daemon_enable
- ```
-
-2. Remove files created by Nix:
-
- ```console
- sudo rm -rf /etc/nix /usr/local/etc/profile.d/nix.sh /nix ~root/.nix-channels ~root/.nix-defexpr ~root/.nix-profile ~root/.cache/nix
- ```
-
-3. Remove build users and their group:
-
- ```console
- for i in $(seq 1 32); do
- sudo pw userdel nixbld$i
- done
- sudo pw groupdel nixbld
- ```
-
-4. There may also be references to Nix in:
- - `/usr/local/etc/bashrc`
- - `/usr/local/etc/zshrc`
- - Shell configuration files in users' home directories
-
- which you may remove.
-
-### macOS
-
-> **Updating to macOS 15 Sequoia**
->
-> If you recently updated to macOS 15 Sequoia and are getting
-> ```console
-> error: the user '_nixbld1' in the group 'nixbld' does not exist
-> ```
-> when running Nix commands, refer to GitHub issue [NixOS/nix#10892](https://github.com/NixOS/nix/issues/10892) for instructions to fix your installation without reinstalling.
-
-1. If system-wide shell initialisation files haven't been altered since installing Nix, use the backups made by the installer:
-
- ```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
- ```
-
- Otherwise, 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
- ```
-
-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
- ```
-
- by setting the cursor on the respective line using the arrow keys, and pressing `dd`, and then `:wq` to save the file.
-
- 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:
-
- ```bash
- if [ -f /etc/synthetic.conf ]; then
- if [ "$(cat /etc/synthetic.conf)" = "nix" ]; then
- sudo rm /etc/synthetic.conf
- else
- sudo vi /etc/synthetic.conf
- fi
- fi
- ```
-
- This will prevent the creation of the empty `/nix` directory.
-
-6. Remove the files Nix added to your system, except for the store:
-
- ```console
- sudo rm -rf /etc/nix /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
- ```
-
-
-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_ find a "Nix Store" volume, delete it by running `diskutil apfs deleteVolume` with the store volume's `diskXsY` identifier.
-
- If you get an error that the volume is in use by the kernel, reboot and immediately delete the volume before starting any other process.
-
-> **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.
-
-## Single User
-
-To remove a [single-user installation](./installing-binary.md#single-user-installation) of Nix, run:
-
-```console
-rm -rf /nix ~/.nix-channels ~/.nix-defexpr ~/.nix-profile
-```
-You might also want to manually remove references to Nix from your `~/.profile`.
+[installer]: https://github.com/DeterminateSystems/nix-installer
diff --git a/doc/manual/source/installation/upgrading.md b/doc/manual/source/installation/upgrading.md
index a433f1d30e6..8fe342b09b7 100644
--- a/doc/manual/source/installation/upgrading.md
+++ b/doc/manual/source/installation/upgrading.md
@@ -1,40 +1,10 @@
# Upgrading Nix
-> **Note**
->
-> These upgrade instructions apply where Nix was installed following the [installation instructions in this manual](./index.md).
-
-Check which Nix version will be installed, for example from one of the [release channels](http://channels.nixos.org/) such as `nixpkgs-unstable`:
-
-```console
-$ nix-shell -p nix -I nixpkgs=channel:nixpkgs-unstable --run "nix --version"
-nix (Nix) 2.18.1
-```
-
-> **Warning**
->
-> Writing to the [local store](@docroot@/store/types/local-store.md) with a newer version of Nix, for example by building derivations with [`nix-build`](@docroot@/command-ref/nix-build.md) or [`nix-store --realise`](@docroot@/command-ref/nix-store/realise.md), may change the database schema!
-> Reverting to an older version of Nix may therefore require purging the store database before it can be used.
-
-## Linux multi-user
+You can upgrade Determinate Nix using Determinate Nixd:
```console
-$ sudo su
-# nix-env --install --file '' --attr nix cacert -I nixpkgs=channel:nixpkgs-unstable
-# systemctl daemon-reload
-# systemctl restart nix-daemon
+sudo determinate-nixd upgrade
```
-## macOS multi-user
+Note that the `sudo` is necessary here and upgrading fails without it.
-```console
-$ sudo nix-env --install --file '' --attr nix cacert -I nixpkgs=channel:nixpkgs-unstable
-$ sudo launchctl remove org.nixos.nix-daemon
-$ sudo launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist
-```
-
-## Single-user all platforms
-
-```console
-$ nix-env --install --file '' --attr nix cacert -I nixpkgs=channel:nixpkgs-unstable
-```
diff --git a/doc/manual/source/introduction.md b/doc/manual/source/introduction.md
index e70411c11f5..fedb5595a1d 100644
--- a/doc/manual/source/introduction.md
+++ b/doc/manual/source/introduction.md
@@ -1,4 +1,19 @@
-# Introduction
+# Determinate Nix
+
+**Determinate Nix** is a downstream distribution of [Nix], a purely functional language, CLI tool, and package management system.
+It's available on Linux, macOS, and Windows Subsystem for Linux (WSL).
+
+## Installing
+
+We recommend that macOS users install Determinate Nix using our graphical installer, [Determinate.pkg][pkg].
+For Linux and Windows Subsystem for Linux (WSL) users:
+
+```console
+curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | \
+ sh -s -- install --determinate
+```
+
+## How Nix works
Nix is a _purely functional package manager_. This means that it
treats packages like values in a purely functional programming language
@@ -184,10 +199,14 @@ to build configuration files in `/etc`). This means, among other
things, that it is easy to roll back the entire configuration of the
system to an earlier state. Also, users can install software without
root privileges. For more information and downloads, see the [NixOS
-homepage](https://nixos.org/).
+homepage][nix].
## License
Nix is released under the terms of the [GNU LGPLv2.1 or (at your
option) any later
-version](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html).
+version][license].
+
+[license]: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+[pkg]: https://install.determinate.systems/determinate-pkg/stable/Universal
+[site]: https://nixos.org
diff --git a/doc/manual/source/protocols/json/derivation.md b/doc/manual/source/protocols/json/derivation.md
index 04881776abc..2fc018c33ff 100644
--- a/doc/manual/source/protocols/json/derivation.md
+++ b/doc/manual/source/protocols/json/derivation.md
@@ -1,11 +1,5 @@
# Derivation JSON Format
-> **Warning**
->
-> This JSON format is currently
-> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
-> and subject to change.
-
The JSON serialization of a
[derivations](@docroot@/glossary.md#gloss-store-derivation)
is a JSON object with the following fields:
diff --git a/doc/manual/source/protocols/json/store-object-info.md b/doc/manual/source/protocols/json/store-object-info.md
index b7348538c35..4b029c40b5d 100644
--- a/doc/manual/source/protocols/json/store-object-info.md
+++ b/doc/manual/source/protocols/json/store-object-info.md
@@ -1,11 +1,5 @@
# Store object info JSON format
-> **Warning**
->
-> This JSON format is currently
-> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
-> and subject to change.
-
Info about a [store object].
* `path`:
diff --git a/doc/manual/source/quick-start.md b/doc/manual/source/quick-start.md
index 9eb7a326590..ffb87aa725f 100644
--- a/doc/manual/source/quick-start.md
+++ b/doc/manual/source/quick-start.md
@@ -3,10 +3,13 @@
This chapter is for impatient people who don't like reading documentation.
For more in-depth information you are kindly referred to subsequent chapters.
-1. Install Nix:
+1. Install Nix.
+ We recommend that macOS users install Determinate Nix using our graphical installer, [Determinate.pkg][pkg].
+ For Linux and Windows Subsystem for Linux (WSL) users:
```console
- $ curl -L https://nixos.org/nix/install | sh
+ $ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | \
+ sh -s -- install --determinate
```
The install script will use `sudo`, so make sure you have sufficient rights.
@@ -41,3 +44,5 @@ For more in-depth information you are kindly referred to subsequent chapters.
```console
$ nix-collect-garbage
```
+
+[pkg]: https://install.determinate.systems/determinate-pkg/stable/Universal
diff --git a/doc/manual/source/release-notes-determinate/changes.md b/doc/manual/source/release-notes-determinate/changes.md
new file mode 100644
index 00000000000..d55ed09bd31
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/changes.md
@@ -0,0 +1,129 @@
+# Changes between Nix and Determinate Nix
+
+This section lists the differences between upstream Nix 2.31 and Determinate Nix 3.11.2.
+
+* In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature.
+
+* In Determinate Nix, the new Nix CLI (i.e. the `nix` command) is stable. You no longer need to enable the `nix-command` experimental feature.
+
+* Determinate Nix has a setting [`json-log-path`](@docroot@/command-ref/conf-file.md#conf-json-log-path) to send a copy of all Nix log messages (in JSON format) to a file or Unix domain socket.
+
+* Determinate Nix has made `nix profile install` an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.
+
+* `nix-channel` and `channel:` url syntax (like `channel:nixos-24.11`) is deprecated, see: https://github.com/DeterminateSystems/nix-src/issues/34
+
+* Using indirect flake references and implicit inputs is deprecated, see: https://github.com/DeterminateSystems/nix-src/issues/37
+
+* Warnings around "dirty trees" are updated to reduce "dirty" jargon, and now refers to "uncommitted changes".
+
+
+
+
+
+
+
+* `nix upgrade-nix` is now inert, and suggests using `determinate-nixd upgrade` -- [DeterminateSystems/nix-src#55](https://github.com/DeterminateSystems/nix-src/pull/55)
+
+* Lazy Trees support has been merged. ([DeterminateSystems/nix-src#27](https://github.com/DeterminateSystems/nix-src/pull/27), [DeterminateSystems/nix-src#56](https://github.com/DeterminateSystems/nix-src/pull/56))
+
+
+
+
+
+
+
+
+
+* Faster `nix store copy-sigs` by @edolstra in [DeterminateSystems/nix-src#80](https://github.com/DeterminateSystems/nix-src/pull/80)
+
+* Document how to replicate nix-store --query --deriver with the nix cli by @grahamc in [DeterminateSystems/nix-src#82](https://github.com/DeterminateSystems/nix-src/pull/82)
+
+* nix profile: Replace ε and ∅ with descriptive English words by @grahamc in [DeterminateSystems/nix-src#81](https://github.com/DeterminateSystems/nix-src/pull/81)
+
+* Call out that `--keep-failed` with remote builders will keep the failed build directory on that builder by @cole-h in [DeterminateSystems/nix-src#85](https://github.com/DeterminateSystems/nix-src/pull/85)
+
+
+
+
+
+
+* When remote building with --keep-failed, only show "you can rerun" message if the derivation's platform is supported on this machine by @cole-h in [DeterminateSystems/nix-src#87](https://github.com/DeterminateSystems/nix-src/pull/87)
+
+* Indicate that sandbox-paths specifies a missing file in the corresponding error message. by @cole-h in [DeterminateSystems/nix-src#88](https://github.com/DeterminateSystems/nix-src/pull/88)
+
+* Use FlakeHub inputs by @lucperkins in [DeterminateSystems/nix-src#89](https://github.com/DeterminateSystems/nix-src/pull/89)
+
+* Proactively cache more flake inputs and fetches by @edolstra in [DeterminateSystems/nix-src#93](https://github.com/DeterminateSystems/nix-src/pull/93)
+
+* Fix the link to `builders-use-substitutes` documentation for `builders` by @lucperkins in [DeterminateSystems/nix-src#102](https://github.com/DeterminateSystems/nix-src/pull/102)
+
+* Improve caching of inputs in dry-run mode by @edolstra in [DeterminateSystems/nix-src#98](https://github.com/DeterminateSystems/nix-src/pull/98)
+
+
+
+
+
+
+
+* Fix fetchToStore() caching with --impure, improve testing by @edolstra in [DeterminateSystems/nix-src#117](https://github.com/DeterminateSystems/nix-src/pull/117)
+
+* Add lazy-locks setting by @edolstra in [DeterminateSystems/nix-src#113](https://github.com/DeterminateSystems/nix-src/pull/113)
+
+
+
+* `nix store delete` now explains why deletion fails by @edolstra in [DeterminateSystems/nix-src#130](https://github.com/DeterminateSystems/nix-src/pull/130)
+
+
+
+* nix flake check: Skip substitutable derivations by @edolstra in [DeterminateSystems/nix-src#134](https://github.com/DeterminateSystems/nix-src/pull/134)
+
+
+
+* Address ifdef problem with macOS/BSD sandboxing by @gustavderdrache in [DeterminateSystems/nix-src#142](https://github.com/DeterminateSystems/nix-src/pull/142)
+
+
+
+* ci: don't run the full test suite for x86_64-darwin by @grahamc in [DeterminateSystems/nix-src#144](https://github.com/DeterminateSystems/nix-src/pull/144)
+
+
+
+* Add an `external-builders` experimental feature [DeterminateSystems/nix-src#141](https://github.com/DeterminateSystems/nix-src/pull/141),
+[DeterminateSystems/nix-src#78](https://github.com/DeterminateSystems/nix-src/pull/78)
+
+
+
+
+
+* Tab completing arguments to Nix avoids network access [DeterminateSystems/nix-src#161](https://github.com/DeterminateSystems/nix-src/pull/161)
+
+* Importing Nixpkgs and other tarballs to the cache is 2-4x faster [DeterminateSystems/nix-src#149](https://github.com/DeterminateSystems/nix-src/pull/149)
+
+* Adding paths to the store is significantly faster [DeterminateSystems/nix-src#162](https://github.com/DeterminateSystems/nix-src/pull/162)
+
+
+
+
+
+* Build-time flake inputs [DeterminateSystems/nix-src#49](https://github.com/DeterminateSystems/nix-src/pull/49)
+
+
+
+* The default `nix flake init` template is much more useful [DeterminateSystems/nix-src#180](https://github.com/DeterminateSystems/nix-src/pull/180)
+
+
+
+
+
+
+
+
+* Multithreaded evaluation support [DeterminateSystems/nix-src#125](https://github.com/DeterminateSystems/nix-src/pull/125)
+
+
+
+
+
+
+* Fix some interactions with the registry and flakes that include a `?dir=` parameter [DeterminateSystems/nix-src#196](https://github.com/DeterminateSystems/nix-src/pull/196), [DeterminateSystems/nix-src#199](https://github.com/DeterminateSystems/nix-src/pull/199)
+
+* Only try to substitute input if fetching from its original location fails [DeterminateSystems/nix-src#202](https://github.com/DeterminateSystems/nix-src/pull/202)
diff --git a/doc/manual/source/release-notes-determinate/index.md b/doc/manual/source/release-notes-determinate/index.md
new file mode 100644
index 00000000000..bba33084424
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/index.md
@@ -0,0 +1,3 @@
+# Determinate Nix Release Notes
+
+This chapter lists the differences between Nix and Determinate Nix, as well as the release history of Determinate Nix.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.0.0.md b/doc/manual/source/release-notes-determinate/rl-3.0.0.md
new file mode 100644
index 00000000000..d60786e9a72
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.0.0.md
@@ -0,0 +1,5 @@
+# Release 3.0.0 (2025-03-04)
+
+* Initial release of Determinate Nix.
+
+* Based on [upstream Nix 2.26.2](../release-notes/rl-2.26.md).
diff --git a/doc/manual/source/release-notes-determinate/rl-3.1.0.md b/doc/manual/source/release-notes-determinate/rl-3.1.0.md
new file mode 100644
index 00000000000..96b7819d08d
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.1.0.md
@@ -0,0 +1,5 @@
+# Release 3.1.0 (2025-03-27)
+
+* Based on [upstream Nix 2.27.1](../release-notes/rl-2.27.md).
+
+* New setting `json-log-path` that sends a copy of all Nix log messages (in JSON format) to a file or Unix domain socket.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.3.0.md b/doc/manual/source/release-notes-determinate/rl-3.3.0.md
new file mode 100644
index 00000000000..badf96415df
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.3.0.md
@@ -0,0 +1,5 @@
+# Release 3.3.0 (2025-04-11)
+
+* Based on [upstream Nix 2.28.1](../release-notes/rl-2.28.md).
+
+* The `nix profile install` command is now an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.4.0.md b/doc/manual/source/release-notes-determinate/rl-3.4.0.md
new file mode 100644
index 00000000000..24ae03ca554
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.4.0.md
@@ -0,0 +1,50 @@
+# Release 3.4.0 (2025-04-25)
+
+* Based on [upstream Nix 2.28.2](../release-notes/rl-2.28.md).
+
+* **Warn users that `nix-channel` is deprecated.**
+
+This is the first change accomplishing our roadmap item of deprecating Nix channels: https://github.com/DeterminateSystems/nix-src/issues/34
+
+This is due to user confusion and surprising behavior of channels, especially in the context of user vs. root channels.
+
+The goal of this change is to make the user experience of Nix more predictable.
+In particular, these changes are to support users with lower levels of experience who are following guides that focus on channels as the mechanism of distribution.
+
+Users will now see this message:
+
+> nix-channel is deprecated in favor of flakes in Determinate Nix. For a guide on Nix flakes, see: https://zero-to-nix.com/. or details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.
+
+
+* **Warn users that `channel:` URLs are deprecated.**
+
+This is the second change regarding our deprecation of Nix channels.
+Using a `channel:` URL (like `channel:nixos-24.11`) will yield a warning like this:
+
+> Channels are deprecated in favor of flakes in Determinate Nix. Instead of 'channel:nixos-24.11', use 'https://nixos.org/channels/nixos-24.11/nixexprs.tar.xz'. For a guide on Nix flakes, see: https://zero-to-nix.com/. For details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.
+
+* **Warn users against indirect flake references in `flake.nix` inputs**
+
+This is the first change accomplishing our roadmap item of deprecating implicit and indirect flake inputs: https://github.com/DeterminateSystems/nix-src/issues/37
+
+The flake registry provides an important UX affordance for using Nix flakes and remote sources in command line uses.
+For that reason, the registry is not being deprecated entirely and will still be used for command-line incantations, like nix run.
+
+This move will eliminate user confusion and surprising behavior around global and local registries during flake input resolution.
+
+The goal of this change is to make the user experience of Nix more predictable.
+We have seen a pattern of confusion when using automatic flake inputs and local registries.
+Specifically, users' flake inputs resolving and locking inconsistently depending on the configuration of the host system.
+
+Users will now see the following warning if their flake.nix uses an implicit or indirect Flake reference input:
+
+> Flake input 'nixpkgs' uses the flake registry. Using the registry in flake inputs is deprecated in Determinate Nix. To make your flake future-proof, add the following to 'xxx/flake.nix':
+>
+> inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
+>
+> For more information, see: https://github.com/DeterminateSystems/nix-src/issues/37
+
+
+### Other updates:
+* Improve the "dirty tree" message. Determinate Nix will now say `Git tree '...' has uncommitted changes` instead of `Git tree '...' is dirty`
+* Stop warning about uncommitted changes in a Git repository when using `nix develop`
diff --git a/doc/manual/source/release-notes-determinate/rl-3.4.2.md b/doc/manual/source/release-notes-determinate/rl-3.4.2.md
new file mode 100644
index 00000000000..8acabd4425f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.4.2.md
@@ -0,0 +1,4 @@
+# Release 3.4.2 (2025-05-05)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.0.md b/doc/manual/source/release-notes-determinate/rl-3.5.0.md
new file mode 100644
index 00000000000..d5b26b9419e
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.0.md
@@ -0,0 +1,4 @@
+# Release 3.5.0 (2025-05-09)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.1.md b/doc/manual/source/release-notes-determinate/rl-3.5.1.md
new file mode 100644
index 00000000000..b0813ca59c9
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.1.md
@@ -0,0 +1,57 @@
+# Release 3.5.1 (2025-05-09)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
+## What's Changed
+
+Most notably, Lazy Trees has merged in to Determinate Nix and is in Feature Preview status, but remains disabled by default.
+Lazy trees massively improves performance in virtually all scenarios because it enables Nix to avoid making unnecessary copies of files into the Nix store.
+In testing, we saw iteration times on Nixpkgs **drop from over 12 seconds to 3.5 seconds**.
+
+After upgrading to Determinate Nix 3.5.1 with `sudo determinate-nixd upgrade`, enable lazy trees by adding this to `/etc/nix/nix.custom.conf`:
+
+```
+lazy-trees = true
+```
+
+Please note that our full flake regression test suite passes with no changes with lazy trees, and please report compatibility issues.
+
+Read [this GitHub comment](https://github.com/DeterminateSystems/nix-src/pull/27#pullrequestreview-2822153088) for further details and next steps.
+We'll be publishing an update on the [Determinate Systems blog](https://determinate.systems/posts/) in the next few days with more information as well.
+
+Relevant PRs:
+* Lazy trees v2 by @edolstra in [DeterminateSystems/nix-src#27](https://github.com/DeterminateSystems/nix-src/pull/27)
+* Improve lazy trees backward compatibility by @edolstra in [DeterminateSystems/nix-src#56](https://github.com/DeterminateSystems/nix-src/pull/56)
+
+
+### Additional changes in this release:
+* Bug fix: Flake input URLs are canonicalized before checking flake.lock file staleness, avoiding needlessly regenerating flake.lock files with `dir` in URL-style flakerefs by @edolstra in [DeterminateSystems/nix-src#57](https://github.com/DeterminateSystems/nix-src/pull/57)
+* `nix upgrade-nix` is deprecated in favor of `determinate-nixd upgrade`, by @gustavderdrache in [DeterminateSystems/nix-src#55](https://github.com/DeterminateSystems/nix-src/pull/55)
+* UX: Improved build failure and dependency failure error messages to include needed output paths by @edolstra in [DeterminateSystems/nix-src#58](https://github.com/DeterminateSystems/nix-src/pull/58).
+
+Previously:
+
+```
+error: builder for '/nix/store/[...]-nested-failure-bottom.drv' failed with exit code 1
+error: 1 dependencies of derivation '/nix/store/[...]-nested-failure-middle.drv' failed to build
+error: 1 dependencies of derivation '/nix/store/[...]-nested-failure-top.drv' failed to build
+```
+
+Now:
+
+```
+error: Cannot build '/nix/store/w37gflm9wz9dcnsgy3sfrmnlvm8qigaj-nested-failure-bottom.drv'.
+ Reason: builder failed with exit code 1.
+ Output paths:
+ /nix/store/yzybs8kp35dfipbzdlqcc6lxz62hax04-nested-failure-bottom
+error: Cannot build '/nix/store/00gr5hlxfc03x2675w6nn3pwfrz2fr62-nested-failure-middle.drv'.
+ Reason: 1 dependency failed.
+ Output paths:
+ /nix/store/h781j5h4bdchmb4c2lvy8qzh8733azhz-nested-failure-middle
+error: Cannot build '/nix/store/8am0ng1gyx8sbzyr0yx6jd5ix3yy5szc-nested-failure-top.drv'.
+ Reason: 1 dependency failed.
+ Output paths:
+ /nix/store/fh12637kgvp906s9yhi9w2dc7ghfwxs1-nested-failure-top
+```
+
+**Full Changelog**: [v3.4.2...v3.5.1](https://github.com/DeterminateSystems/nix-src/compare/v3.4.2...v3.5.1)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.2.md b/doc/manual/source/release-notes-determinate/rl-3.5.2.md
new file mode 100644
index 00000000000..bc5396c255b
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.2.md
@@ -0,0 +1,11 @@
+# Release 3.5.2 (2025-05-12)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
+## What's Changed
+* Fix a regression where narHash was not added to lock files when lazy trees were disabled by @edolstra in [DeterminateSystems/nix-src#63](https://github.com/DeterminateSystems/nix-src/pull/63)
+
+* Tell users a source is corrupted ("cannot read file from tarball: Truncated tar archive detected while reading data"), improving over the previous 'cannot read file from tarball' error by @edolstra in [DeterminateSystems/nix-src#64](https://github.com/DeterminateSystems/nix-src/pull/64)
+
+
+**Full Changelog**: [v3.5.1...v3.5.2](https://github.com/DeterminateSystems/nix-src/compare/v3.5.1...v3.5.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.0.md b/doc/manual/source/release-notes-determinate/rl-3.6.0.md
new file mode 100644
index 00000000000..453ab6c301d
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.0.md
@@ -0,0 +1,11 @@
+# Release 3.6.0 (2025-05-22)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Install 'nix profile add' manpage by @edolstra in [DeterminateSystems/nix-src#69](https://github.com/DeterminateSystems/nix-src/pull/69)
+* Sync with upstream 2.29.0 by @edolstra in [DeterminateSystems/nix-src#67](https://github.com/DeterminateSystems/nix-src/pull/67)
+* Emit warnings when using import-from-derivation by setting the `trace-import-from-derivation` option to `true` by @gustavderdrache in [DeterminateSystems/nix-src#70](https://github.com/DeterminateSystems/nix-src/pull/70)
+
+
+**Full Changelog**: [v3.5.2...v3.6.0](https://github.com/DeterminateSystems/nix-src/compare/v3.5.2...v3.6.0)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.1.md b/doc/manual/source/release-notes-determinate/rl-3.6.1.md
new file mode 100644
index 00000000000..12505afee27
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.1.md
@@ -0,0 +1,9 @@
+# Release 3.6.1 (2025-05-24)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Fix nlohmann error in fromStructuredAttrs() by @edolstra in [DeterminateSystems/nix-src#73](https://github.com/DeterminateSystems/nix-src/pull/73)
+
+
+**Full Changelog**: [v3.6.0...v3.6.1](https://github.com/DeterminateSystems/nix-src/compare/v3.6.0...v3.6.1)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.2.md b/doc/manual/source/release-notes-determinate/rl-3.6.2.md
new file mode 100644
index 00000000000..882c142f00c
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.2.md
@@ -0,0 +1,15 @@
+# Release 3.6.2 (2025-06-02)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Dramatically improve the performance of nix store copy-sigs: Use http-connections setting to control parallelism by @edolstra in [DeterminateSystems/nix-src#80](https://github.com/DeterminateSystems/nix-src/pull/80)
+* Document how to replicate nix-store --query --deriver with the nix cli by @grahamc in [DeterminateSystems/nix-src#82](https://github.com/DeterminateSystems/nix-src/pull/82)
+* The garbage collector no longer gives up if it encounters an undeletable file, by @edolstra in [DeterminateSystems/nix-src#83](https://github.com/DeterminateSystems/nix-src/pull/83)
+* nix profile: Replace ε and ∅ with descriptive English words by @grahamc in [DeterminateSystems/nix-src#81](https://github.com/DeterminateSystems/nix-src/pull/81)
+* Rework README to clarify that this distribution is our distribution, by @lucperkins in [DeterminateSystems/nix-src#84](https://github.com/DeterminateSystems/nix-src/pull/84)
+* Include the source location when warning about inefficient double copies by @edolstra in [DeterminateSystems/nix-src#79](https://github.com/DeterminateSystems/nix-src/pull/79)
+* Call out that `--keep-failed` with remote builders will keep the failed build directory on that builder by @cole-h in [DeterminateSystems/nix-src#85](https://github.com/DeterminateSystems/nix-src/pull/85)
+
+
+**Full Changelog**: [v3.6.1...v3.6.2](https://github.com/DeterminateSystems/nix-src/compare/v3.6.1...v3.6.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.5.md b/doc/manual/source/release-notes-determinate/rl-3.6.5.md
new file mode 100644
index 00000000000..8ef5be0fd0d
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.5.md
@@ -0,0 +1,19 @@
+# Release 3.6.5 (2025-06-12)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* When remote building with --keep-failed, only show "you can rerun" message if the derivation's platform is supported on this machine by @cole-h in [DeterminateSystems/nix-src#87](https://github.com/DeterminateSystems/nix-src/pull/87)
+* Indicate that sandbox-paths specifies a missing file in the corresponding error message. by @cole-h in [DeterminateSystems/nix-src#88](https://github.com/DeterminateSystems/nix-src/pull/88)
+* Render lazy tree paths in messages withouth the/nix/store/hash... prefix in substituted source trees by @edolstra in [DeterminateSystems/nix-src#91](https://github.com/DeterminateSystems/nix-src/pull/91)
+* Use FlakeHub inputs by @lucperkins in [DeterminateSystems/nix-src#89](https://github.com/DeterminateSystems/nix-src/pull/89)
+* Proactively cache more flake inputs and fetches by @edolstra in [DeterminateSystems/nix-src#93](https://github.com/DeterminateSystems/nix-src/pull/93)
+* Fix: register extra builtins just once by @edolstra in [DeterminateSystems/nix-src#97](https://github.com/DeterminateSystems/nix-src/pull/97)
+* Fix the link to `builders-use-substitutes` documentation for `builders` by @lucperkins in [DeterminateSystems/nix-src#102](https://github.com/DeterminateSystems/nix-src/pull/102)
+* Improve error messages that use the hypothetical future tense of "will" by @lucperkins in [DeterminateSystems/nix-src#92](https://github.com/DeterminateSystems/nix-src/pull/92)
+* Make the `nix repl` test more stable by @edolstra in [DeterminateSystems/nix-src#103](https://github.com/DeterminateSystems/nix-src/pull/103)
+* Run nixpkgsLibTests against lazy trees by @edolstra in [DeterminateSystems/nix-src#100](https://github.com/DeterminateSystems/nix-src/pull/100)
+* Run the Nix test suite against lazy trees by @edolstra in [DeterminateSystems/nix-src#105](https://github.com/DeterminateSystems/nix-src/pull/105)
+* Improve caching of inputs by @edolstra in [DeterminateSystems/nix-src#98](https://github.com/DeterminateSystems/nix-src/pull/98), [DeterminateSystems/nix-src#110](https://github.com/DeterminateSystems/nix-src/pull/110), and [DeterminateSystems/nix-src#115](https://github.com/DeterminateSystems/nix-src/pull/115)
+
+**Full Changelog**: [v3.6.2...v3.6.5](https://github.com/DeterminateSystems/nix-src/compare/v3.6.2...v3.6.4)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.6.md b/doc/manual/source/release-notes-determinate/rl-3.6.6.md
new file mode 100644
index 00000000000..bf4e3690afa
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.6.md
@@ -0,0 +1,7 @@
+# Release 3.6.6 (2025-06-17)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+* No-op release on the nix-src side, due to a regression on nix-darwin in determinate-nixd.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.7.md b/doc/manual/source/release-notes-determinate/rl-3.6.7.md
new file mode 100644
index 00000000000..197587f1b3a
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.7.md
@@ -0,0 +1,17 @@
+# Release 3.6.7 (2025-06-24)
+
+* Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+### Security contents
+
+* Patched against GHSA-g948-229j-48j3
+
+### Lazy trees:
+
+* Lazy trees now produces `flake.lock` files with NAR hashes unless `lazy-locks` is set to `true` by @edolstra in [DeterminateSystems/nix-src#113](https://github.com/DeterminateSystems/nix-src/pull/113)
+* Improved caching with lazy-trees when using --impure, with enhanced testing by @edolstra in [DeterminateSystems/nix-src#117](https://github.com/DeterminateSystems/nix-src/pull/117)
+
+
+**Full Changelog**: [v3.6.6...v3.6.7](https://github.com/DeterminateSystems/nix-src/compare/v3.6.6...v3.6.7)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.8.md b/doc/manual/source/release-notes-determinate/rl-3.6.8.md
new file mode 100644
index 00000000000..c4b4b96c9e7
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.8.md
@@ -0,0 +1,12 @@
+# Release 3.6.8 (2025-06-25)
+
+* Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Fix fetchToStore() caching with --impure, improve testing by @edolstra in [DeterminateSystems/nix-src#117](https://github.com/DeterminateSystems/nix-src/pull/117)
+* Add lazy-locks setting by @edolstra in [DeterminateSystems/nix-src#113](https://github.com/DeterminateSystems/nix-src/pull/113)
+* Sync 2.29.1 by @edolstra in [DeterminateSystems/nix-src#124](https://github.com/DeterminateSystems/nix-src/pull/124)
+* Release v3.6.7 by @github-actions in [DeterminateSystems/nix-src#126](https://github.com/DeterminateSystems/nix-src/pull/126)
+
+
+**Full Changelog**: [v3.6.6...v3.6.8](https://github.com/DeterminateSystems/nix-src/compare/v3.6.6...v3.6.8)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.7.0.md b/doc/manual/source/release-notes-determinate/rl-3.7.0.md
new file mode 100644
index 00000000000..8e5fc9ca6a1
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.7.0.md
@@ -0,0 +1,63 @@
+# Release 3.7.0 (2025-07-03)
+
+- Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+### Prefetch flake inputs in parallel
+
+By @edolstra in [DeterminateSystems/nix-src#127](https://github.com/DeterminateSystems/nix-src/pull/127)
+
+This release brings the command `nix flake prefetch-inputs`.
+
+Flake inputs are typically fetched "just in time."
+That means Nix fetches a flake input when the evaluator needs it, and not before.
+When the evaluator needs an input, evaluation is paused until the source is available.
+
+This causes a significant slow-down on projects with lots of flake inputs.
+
+The new command `nix flake prefetch-inputs` fetches all flake inputs in parallel.
+We expect running this new command before building will dramatically improve evaluation performance for most projects, especially in CI.
+Note that projects which with many unused flake inputs may not benefit from this change, since the new command fetches every input whether they're used or not.
+
+### Deep flake input overrides now work as expected
+
+By @edolstra in [DeterminateSystems/nix-src#108](https://github.com/DeterminateSystems/nix-src/pull/108)
+
+An override like:
+
+```
+inputs.foo.inputs.bar.inputs.nixpkgs.follows = "nixpkgs";
+```
+
+implicitly set `inputs.foo.inputs.bar` to `flake:bar`, which led to an unexpected error like:
+
+```
+error: cannot find flake 'flake:bar' in the flake registries
+```
+
+We now no longer create a parent override (like for `foo.bar` in the example above) if it doesn't set an explicit ref or follows attribute.
+We only recursively apply its child overrides.
+
+### `nix store delete` now shows you why deletion was not possible
+
+By @edolstra in [DeterminateSystems/nix-src#130](https://github.com/DeterminateSystems/nix-src/pull/130)
+
+For example:
+
+```
+error: Cannot delete path '/nix/store/6fcrjgfjip2ww3sx51rrmmghfsf60jvi-patchelf-0.14.3'
+ because it's referenced by the GC root '/home/eelco/Dev/nix-master/build/result'.
+
+error: Cannot delete path '/nix/store/rn0qyn3kmky26xgpr2n10vr787g57lff-cowsay-3.8.4'
+ because it's referenced by the GC root '/proc/3600568/environ'.
+
+error: Cannot delete path '/nix/store/klyng5rpdkwi5kbxkncy4gjwb490dlhb-foo.drv'
+ because it's in use by '{nix-process:3605324}'.
+```
+
+### Lazy-tree improvements
+
+- Improved lazy-tree evaluation caching for flakes accessed with a `path` flakeref by @edolstra in [DeterminateSystems/nix-src#131](https://github.com/DeterminateSystems/nix-src/pull/131)
+
+**Full Changelog**: [v3.6.8...v3.7.0](https://github.com/DeterminateSystems/nix-src/compare/v3.6.8...v3.7.0)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.0.md b/doc/manual/source/release-notes-determinate/rl-3.8.0.md
new file mode 100644
index 00000000000..4103d6df94e
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.0.md
@@ -0,0 +1,29 @@
+# Release 3.8.0 (2025-07-10)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Faster CI with `nix flake check`
+
+`nix flake check` no longer downloads flake outputs if no building is necessary.
+
+This command is intended to validate that a flake can fully evaluate and all outputs can build.
+If the outputs are available in a binary cache then both properties are confirmed to be true.
+Notably, downloading the output from the binary cache is not strictly necessary for the validation.
+
+Previously, `nix flake check` would download a flake output if the full build is available in a binary cache.
+
+Some users will find this change significantly reduces costly bandwidth and CI workflow time.
+
+PR: [DeterminateSystems/nix-src#134](https://github.com/DeterminateSystems/nix-src/pull/134)
+
+### Improved flake locking of transitive dependencies
+
+Determinate Nix now re-locks all transitive dependencies when changing a flake input's source URL.
+
+This fixes an issue where in some scenarios Nix would not re-lock those inputs and incorrectly use the old inputs' dependencies.
+
+PR: [DeterminateSystems/nix-src#137](https://github.com/DeterminateSystems/nix-src/pull/137)
+
+**Full Changelog**: [v3.7.0...v3.8.0](https://github.com/DeterminateSystems/nix-src/compare/v3.7.0...v3.8.0)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.1.md b/doc/manual/source/release-notes-determinate/rl-3.8.1.md
new file mode 100644
index 00000000000..90dc328f6ec
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.1.md
@@ -0,0 +1,9 @@
+# Release 3.8.1 (2025-07-11)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Address ifdef problem with macOS/BSD sandboxing by @gustavderdrache in [DeterminateSystems/nix-src#142](https://github.com/DeterminateSystems/nix-src/pull/142)
+
+
+**Full Changelog**: [v3.8.0...v3.8.1](https://github.com/DeterminateSystems/nix-src/compare/v3.8.0...v3.8.1)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.2.md b/doc/manual/source/release-notes-determinate/rl-3.8.2.md
new file mode 100644
index 00000000000..638d90f6841
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.2.md
@@ -0,0 +1,10 @@
+# Release 3.8.2 (2025-07-12)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+* ci: don't run the full test suite for x86_64-darwin by @grahamc in [DeterminateSystems/nix-src#144](https://github.com/DeterminateSystems/nix-src/pull/144)
+* Try publishing the manual again by @grahamc in [DeterminateSystems/nix-src#145](https://github.com/DeterminateSystems/nix-src/pull/145)
+
+
+**Full Changelog**: [v3.8.1...v3.8.2](https://github.com/DeterminateSystems/nix-src/compare/v3.8.1...v3.8.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.3.md b/doc/manual/source/release-notes-determinate/rl-3.8.3.md
new file mode 100644
index 00000000000..d3eb02bc7ea
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.3.md
@@ -0,0 +1,26 @@
+# Release 3.8.3 (2025-07-18)
+
+* Based on [upstream Nix 2.30.1](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Non-blocking evaluation caching
+
+Users reported evaluation would occasionally block other evaluation processes.
+
+The evaluation cache database is now opened in write-ahead mode to prevent delaying evaluations.
+
+PR: [DeterminateSystems/nix-src#150](https://github.com/DeterminateSystems/nix-src/pull/150)
+
+### New experimental feature: `external-builders`
+
+This experimental feature allows Nix to call an external program for the build environment.
+
+The interface and behavior of this feature may change at any moment without a correspondingly major semver version change.
+
+PRs:
+- [DeterminateSystems/nix-src#141](https://github.com/DeterminateSystems/nix-src/pull/141)
+- [DeterminateSystems/nix-src#152](https://github.com/DeterminateSystems/nix-src/pull/152)
+- [DeterminateSystems/nix-src#78](https://github.com/DeterminateSystems/nix-src/pull/78)
+
+**Full Changelog**: [v3.8.2...v3.8.3](https://github.com/DeterminateSystems/nix-src/compare/v3.8.2...v3.8.3)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.4.md b/doc/manual/source/release-notes-determinate/rl-3.8.4.md
new file mode 100644
index 00000000000..7c73e75ca02
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.4.md
@@ -0,0 +1,9 @@
+# Release 3.8.4 (2025-07-21)
+
+* Based on [upstream Nix 2.30.1](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Revert "Use WAL mode for SQLite cache databases" by @grahamc in [DeterminateSystems/nix-src#155](https://github.com/DeterminateSystems/nix-src/pull/155)
+
+
+**Full Changelog**: [v3.8.3...v3.8.4](https://github.com/DeterminateSystems/nix-src/compare/v3.8.3...v3.8.4)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.5.md b/doc/manual/source/release-notes-determinate/rl-3.8.5.md
new file mode 100644
index 00000000000..0f1bbe6f99d
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.5.md
@@ -0,0 +1,58 @@
+## What's Changed
+
+### Less time "unpacking into the Git cache"
+
+Unpacking sources into the user's cache is now takes 1/2 to 1/4 of the time it used to.
+Previously, Nix serially unpacked sources into the cache.
+This change takes better advantage of our users' hardware by parallelizing the import.
+Real life testing shows an initial Nixpkgs import takes 3.6s on Linux, when it used to take 11.7s.
+
+PR: [DeterminateSystems/nix-src#149](https://github.com/DeterminateSystems/nix-src/pull/149)
+
+### Copy paths to the daemon in parallel
+
+Determinate Nix's evaluator no longer blocks evaluation when copying paths to the store.
+Previously, Nix would pause evaluation when it needed to add files to the store.
+Now, the copying is performed in the background allowing evaluation to proceed.
+
+PR: [DeterminateSystems/nix-src#162](https://github.com/DeterminateSystems/nix-src/pull/162)
+
+### Faster Nix evaluation by reducing duplicate Nix daemon queries
+
+Determinate Nix more effectively caches store path validity data within a single evaluation.
+Previously, the Nix client would perform many thousands of exra Nix daemon requests.
+Each extra request takes real time, and this change reduced a sample evaluation by over 12,000 requests.
+
+PR: [DeterminateSystems/nix-src#157](https://github.com/DeterminateSystems/nix-src/pull/157)
+
+### More responsive tab completion
+
+Tab completion now implies the "--offline" flag, which disables most network requests.
+Previously, tab completing Nix arguments would attempt to fetch sources and access binary caches.
+Operating in offline mode improves the interactive experience of Nix when tab completing.
+
+PR: [DeterminateSystems/nix-src#161](https://github.com/DeterminateSystems/nix-src/pull/161)
+
+### ZFS users: we fixed the mysterious stall.
+
+Opening the Nix database is usually instantaneous but sometimes has a several second latency.
+Determinate Nix works around this issue, eliminating the frustrating random stall when running Nix commands.
+
+PR: [DeterminateSystems/nix-src#158](https://github.com/DeterminateSystems/nix-src/pull/158)
+
+### Other changes
+
+* Determinate Nix is now fully formatted by clang-format, making it easier than ever to contribute to the project.
+
+PR: [DeterminateSystems/nix-src#159](https://github.com/DeterminateSystems/nix-src/pull/159)
+
+* Determinate Nix is now based on upstream Nix 2.30.2.
+
+PR: [DeterminateSystems/nix-src#160](https://github.com/DeterminateSystems/nix-src/pull/160)
+
+* Determinate Nix now uses `main` as our development branch, moving away from `detsys-main`.
+
+PRs:
+* [DeterminateSystems/nix-src#164](https://github.com/DeterminateSystems/nix-src/pull/164)
+* [DeterminateSystems/nix-src#166](https://github.com/DeterminateSystems/nix-src/pull/166)
+
diff --git a/doc/manual/source/release-notes-determinate/v3.10.0.md b/doc/manual/source/release-notes-determinate/v3.10.0.md
new file mode 100644
index 00000000000..c644dd78744
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.10.0.md
@@ -0,0 +1,10 @@
+# Release 3.10.0 (2025-09-02)
+
+* Based on [upstream Nix 2.31.0](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+This release rebases Determinate Nix on upstream Nix 2.31.0.
+
+
+**Full Changelog**: [v3.9.1...v3.10.0](https://github.com/DeterminateSystems/nix-src/compare/v3.9.1...v3.10.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.10.1.md b/doc/manual/source/release-notes-determinate/v3.10.1.md
new file mode 100644
index 00000000000..08cbe4fd058
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.10.1.md
@@ -0,0 +1,9 @@
+# Release 3.10.1 (2025-09-02)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+This release rebases Determinate Nix on upstream Nix 2.31.1.
+
+
+**Full Changelog**: [v3.10.0...v3.10.1](https://github.com/DeterminateSystems/nix-src/compare/v3.10.0...v3.10.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.0.md b/doc/manual/source/release-notes-determinate/v3.11.0.md
new file mode 100644
index 00000000000..7abb665a5a9
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.0.md
@@ -0,0 +1,36 @@
+# Release 3.11.0 (2025-09-03)
+
+- Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+### Parallel evaluation
+
+The following commands are now able to evaluate Nix expressions in parallel:
+
+- `nix search`
+- `nix flake check`
+- `nix flake show`
+- `nix eval --json`
+
+This is currently in developer preview, and we'll be turning it on for more users in the coming weeks.
+If you would like to try it right away, specify `eval-cores` in your `/etc/nix/nix.custom.conf`:
+
+```ini
+eval-cores = 0 # Evaluate across all cores
+```
+
+Further, we introduced a new builtin: `builtins.parallel`.
+This new builtin allows users to explicitly parallelize evaluation within a Nix expression.
+
+Using this new builtin requires turning on an additional experimental feature:
+
+```ini
+extra-experimental-features = parallel-eval
+```
+
+Please note that this new builtin is subject to change semantics or even go away during the developer preview.
+
+PR: [DeterminateSystems/nix-src#125](https://github.com/DeterminateSystems/nix-src/pull/125)
+
+**Full Changelog**: [v3.10.1...v3.11.0](https://github.com/DeterminateSystems/nix-src/compare/v3.10.1...v3.11.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.1.md b/doc/manual/source/release-notes-determinate/v3.11.1.md
new file mode 100644
index 00000000000..30597164333
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.1.md
@@ -0,0 +1,9 @@
+# Release 3.11.1 (2025-09-04)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+* Fix race condition in Value::isTrivial() by @edolstra in [DeterminateSystems/nix-src#192](https://github.com/DeterminateSystems/nix-src/pull/192)
+
+
+**Full Changelog**: [v3.11.0...v3.11.1](https://github.com/DeterminateSystems/nix-src/compare/v3.11.0...v3.11.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.2.md b/doc/manual/source/release-notes-determinate/v3.11.2.md
new file mode 100644
index 00000000000..ac4fe569dff
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.2.md
@@ -0,0 +1,24 @@
+# Release 3.11.2 (2025-09-12)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+### Fix some interactions with the registry and flakes that include a `?dir=` parameter
+
+Some users were experiencing issues when their flake registry contained a flake that included a `?dir=` parameter, causing commands like `nix eval registry-with-flake-in-subdir#output` and those that used --inputs-from` to fail or behave incorrectly.
+
+This is now fixed, so use your flakes inside subdirs without fear!
+
+PRs: [DeterminateSystems/nix-src#196](https://github.com/DeterminateSystems/nix-src/pull/196), [DeterminateSystems/nix-src#199](https://github.com/DeterminateSystems/nix-src/pull/199)
+
+### Only substitute inputs if they haven't already been fetched
+
+When using `lazy-trees`, you might have noticed Nix fetching some source inputs from a cache, even though you could have sworn it already fetched those inputs!
+
+This fixes that behavior such that Nix will try to fetch inputs from their original location, and only if that fails fall back to fetching from a substituter.
+
+PR: [DeterminateSystems/nix-src#202](https://github.com/DeterminateSystems/nix-src/pull/202)
+
+
+**Full Changelog**: [v3.11.1...v3.11.2](https://github.com/DeterminateSystems/nix-src/compare/v3.11.1...v3.11.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.8.6.md b/doc/manual/source/release-notes-determinate/v3.8.6.md
new file mode 100644
index 00000000000..8f917f2362f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.8.6.md
@@ -0,0 +1,14 @@
+# Release 3.8.6 (2025-08-19)
+
+* Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Auto update release notes by @grahamc in [DeterminateSystems/nix-src#170](https://github.com/DeterminateSystems/nix-src/pull/170)
+* Use WAL mode for SQLite cache databases (2nd attempt) by @edolstra in [DeterminateSystems/nix-src#167](https://github.com/DeterminateSystems/nix-src/pull/167)
+* Enable parallel marking in boehm-gc by @edolstra in [DeterminateSystems/nix-src#168](https://github.com/DeterminateSystems/nix-src/pull/168)
+* BasicClientConnection::queryPathInfo(): Don't throw exception for invalid paths by @edolstra in [DeterminateSystems/nix-src#172](https://github.com/DeterminateSystems/nix-src/pull/172)
+* Fix queryPathInfo() negative caching by @edolstra in [DeterminateSystems/nix-src#173](https://github.com/DeterminateSystems/nix-src/pull/173)
+* forceDerivation(): Wait for async path write after forcing value by @edolstra in [DeterminateSystems/nix-src#176](https://github.com/DeterminateSystems/nix-src/pull/176)
+
+
+**Full Changelog**: [v3.8.5...v3.8.6](https://github.com/DeterminateSystems/nix-src/compare/v3.8.5...v3.8.6)
diff --git a/doc/manual/source/release-notes-determinate/v3.9.0.md b/doc/manual/source/release-notes-determinate/v3.9.0.md
new file mode 100644
index 00000000000..66deb69b619
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.9.0.md
@@ -0,0 +1,45 @@
+# Release 3.9.0 (2025-08-26)
+
+* Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Build-time flake inputs
+
+Some of our users have hundreds or thousands of flake inputs.
+In those cases, it is painfully slow for Nix to fetch all the inputs during evaluation of the flake.
+
+Determinate Nix has an experimental feature for deferring the fetching to build time of the dependent derivations.
+
+This is currently in developer preview.
+If you would like to try it, add the experimental feature to your `/etc/nix/nix.custom.conf`:
+
+```ini
+extra-experimental-features = build-time-fetch-tree
+```
+
+Then, mark an input to be fetched at build time:
+
+```nix
+inputs.example = {
+ type = "github";
+ owner = "DeterminateSystems";
+ repo = "example";
+ flake = false; # <-- currently required
+ buildTime = true;
+};
+```
+
+Let us know what you think!
+
+PR: [DeterminateSystems/nix-src#49](https://github.com/DeterminateSystems/nix-src/pull/49)
+
+### Corrected inconsistent behavior of `nix flake check`
+
+Users reported that `nix flake check` would not consistently validate the entire flake.
+
+We've fixed this issue and improved our testing around `nix flake check`.
+
+PR: [DeterminateSystems/nix-src#182](https://github.com/DeterminateSystems/nix-src/pull/182)
+
+**Full Changelog**: [v3.8.6...v3.9.0](https://github.com/DeterminateSystems/nix-src/compare/v3.8.6...v3.9.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.9.1.md b/doc/manual/source/release-notes-determinate/v3.9.1.md
new file mode 100644
index 00000000000..38d17199c2c
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.9.1.md
@@ -0,0 +1,20 @@
+# Release 3.9.1 (2025-08-28)
+
+- Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+### A useful `nix flake init` template default
+
+Nix's default flake template is [extremely bare bones](https://github.com/NixOS/templates/blob/ad0e221dda33c4b564fad976281130ce34a20cb9/trivial/flake.nix), and not a useful starting point.
+
+Deteminate Nix now uses [a more fleshed out default template](https://github.com/DeterminateSystems/flake-templates/blob/8af99b99627da41f16897f60eb226db30c775e76/default/flake.nix), including targeting multiple systems.
+
+PR: [DeterminateSystems/nix-src#180](https://github.com/DeterminateSystems/nix-src/pull/180)
+
+### Build cancellation is repaired on macOS
+
+A recent macOS update changed how signals are handled by Nix and broke using Ctrl-C to stop a build.
+Determinate Nix on macOS correctly handles these signals and stops the build.
+
+PR: [DeterminateSystems/nix-src#184](https://github.com/DeterminateSystems/nix-src/pull/184)
+
+**Full Changelog**: [v3.9.0...v3.9.1](https://github.com/DeterminateSystems/nix-src/compare/v3.9.0...v3.9.1)
diff --git a/doc/manual/source/release-notes/rl-2.19.md b/doc/manual/source/release-notes/rl-2.19.md
index 06c704324dd..47a0dd3db99 100644
--- a/doc/manual/source/release-notes/rl-2.19.md
+++ b/doc/manual/source/release-notes/rl-2.19.md
@@ -69,7 +69,7 @@
This makes it match `nix derivation show`, which also maps store paths to information.
-- When Nix is installed using the [binary installer](@docroot@/installation/installing-binary.md), in supported shells (Bash, Zsh, Fish)
+- When Nix is installed using the binary installer, in supported shells (Bash, Zsh, Fish)
[`XDG_DATA_DIRS`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables) is now populated with the path to the `/share` subdirectory of the current profile.
This means that command completion scripts, `.desktop` files, and similar artifacts installed via [`nix-env`](@docroot@/command-ref/nix-env.md) or [`nix profile`](@docroot@/command-ref/new-cli/nix3-profile.md)
(experimental) can be found by any program that follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
diff --git a/doc/manual/source/release-notes/rl-2.24.md b/doc/manual/source/release-notes/rl-2.24.md
index d4af3cb5174..33fc0db03f9 100644
--- a/doc/manual/source/release-notes/rl-2.24.md
+++ b/doc/manual/source/release-notes/rl-2.24.md
@@ -268,6 +268,21 @@
be configured using the `warn-large-path-threshold` setting,
e.g. `--warn-large-path-threshold 100M`.
+- Wrap filesystem exceptions more correctly [#11378](https://github.com/NixOS/nix/pull/11378)
+
+ With the switch to `std::filesystem` in different places, Nix started to throw `std::filesystem::filesystem_error` in many places instead of its own exceptions.
+
+ This led to no longer generating error traces, for example when listing a non-existing directory.
+
+ This version catches these types of exception correctly and wraps them into Nix's own exeception type.
+
+ Author: [**@Mic92**](https://github.com/Mic92)
+
+- `` uses TLS verification [#11585](https://github.com/NixOS/nix/pull/11585)
+
+ Previously `` did not do TLS verification. This was because the Nix sandbox in the past did not have access to TLS certificates, and Nix checks the hash of the fetched file anyway. However, this can expose authentication data from `netrc` and URLs to man-in-the-middle attackers. In addition, Nix now in some cases (such as when using impure derivations) does *not* check the hash. Therefore we have now enabled TLS verification. This means that downloads by `` will now fail if you're fetching from a HTTPS server that does not have a valid certificate.
+
+ `` is also known as the builtin derivation builder `builtin:fetchurl`. It's not to be confused with the evaluation-time function `builtins.fetchurl`, which was not affected by this issue.
## Contributors
diff --git a/docker.nix b/docker.nix
index 619e75c5440..7ed1aa938e5 100644
--- a/docker.nix
+++ b/docker.nix
@@ -333,7 +333,7 @@ let
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
mkdir -p $out/nix/var/nix/gcroots/auto
- rootName=$(${lib.getExe' nix "nix"} --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
+ rootName=$(${lib.getExe' nix "nix"} hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
'')
);
diff --git a/flake.lock b/flake.lock
index cc2b2f27e72..919115594d7 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
- "lastModified": 1733328505,
- "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
- "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@@ -23,58 +23,51 @@
]
},
"locked": {
- "lastModified": 1733312601,
- "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
- "owner": "hercules-ci",
- "repo": "flake-parts",
- "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
- "type": "github"
+ "lastModified": 1748821116,
+ "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=",
+ "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1",
+ "revCount": 377,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/hercules-ci/flake-parts/0.1.377%2Brev-49f0870db23e8c1ca0b5259734a02cd9e1e371a1/01972f28-554a-73f8-91f4-d488cc502f08/source.tar.gz"
},
"original": {
- "owner": "hercules-ci",
- "repo": "flake-parts",
- "type": "github"
+ "type": "tarball",
+ "url": "https://flakehub.com/f/hercules-ci/flake-parts/0.1"
}
},
"git-hooks-nix": {
"inputs": {
- "flake-compat": [],
+ "flake-compat": "flake-compat",
"gitignore": [],
"nixpkgs": [
"nixpkgs"
- ],
- "nixpkgs-stable": [
- "nixpkgs"
]
},
"locked": {
- "lastModified": 1734279981,
- "narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
- "owner": "cachix",
- "repo": "git-hooks.nix",
- "rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
- "type": "github"
+ "lastModified": 1747372754,
+ "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
+ "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
+ "revCount": 1026,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/cachix/git-hooks.nix/0.1.1026%2Brev-80479b6ec16fefd9c1db3ea13aeb038c60530f46/0196d79a-1b35-7b8e-a021-c894fb62163d/source.tar.gz"
},
"original": {
- "owner": "cachix",
- "repo": "git-hooks.nix",
- "type": "github"
+ "type": "tarball",
+ "url": "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941"
}
},
"nixpkgs": {
"locked": {
- "lastModified": 1756178832,
- "narHash": "sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "d98ce345cdab58477ca61855540999c86577d19d",
- "type": "github"
+ "lastModified": 1755922037,
+ "narHash": "sha256-wY1+2JPH0ZZC4BQefoZw/k+3+DowFyfOxv17CN/idKs=",
+ "rev": "b1b3291469652d5a2edb0becc4ef0246fff97a7c",
+ "revCount": 808723,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2505.808723%2Brev-b1b3291469652d5a2edb0becc4ef0246fff97a7c/0198daf7-011a-7703-95d7-57146e794342/source.tar.gz"
},
"original": {
- "owner": "NixOS",
- "ref": "nixos-25.05-small",
- "repo": "nixpkgs",
- "type": "github"
+ "type": "tarball",
+ "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2505"
}
},
"nixpkgs-23-11": {
@@ -111,7 +104,6 @@
},
"root": {
"inputs": {
- "flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"git-hooks-nix": "git-hooks-nix",
"nixpkgs": "nixpkgs",
diff --git a/flake.nix b/flake.nix
index a2bdeb0e594..967f8d8c397 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,24 +1,18 @@
{
description = "The purely functional package manager";
- inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
+ inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.2505";
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
- inputs.flake-compat = {
- url = "github:edolstra/flake-compat";
- flake = false;
- };
# dev tooling
- inputs.flake-parts.url = "github:hercules-ci/flake-parts";
- inputs.git-hooks-nix.url = "github:cachix/git-hooks.nix";
+ inputs.flake-parts.url = "https://flakehub.com/f/hercules-ci/flake-parts/0.1";
+ inputs.git-hooks-nix.url = "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941";
# work around https://github.com/NixOS/nix/issues/7730
inputs.flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
inputs.git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs";
- inputs.git-hooks-nix.inputs.nixpkgs-stable.follows = "nixpkgs";
# work around 7730 and https://github.com/NixOS/nix/issues/7807
- inputs.git-hooks-nix.inputs.flake-compat.follows = "";
inputs.git-hooks-nix.inputs.gitignore.follows = "";
outputs =
@@ -34,7 +28,7 @@
officialRelease = true;
- linux32BitSystems = [ "i686-linux" ];
+ linux32BitSystems = [ ];
linux64BitSystems = [
"x86_64-linux"
"aarch64-linux"
@@ -47,13 +41,12 @@
systems = linuxSystems ++ darwinSystems;
crossSystems = [
- "armv6l-unknown-linux-gnueabihf"
- "armv7l-unknown-linux-gnueabihf"
- "riscv64-unknown-linux-gnu"
+ #"armv6l-unknown-linux-gnueabihf"
+ #"armv7l-unknown-linux-gnueabihf"
+ #"riscv64-unknown-linux-gnu"
# Disabled because of https://github.com/NixOS/nixpkgs/issues/344423
# "x86_64-unknown-netbsd"
- "x86_64-unknown-freebsd"
- "x86_64-w64-mingw32"
+ #"x86_64-unknown-freebsd"
];
stdenvs = [
@@ -371,6 +364,40 @@
nix-manual = nixpkgsFor.${system}.native.nixComponents2.nix-manual;
nix-internal-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-internal-api-docs;
nix-external-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-external-api-docs;
+
+ fallbackPathsNix =
+ let
+ pkgs = nixpkgsFor.${system}.native;
+
+ closures = forAllSystems (system: self.packages.${system}.default.outPath);
+
+ closures_json =
+ pkgs.runCommand "versions.json"
+ {
+ buildInputs = [ pkgs.jq ];
+ passAsFile = [ "json" ];
+ json = builtins.toJSON closures;
+ }
+ ''
+ cat "$jsonPath" | jq . > $out
+ '';
+
+ closures_nix =
+ pkgs.runCommand "versions.nix"
+ {
+ buildInputs = [ pkgs.jq ];
+ passAsFile = [ "template" ];
+ jsonPath = closures_json;
+ template = ''
+ builtins.fromJSON('''@closures@''')
+ '';
+ }
+ ''
+ export closures=$(cat "$jsonPath");
+ substituteAll "$templatePath" "$out"
+ '';
+ in
+ closures_nix;
}
# We need to flatten recursive attribute sets of derivations to pass `flake check`.
//
@@ -425,8 +452,6 @@
{
# These attributes go right into `packages.`.
"${pkgName}" = nixpkgsFor.${system}.native.nixComponents2.${pkgName};
- "${pkgName}-static" = nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName};
- "${pkgName}-llvm" = nixpkgsFor.${system}.native.pkgsLLVM.nixComponents2.${pkgName};
}
// lib.optionalAttrs supportsCross (
flatMapAttrs (lib.genAttrs crossSystems (_: { })) (
@@ -482,32 +507,6 @@
}
)
)
- // lib.optionalAttrs (!nixpkgsFor.${system}.native.stdenv.isDarwin) (
- prefixAttrs "static" (
- forAllStdenvs (
- stdenvName:
- makeShell {
- pkgs = nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.pkgsStatic;
- }
- )
- )
- // prefixAttrs "llvm" (
- forAllStdenvs (
- stdenvName:
- makeShell {
- pkgs = nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.pkgsLLVM;
- }
- )
- )
- // prefixAttrs "cross" (
- forAllCrossSystems (
- crossSystem:
- makeShell {
- pkgs = nixpkgsFor.${system}.cross.${crossSystem};
- }
- )
- )
- )
// {
native = self.devShells.${system}.native-stdenv;
default = self.devShells.${system}.native;
diff --git a/maintainers/link-headers b/maintainers/link-headers
new file mode 100755
index 00000000000..2457a2dc829
--- /dev/null
+++ b/maintainers/link-headers
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+
+# This script must be run from the root of the Nix repository.
+#
+# For include path hygiene, we need to put headers in a separate
+# directory than sources. But during development, it is nice to paths
+# that are similar for headers and source files, e.g.
+# `foo/bar/baz.{cc,hh}`, e.g. for less typing when opening one file, and
+# then opening the other file.
+#
+# This script symlinks the headers next to the source files to
+# facilitate such a development workflows. It also updates
+# `.git/info/exclude` so that the symlinks are not accidentally committed
+# by mistake.
+
+from pathlib import Path
+import subprocess
+import os
+
+
+def main() -> None:
+ # Path to the source directory
+ GIT_TOPLEVEL = Path(
+ subprocess.run(
+ ["git", "rev-parse", "--show-toplevel"],
+ text=True,
+ stdout=subprocess.PIPE,
+ check=True,
+ ).stdout.strip()
+ )
+
+ # Get header files from git
+ result = subprocess.run(
+ ["git", "-C", str(GIT_TOPLEVEL), "ls-files", "*/include/nix/**.hh"],
+ text=True,
+ stdout=subprocess.PIPE,
+ check=True,
+ )
+ header_files = result.stdout.strip().split("\n")
+ header_files.sort()
+
+ links = []
+ for file_str in header_files:
+ project_str, header_str = file_str.split("/include/nix/", 1)
+ project = Path(project_str)
+ header = Path(header_str)
+
+ # Reconstruct the full path (relative to SRC_DIR) to the header file.
+ file = project / "include" / "nix" / header
+
+ # The symlink should be created at "project/header", i.e. next to the project's sources.
+ link = project / header
+
+ # Compute a relative path from the symlink's parent directory to the actual header file.
+ relative_source = os.path.relpath(
+ GIT_TOPLEVEL / file, GIT_TOPLEVEL / link.parent
+ )
+
+ # Create the symbolic link.
+ full_link_path = GIT_TOPLEVEL / link
+ full_link_path.parent.mkdir(parents=True, exist_ok=True)
+ if full_link_path.is_symlink():
+ full_link_path.unlink()
+ full_link_path.symlink_to(relative_source)
+ links.append(link)
+
+ # Generate .gitignore file
+ gitignore_path = GIT_TOPLEVEL / ".git" / "info" / "exclude"
+ gitignore_path.parent.mkdir(parents=True, exist_ok=True)
+ with gitignore_path.open("w") as gitignore:
+ gitignore.write("# DO NOT EDIT! Autogenerated\n")
+ gitignore.write(
+ "# Symlinks for headers to be next to sources for development\n"
+ )
+ gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')
+ gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')
+
+ for link in links:
+ gitignore.write(f"/{link}\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/packaging/components.nix b/packaging/components.nix
index b5fad404343..fcbd2712b82 100644
--- a/packaging/components.nix
+++ b/packaging/components.nix
@@ -27,7 +27,7 @@ let
pkg-config
;
- baseVersion = lib.fileContents ../.version;
+ baseVersion = lib.fileContents ../.version-determinate;
versionSuffix = lib.optionalString (!officialRelease) "pre";
@@ -51,15 +51,6 @@ let
exts: userFn: stdenv.mkDerivation (lib.extends (lib.composeManyExtensions exts) userFn);
setVersionLayer = finalAttrs: prevAttrs: {
- preConfigure =
- prevAttrs.preConfigure or ""
- +
- # Update the repo-global .version file.
- # Symlink ./.version points there, but by default only workDir is writable.
- ''
- chmod u+w ./.version
- echo ${finalAttrs.version} > ./.version
- '';
};
localSourceLayer =
diff --git a/packaging/dependencies.nix b/packaging/dependencies.nix
index 3d7da9acb44..d8aea9f3e49 100644
--- a/packaging/dependencies.nix
+++ b/packaging/dependencies.nix
@@ -85,6 +85,7 @@ scope: {
"--with-coroutine"
"--with-iostreams"
"--with-url"
+ "--with-thread"
];
enableIcu = false;
}).overrideAttrs
diff --git a/packaging/dev-shell.nix b/packaging/dev-shell.nix
index 949f7975231..ea064ad0937 100644
--- a/packaging/dev-shell.nix
+++ b/packaging/dev-shell.nix
@@ -26,7 +26,7 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
pname = "shell-for-" + attrs.pname;
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
- version = lib.fileContents ../.version;
+ version = lib.fileContents ../.version-determinate;
name = attrs.pname;
installFlags = "sysconfdir=$(out)/etc";
diff --git a/packaging/everything.nix b/packaging/everything.nix
index f6bdad4907b..3206b8ba423 100644
--- a/packaging/everything.nix
+++ b/packaging/everything.nix
@@ -75,7 +75,7 @@ let
};
devdoc = buildEnv {
- name = "nix-${nix-cli.version}-devdoc";
+ name = "determinate-nix-${nix-cli.version}-devdoc";
paths = [
nix-internal-api-docs
nix-external-api-docs
@@ -84,7 +84,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
- pname = "nix";
+ pname = "determinate-nix";
version = nix-cli.version;
/**
diff --git a/packaging/hydra.nix b/packaging/hydra.nix
index 9f9749bde16..d563bff0bb3 100644
--- a/packaging/hydra.nix
+++ b/packaging/hydra.nix
@@ -119,65 +119,6 @@ in
system: self.devShells.${system}.default.inputDerivation
)) [ "i686-linux" ];
- buildStatic = forAllPackages (
- pkgName:
- lib.genAttrs linux64BitSystems (
- system: nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName}
- )
- );
-
- buildCross = forAllPackages (
- pkgName:
- # Hack to avoid non-evaling package
- (
- if pkgName == "nix-functional-tests" then
- lib.flip builtins.removeAttrs [ "x86_64-w64-mingw32" ]
- else
- lib.id
- )
- (
- forAllCrossSystems (
- crossSystem:
- lib.genAttrs [ "x86_64-linux" ] (
- system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents2.${pkgName}
- )
- )
- )
- );
-
- buildNoGc =
- let
- components = forAllSystems (
- system:
- nixpkgsFor.${system}.native.nixComponents2.overrideScope (
- self: super: {
- nix-expr = super.nix-expr.override { enableGC = false; };
- }
- )
- );
- in
- forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
-
- buildNoTests = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-cli);
-
- # Toggles some settings for better coverage. Windows needs these
- # library combinations, and Debian build Nix with GNU readline too.
- buildReadlineNoMarkdown =
- let
- components = forAllSystems (
- system:
- nixpkgsFor.${system}.native.nixComponents2.overrideScope (
- self: super: {
- nix-cmd = super.nix-cmd.override {
- enableMarkdown = false;
- readlineFlavor = "readline";
- };
- }
- )
- );
- in
- forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
-
# Perl bindings for various platforms.
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-perl-bindings);
@@ -188,30 +129,6 @@ in
system: nixpkgsFor.${system}.native.callPackage ./binary-tarball.nix { }
);
- binaryTarballCross = lib.genAttrs [ "x86_64-linux" ] (
- system:
- forAllCrossSystems (
- crossSystem: nixpkgsFor.${system}.cross.${crossSystem}.callPackage ./binary-tarball.nix { }
- )
- );
-
- # The first half of the installation script. This is uploaded
- # to https://nixos.org/nix/install. It downloads the binary
- # tarball for the user's system and calls the second half of the
- # installation script.
- installerScript = installScriptFor [
- # Native
- self.hydraJobs.binaryTarball."x86_64-linux"
- self.hydraJobs.binaryTarball."i686-linux"
- self.hydraJobs.binaryTarball."aarch64-linux"
- self.hydraJobs.binaryTarball."x86_64-darwin"
- self.hydraJobs.binaryTarball."aarch64-darwin"
- # Cross
- self.hydraJobs.binaryTarballCross."x86_64-linux"."armv6l-unknown-linux-gnueabihf"
- self.hydraJobs.binaryTarballCross."x86_64-linux"."armv7l-unknown-linux-gnueabihf"
- self.hydraJobs.binaryTarballCross."x86_64-linux"."riscv64-unknown-linux-gnu"
- ];
-
installerScriptForGHA = forAllSystems (
system:
nixpkgsFor.${system}.native.callPackage ./installer {
@@ -279,6 +196,19 @@ in
pkgs = nixpkgsFor.${system}.native;
}
);
+
+ nixpkgsLibTestsLazy = forAllSystems (
+ system:
+ lib.overrideDerivation
+ (import (nixpkgs + "/lib/tests/test-with-nix.nix") {
+ lib = nixpkgsFor.${system}.native.lib;
+ nix = self.packages.${system}.nix-cli;
+ pkgs = nixpkgsFor.${system}.native;
+ })
+ (_: {
+ "NIX_CONFIG" = "lazy-trees = true";
+ })
+ );
};
metrics.nixpkgs = import "${nixpkgs-regression}/pkgs/top-level/metrics.nix" {
@@ -293,17 +223,12 @@ in
in
pkgs.runCommand "install-tests" {
againstSelf = testNixVersions pkgs pkgs.nix;
- againstCurrentLatest =
- # FIXME: temporarily disable this on macOS because of #3605.
- if system == "x86_64-linux" then testNixVersions pkgs pkgs.nixVersions.latest else null;
+ #againstCurrentLatest =
+ # # FIXME: temporarily disable this on macOS because of #3605.
+ # if system == "x86_64-linux" then testNixVersions pkgs pkgs.nixVersions.latest else null;
# Disabled because the latest stable version doesn't handle
# `NIX_DAEMON_SOCKET_PATH` which is required for the tests to work
# againstLatestStable = testNixVersions pkgs pkgs.nixStable;
} "touch $out"
);
-
- installerTests = import ../tests/installer {
- binaryTarballs = self.hydraJobs.binaryTarball;
- inherit nixpkgsFor;
- };
}
diff --git a/packaging/installer/default.nix b/packaging/installer/default.nix
index e171f36f99f..a8e344b496c 100644
--- a/packaging/installer/default.nix
+++ b/packaging/installer/default.nix
@@ -32,7 +32,7 @@ runCommand "installer-script"
in
''
\
- --replace '@tarballHash_${system}@' $(nix --experimental-features nix-command hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
+ --replace '@tarballHash_${system}@' $(nix hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
--replace '@tarballPath_${system}@' $(tarballPath ${tarball}/*.tar.xz) \
''
) tarballs
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index 918f4bbd9e9..00000000000
--- a/shell.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-(import (fetchTarball "https://github.com/edolstra/flake-compat/archive/master.tar.gz") {
- src = ./.;
-}).shellNix
diff --git a/src/external-api-docs/package.nix b/src/external-api-docs/package.nix
index b194e16d460..28cde8c09e6 100644
--- a/src/external-api-docs/package.nix
+++ b/src/external-api-docs/package.nix
@@ -14,7 +14,7 @@ let
in
mkMesonDerivation (finalAttrs: {
- pname = "nix-external-api-docs";
+ pname = "determinate-nix-external-api-docs";
inherit version;
workDir = ./.;
diff --git a/src/internal-api-docs/package.nix b/src/internal-api-docs/package.nix
index 6c4f354aee5..636c19653ea 100644
--- a/src/internal-api-docs/package.nix
+++ b/src/internal-api-docs/package.nix
@@ -14,7 +14,7 @@ let
in
mkMesonDerivation (finalAttrs: {
- pname = "nix-internal-api-docs";
+ pname = "determinate-nix-internal-api-docs";
inherit version;
workDir = ./.;
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 6b6bbe34585..077381eee43 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -125,6 +125,13 @@ ref EvalCommand::getEvalStore()
ref EvalCommand::getEvalState()
{
if (!evalState) {
+ if (startReplOnEvalErrors && evalSettings.evalCores != 1U) {
+ // Disable parallel eval if the debugger is enabled, since
+ // they're incompatible at the moment.
+ warn("using the debugger disables multi-threaded evaluation");
+ evalSettings.evalCores = 1;
+ }
+
evalState = std::allocate_shared(
traceable_allocator(), lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore());
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index f7e086c169c..890fe8337b3 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -19,17 +19,12 @@
namespace nix {
-fetchers::Settings fetchSettings;
-
-static GlobalConfig::Register rFetchSettings(&fetchSettings);
-
EvalSettings evalSettings{
settings.readOnlyMode,
{
{
"flake",
[](EvalState & state, std::string_view rest) {
- experimentalFeatureSettings.require(Xp::Flakes);
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(fetchSettings, std::string{rest}, {}, true, false);
debug("fetching flake search path element '%s''", rest);
@@ -185,7 +180,6 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas
}
else if (hasPrefix(s, "flake:")) {
- experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(fetchSettings, std::string(s.substr(6)), {}, true, false);
auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store);
auto storePath = nix::fetchToStore(
diff --git a/src/libcmd/include/nix/cmd/command.hh b/src/libcmd/include/nix/cmd/command.hh
index 20cd1abc1c4..0455a1d3c85 100644
--- a/src/libcmd/include/nix/cmd/command.hh
+++ b/src/libcmd/include/nix/cmd/command.hh
@@ -214,6 +214,8 @@ struct InstallableCommand : virtual Args, SourceExprCommand
{
InstallableCommand();
+ virtual void preRun(ref store);
+
virtual void run(ref store, ref installable) = 0;
void run(ref store) override;
diff --git a/src/libcmd/include/nix/cmd/common-eval-args.hh b/src/libcmd/include/nix/cmd/common-eval-args.hh
index 62518ba0e7f..dd8c34c1d9c 100644
--- a/src/libcmd/include/nix/cmd/common-eval-args.hh
+++ b/src/libcmd/include/nix/cmd/common-eval-args.hh
@@ -25,9 +25,6 @@ namespace flake {
struct Settings;
}
-/**
- * @todo Get rid of global settings variables
- */
extern fetchers::Settings fetchSettings;
/**
diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc
index 28c3db3fc79..3a80aa384de 100644
--- a/src/libcmd/installable-attr-path.cc
+++ b/src/libcmd/installable-attr-path.cc
@@ -89,7 +89,8 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
}
DerivedPathsWithInfo res;
- for (auto & [drvPath, outputs] : byDrvPath)
+ for (auto & [drvPath, outputs] : byDrvPath) {
+ state->waitForPath(drvPath);
res.push_back({
.path =
DerivedPath::Built{
@@ -102,6 +103,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
so we can fill in this info. */
}),
});
+ }
return res;
}
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 97f7eb645fa..77210ef8108 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -102,6 +102,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
}
auto drvPath = attr->forceDerivation();
+ state->waitForPath(drvPath);
std::optional priority;
diff --git a/src/libcmd/installable-value.cc b/src/libcmd/installable-value.cc
index 3a167af3db4..ec53ee97c89 100644
--- a/src/libcmd/installable-value.cc
+++ b/src/libcmd/installable-value.cc
@@ -55,7 +55,7 @@ InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::
else if (v.type() == nString) {
return {{
- .path = DerivedPath::fromSingle(state->coerceToSingleDerivedPath(pos, v, errorCtx)),
+ .path = DerivedPath::fromSingle(state->devirtualize(state->coerceToSingleDerivedPath(pos, v, errorCtx))),
.info = make_ref(),
}};
}
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 0e6a204a7fb..433c842b2c4 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -178,10 +178,16 @@ MixFlakeOptions::MixFlakeOptions()
for (auto & [inputName, input] : flake.lockFile.root->inputs) {
auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes
if (auto input3 = std::dynamic_pointer_cast(input2)) {
+ fetchers::Attrs extraAttrs;
+
+ if (!input3->lockedRef.subdir.empty()) {
+ extraAttrs["dir"] = input3->lockedRef.subdir;
+ }
+
overrideRegistry(
fetchers::Input::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", inputName}}),
input3->lockedRef.input,
- {});
+ extraAttrs);
}
}
}},
@@ -395,9 +401,6 @@ void completeFlakeRefWithFragment(
void completeFlakeRef(AddCompletions & completions, ref store, std::string_view prefix)
{
- if (!experimentalFeatureSettings.isEnabled(Xp::Flakes))
- return;
-
if (prefix == "")
completions.add(".");
@@ -869,8 +872,11 @@ InstallableCommand::InstallableCommand()
});
}
+void InstallableCommand::preRun(ref store) {}
+
void InstallableCommand::run(ref store)
{
+ preRun(store);
auto installable = parseInstallable(store, _installable);
run(store, std::move(installable));
}
diff --git a/src/libcmd/package.nix b/src/libcmd/package.nix
index c382f0e5760..21d7586a321 100644
--- a/src/libcmd/package.nix
+++ b/src/libcmd/package.nix
@@ -35,7 +35,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-cmd";
+ pname = "determinate-nix-cmd";
inherit version;
workDir = ./.;
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 01d786debfb..9f470928c56 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -333,6 +333,7 @@ StorePath NixRepl::getDerivationPath(Value & v)
auto drvPath = packageInfo->queryDrvPath();
if (!drvPath)
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
+ state->waitForPath(*drvPath);
if (!state->store->isValidPath(*drvPath))
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
return *drvPath;
diff --git a/src/libexpr-c/nix_api_expr.cc b/src/libexpr-c/nix_api_expr.cc
index 02e901de9f2..454a7652bf5 100644
--- a/src/libexpr-c/nix_api_expr.cc
+++ b/src/libexpr-c/nix_api_expr.cc
@@ -69,6 +69,7 @@ nix_err nix_expr_eval_from_string(
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
state->state.eval(parsedExpr, value->value);
state->state.forceValue(value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -80,6 +81,7 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n
try {
state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
state->state.forceValue(value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -92,6 +94,7 @@ nix_err nix_value_call_multi(
try {
state->state.callFunction(fn->value, {(nix::Value **) args, nargs}, value->value, nix::noPos);
state->state.forceValue(value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -102,6 +105,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value *
context->last_err_code = NIX_OK;
try {
state->state.forceValue(value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -112,6 +116,7 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
context->last_err_code = NIX_OK;
try {
state->state.forceValueDeep(value->value);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
diff --git a/src/libexpr-c/nix_api_value.cc b/src/libexpr-c/nix_api_value.cc
index fb90e2872e6..71a4c2f72e3 100644
--- a/src/libexpr-c/nix_api_value.cc
+++ b/src/libexpr-c/nix_api_value.cc
@@ -175,6 +175,8 @@ ValueType nix_get_type(nix_c_context * context, const nix_value * value)
switch (v.type()) {
case nThunk:
return NIX_TYPE_THUNK;
+ case nFailed:
+ return NIX_TYPE_FAILED;
case nInt:
return NIX_TYPE_INT;
case nFloat:
@@ -345,6 +347,7 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
if (attr) {
nix_gc_incref(nullptr, attr->value);
state->state.forceValue(*attr->value, nix::noPos);
+ state->state.waitForAllPaths();
return as_nix_value_ptr(attr->value);
}
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
diff --git a/src/libexpr-c/nix_api_value.h b/src/libexpr-c/nix_api_value.h
index 7cd6ad18087..263ca526e77 100644
--- a/src/libexpr-c/nix_api_value.h
+++ b/src/libexpr-c/nix_api_value.h
@@ -32,7 +32,8 @@ typedef enum {
NIX_TYPE_ATTRS,
NIX_TYPE_LIST,
NIX_TYPE_FUNCTION,
- NIX_TYPE_EXTERNAL
+ NIX_TYPE_EXTERNAL,
+ NIX_TYPE_FAILED,
} ValueType;
// forward declarations
diff --git a/src/libexpr-c/package.nix b/src/libexpr-c/package.nix
index 694fbc1fe78..ec92ecce105 100644
--- a/src/libexpr-c/package.nix
+++ b/src/libexpr-c/package.nix
@@ -15,7 +15,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-expr-c";
+ pname = "determinate-nix-expr-c";
inherit version;
workDir = ./.;
diff --git a/src/libexpr-test-support/include/nix/expr/tests/value/context.hh b/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
index 68a0b8dea7d..2311f3941c1 100644
--- a/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
+++ b/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
@@ -26,6 +26,12 @@ struct Arbitrary
static Gen arbitrary();
};
+template<>
+struct Arbitrary
+{
+ static Gen arbitrary();
+};
+
template<>
struct Arbitrary
{
diff --git a/src/libexpr-test-support/package.nix b/src/libexpr-test-support/package.nix
index 5cb4adaa8c4..1879a571608 100644
--- a/src/libexpr-test-support/package.nix
+++ b/src/libexpr-test-support/package.nix
@@ -18,7 +18,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-util-test-support";
+ pname = "determinate-nix-util-test-support";
inherit version;
workDir = ./.;
diff --git a/src/libexpr-test-support/tests/value/context.cc b/src/libexpr-test-support/tests/value/context.cc
index d6036601a94..8ce84fb51f5 100644
--- a/src/libexpr-test-support/tests/value/context.cc
+++ b/src/libexpr-test-support/tests/value/context.cc
@@ -16,6 +16,15 @@ Gen Arbitrary::arb
});
}
+Gen Arbitrary::arbitrary()
+{
+ return gen::map(gen::arbitrary(), [](StorePath storePath) {
+ return NixStringContextElem::Path{
+ .storePath = storePath,
+ };
+ });
+}
+
Gen Arbitrary::arbitrary()
{
return gen::mapcat(
@@ -31,6 +40,8 @@ Gen Arbitrary::arbitrary()
case 2:
return gen::map(
gen::arbitrary(), [](NixStringContextElem a) { return a; });
+ case 3:
+ return gen::map(gen::arbitrary(), [](NixStringContextElem a) { return a; });
default:
assert(false);
}
diff --git a/src/libexpr-tests/value/print.cc b/src/libexpr-tests/value/print.cc
index 7647cd334d7..3b6889692b1 100644
--- a/src/libexpr-tests/value/print.cc
+++ b/src/libexpr-tests/value/print.cc
@@ -10,7 +10,7 @@ using namespace testing;
struct ValuePrintingTests : LibExprTest
{
template
- void test(Value v, std::string_view expected, A... args)
+ void test(Value & v, std::string_view expected, A... args)
{
std::stringstream out;
v.print(state, out, args...);
@@ -625,10 +625,11 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
vThree.mkInt(3);
builder.insert(state.symbols.create("three"), &vThree);
- vAttrs.mkAttrs(builder.finish());
+ Value vAttrs2;
+ vAttrs2.mkAttrs(builder.finish());
test(
- vAttrs,
+ vAttrs2,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«2 attributes elided»" ANSI_NORMAL " }",
PrintOptions{.ansiColors = true, .maxAttrs = 1});
}
diff --git a/src/libexpr-tests/value/value.cc b/src/libexpr-tests/value/value.cc
index 63501dd4995..c6349436fb7 100644
--- a/src/libexpr-tests/value/value.cc
+++ b/src/libexpr-tests/value/value.cc
@@ -11,7 +11,6 @@ TEST_F(ValueTest, unsetValue)
{
Value unsetValue;
ASSERT_EQ(false, unsetValue.isValid());
- ASSERT_EQ(nThunk, unsetValue.type(true));
ASSERT_DEATH(unsetValue.type(), "");
}
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index 292d76e025d..c2e39a2f310 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -552,16 +552,17 @@ string_t AttrCursor::getStringWithContext()
if (auto s = std::get_if(&cachedValue->second)) {
bool valid = true;
for (auto & c : s->second) {
- const StorePath & path = std::visit(
+ const StorePath * path = std::visit(
overloaded{
- [&](const NixStringContextElem::DrvDeep & d) -> const StorePath & { return d.drvPath; },
- [&](const NixStringContextElem::Built & b) -> const StorePath & {
- return b.drvPath->getBaseStorePath();
+ [&](const NixStringContextElem::DrvDeep & d) -> const StorePath * { return &d.drvPath; },
+ [&](const NixStringContextElem::Built & b) -> const StorePath * {
+ return &b.drvPath->getBaseStorePath();
},
- [&](const NixStringContextElem::Opaque & o) -> const StorePath & { return o.path; },
+ [&](const NixStringContextElem::Opaque & o) -> const StorePath * { return &o.path; },
+ [&](const NixStringContextElem::Path & p) -> const StorePath * { return nullptr; },
},
c.raw);
- if (!root->state.store->isValidPath(path)) {
+ if (!path || !root->state.store->isValidPath(*path)) {
valid = false;
break;
}
@@ -709,6 +710,7 @@ StorePath AttrCursor::forceDerivation()
/* The eval cache contains 'drvPath', but the actual path has
been garbage-collected. So force it to be regenerated. */
aDrvPath->forceValue();
+ root->state.waitForPath(drvPath);
if (!root->state.store->isValidPath(drvPath))
throw Error(
"don't know how to recreate store derivation '%s'!", root->state.store->printStorePath(drvPath));
diff --git a/src/libexpr/eval-gc.cc b/src/libexpr/eval-gc.cc
index b17336a901a..c22efe8af65 100644
--- a/src/libexpr/eval-gc.cc
+++ b/src/libexpr/eval-gc.cc
@@ -33,6 +33,88 @@ static void * oomHandler(size_t requested)
throw std::bad_alloc();
}
+static size_t getFreeMem()
+{
+ /* On Linux, use the `MemAvailable` or `MemFree` fields from
+ /proc/cpuinfo. */
+# ifdef __linux__
+ {
+ std::unordered_map fields;
+ for (auto & line :
+ tokenizeString>(readFile(std::filesystem::path("/proc/meminfo")), "\n")) {
+ auto colon = line.find(':');
+ if (colon == line.npos)
+ continue;
+ fields.emplace(line.substr(0, colon), trim(line.substr(colon + 1)));
+ }
+
+ auto i = fields.find("MemAvailable");
+ if (i == fields.end())
+ i = fields.find("MemFree");
+ if (i != fields.end()) {
+ auto kb = tokenizeString>(i->second, " ");
+ if (kb.size() == 2 && kb[1] == "kB")
+ return string2Int(kb[0]).value_or(0) * 1024;
+ }
+ }
+# endif
+
+ /* On non-Linux systems, conservatively assume that 25% of memory is free. */
+ long pageSize = sysconf(_SC_PAGESIZE);
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pageSize > 0 && pages > 0)
+ return (static_cast(pageSize) * static_cast(pages)) / 4;
+ return 0;
+}
+
+/**
+ * When a thread goes into a coroutine, we lose its original sp until
+ * control flow returns to the thread. This causes Boehm GC to crash
+ * since it will scan memory between the coroutine's sp and the
+ * original stack base of the thread. Therefore, we detect when the
+ * current sp is outside of the original thread stack and push the
+ * entire thread stack instead, as an approximation.
+ *
+ * This is not optimal, because it causes the stack below sp to be
+ * scanned. However, we usually we don't have active coroutines during
+ * evaluation, so this is acceptable.
+ *
+ * Note that we don't scan coroutine stacks. It's currently assumed
+ * that we don't have GC roots in coroutines.
+ */
+void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
+{
+ void *& sp = *sp_ptr;
+ auto pthread_id = reinterpret_cast(_pthread_id);
+ size_t osStackSize;
+ char * osStackHi;
+ char * osStackLo;
+
+# ifdef __APPLE__
+ osStackSize = pthread_get_stacksize_np(pthread_id);
+ osStackHi = (char *) pthread_get_stackaddr_np(pthread_id);
+ osStackLo = osStackHi - osStackSize;
+# else
+ pthread_attr_t pattr;
+ if (pthread_attr_init(&pattr))
+ throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
+# ifdef HAVE_PTHREAD_GETATTR_NP
+ if (pthread_getattr_np(pthread_id, &pattr))
+ throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
+# else
+# error "Need `pthread_attr_get_np`"
+# endif
+ if (pthread_attr_getstack(&pattr, (void **) &osStackLo, &osStackSize))
+ throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
+ if (pthread_attr_destroy(&pattr))
+ throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
+ osStackHi = osStackLo + osStackSize;
+# endif
+
+ if (sp >= osStackHi || sp < osStackLo) // sp is outside the os stack
+ sp = osStackLo;
+}
+
static inline void initGCReal()
{
/* Initialise the Boehm garbage collector. */
@@ -63,8 +145,11 @@ static inline void initGCReal()
GC_set_oom_fn(oomHandler);
- /* Set the initial heap size to something fairly big (25% of
- physical RAM, up to a maximum of 384 MiB) so that in most cases
+ GC_set_sp_corrector(&fixupBoehmStackPointer);
+ assert(GC_get_sp_corrector());
+
+ /* Set the initial heap size to something fairly big (80% of
+ free RAM, up to a maximum of 4 GiB) so that in most cases
we don't need to garbage collect at all. (Collection has a
fairly significant overhead.) The heap size can be overridden
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
@@ -75,15 +160,10 @@ static inline void initGCReal()
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
size_t size = 32 * 1024 * 1024;
# if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
- size_t maxSize = 384 * 1024 * 1024;
- long pageSize = sysconf(_SC_PAGESIZE);
- long pages = sysconf(_SC_PHYS_PAGES);
- if (pageSize != -1)
- size = (pageSize * pages) / 4; // 25% of RAM
- if (size > maxSize)
- size = maxSize;
+ size_t maxSize = 4ULL * 1024 * 1024 * 1024;
+ auto free = getFreeMem();
+ size = std::max(size, std::min((size_t) (free * 0.5), maxSize));
# endif
- debug("setting initial heap size to %1% bytes", size);
GC_expand_hp(size);
}
}
diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc
index 93db5aebbdc..c9e271b952f 100644
--- a/src/libexpr/eval-settings.cc
+++ b/src/libexpr/eval-settings.cc
@@ -91,9 +91,19 @@ bool EvalSettings::isPseudoUrl(std::string_view s)
std::string EvalSettings::resolvePseudoUrl(std::string_view url)
{
- if (hasPrefix(url, "channel:"))
- return "https://nixos.org/channels/" + std::string(url.substr(8)) + "/nixexprs.tar.xz";
- else
+ if (hasPrefix(url, "channel:")) {
+ auto realUrl = "https://nixos.org/channels/" + std::string(url.substr(8)) + "/nixexprs.tar.xz";
+ static bool haveWarned = false;
+ warnOnce(
+ haveWarned,
+ "Channels are deprecated in favor of flakes in Determinate Nix. "
+ "Instead of '%s', use '%s'. "
+ "See https://zero-to-nix.com for a guide to Nix flakes. "
+ "For details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.",
+ url,
+ realUrl);
+ return realUrl;
+ } else
return std::string(url);
}
@@ -108,4 +118,4 @@ Path getNixDefExpr()
return settings.useXDGBaseDirectories ? getStateDir() + "/defexpr" : getHome() + "/.nix-defexpr";
}
-} // namespace nix
\ No newline at end of file
+} // namespace nix
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index f0b19994661..cf5c3df6fc5 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -17,11 +17,14 @@
#include "nix/expr/print.hh"
#include "nix/fetchers/filtering-source-accessor.hh"
#include "nix/util/memory-source-accessor.hh"
+#include "nix/util/mounted-source-accessor.hh"
#include "nix/expr/gc-small-vector.hh"
#include "nix/util/url.hh"
#include "nix/fetchers/fetch-to-store.hh"
#include "nix/fetchers/tarball.hh"
#include "nix/fetchers/input-cache.hh"
+#include "nix/store/async-path-writer.hh"
+#include "nix/expr/parallel-eval.hh"
#include "parser-tab.hh"
@@ -37,6 +40,7 @@
#include
#include
+#include
#ifndef _WIN32 // TODO use portable implementation
# include
@@ -127,6 +131,8 @@ std::string_view showType(ValueType type, bool withArticle)
return WA("a", "float");
case nThunk:
return WA("a", "thunk");
+ case nFailed:
+ return WA("a", "failure");
}
unreachable();
}
@@ -173,12 +179,25 @@ PosIdx Value::determinePos(const PosIdx pos) const
#pragma GCC diagnostic pop
}
-bool Value::isTrivial() const
+template<>
+bool ValueStorage::isTrivial() const
{
- return !isa()
- && (!isa()
- || (dynamic_cast(thunk().expr) && ((ExprAttrs *) thunk().expr)->dynamicAttrs.empty())
- || dynamic_cast(thunk().expr) || dynamic_cast(thunk().expr));
+ auto p1_ = p1; // must acquire before reading p0, since thunks can change
+ auto p0_ = p0.load(std::memory_order_acquire);
+
+ auto pd = static_cast(p0_ & discriminatorMask);
+
+ if (pd == pdThunk || pd == pdPending || pd == pdAwaited) {
+ bool isApp = p1_ & discriminatorMask;
+ if (isApp)
+ return false;
+ auto expr = untagPointer(p1_);
+ return (dynamic_cast(expr) && ((ExprAttrs *) expr)->dynamicAttrs.empty())
+ || dynamic_cast(expr) || dynamic_cast(expr);
+ }
+
+ else
+ return true;
}
static Symbol getName(const AttrName & name, EvalState & state, Env & env)
@@ -195,6 +214,27 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
static constexpr size_t BASE_ENV_SIZE = 128;
+struct EvalState::SrcToStore
+{
+ boost::concurrent_flat_map inner;
+};
+
+struct EvalState::ImportResolutionCache
+{
+ boost::concurrent_flat_map inner;
+};
+
+struct EvalState::FileEvalCache
+{
+ boost::concurrent_flat_map<
+ SourcePath,
+ Value *,
+ std::hash,
+ std::equal_to,
+ traceable_allocator>>
+ inner;
+};
+
EvalState::EvalState(
const LookupPath & lookupPathFromArguments,
ref store,
@@ -203,6 +243,7 @@ EvalState::EvalState(
std::shared_ptr buildStore)
: fetchSettings{fetchSettings}
, settings{settings}
+ , executor{make_ref(settings)}
, sWith(symbols.create(""))
, sOutPath(symbols.create("outPath"))
, sDrvPath(symbols.create("drvPath"))
@@ -281,7 +322,7 @@ EvalState::EvalState(
exception, and make union source accessor
catch it, so we don't need to do this hack.
*/
- {CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
+ {CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))}
}))
, rootFS(
({
@@ -296,12 +337,9 @@ EvalState::EvalState(
/nix/store while using a chroot store. */
auto accessor = getFSSourceAccessor();
- auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
- if (settings.pureEval || store->storeDir != realStoreDir) {
- accessor = settings.pureEval
- ? storeFS
- : makeUnionSourceAccessor({accessor, storeFS});
- }
+ accessor = settings.pureEval
+ ? storeFS.cast()
+ : makeUnionSourceAccessor({accessor, storeFS});
/* Apply access control if needed. */
if (settings.restrictEval || settings.pureEval)
@@ -327,10 +365,12 @@ EvalState::EvalState(
, debugRepl(nullptr)
, debugStop(false)
, trylevel(0)
+ , asyncPathWriter(AsyncPathWriter::make(store))
+ , srcToStore(make_ref())
+ , importResolutionCache(make_ref())
+ , fileEvalCache(make_ref())
, regexCache(makeRegexCache())
#if NIX_USE_BOEHMGC
- , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr))
- , env1AllocCache(std::allocate_shared(traceable_allocator(), nullptr))
, baseEnvP(std::allocate_shared(traceable_allocator(), &allocEnv(BASE_ENV_SIZE)))
, baseEnv(**baseEnvP)
#else
@@ -346,6 +386,7 @@ EvalState::EvalState(
assertGCInitialized();
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
+ static_assert(sizeof(Counter) == 64, "counters must be 64 bytes");
vEmptyList.mkList(buildList(0));
vNull.mkNull();
@@ -487,7 +528,8 @@ void EvalState::checkURI(const std::string & uri)
Value * EvalState::addConstant(const std::string & name, Value & v, Constant info)
{
Value * v2 = allocValue();
- *v2 = v;
+ // Do a raw copy since `operator =` barfs on thunks.
+ memcpy((char *) v2, (char *) &v, sizeof(Value));
addConstant(name, v2, info);
return v2;
}
@@ -503,8 +545,10 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info)
We might know the type of a thunk in advance, so be allowed
to just write it down in that case. */
- if (auto gotType = v->type(true); gotType != nThunk)
- assert(info.type == gotType);
+ if (v->isFinished()) {
+ if (auto gotType = v->type(); gotType != nThunk)
+ assert(info.type == gotType);
+ }
/* Install value the base environment. */
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
@@ -686,7 +730,7 @@ void printStaticEnvBindings(const SymbolTable & st, const StaticEnv & se)
// just for the current level of Env, not the whole chain.
void printWithBindings(const SymbolTable & st, const Env & env)
{
- if (!env.values[0]->isThunk()) {
+ if (env.values[0]->isFinished()) {
std::cout << "with: ";
std::cout << ANSI_MAGENTA;
auto j = env.values[0]->attrs()->begin();
@@ -741,7 +785,7 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En
if (env.up && se.up) {
mapStaticEnvBindings(st, *se.up, *env.up, vm);
- if (se.isWith && !env.values[0]->isThunk()) {
+ if (se.isWith && env.values[0]->isFinished()) {
// add 'with' bindings.
for (auto & j : *env.values[0]->attrs())
vm.insert_or_assign(std::string(st[j.name]), j.value);
@@ -960,7 +1004,7 @@ Value * EvalState::getBool(bool b)
return b ? &vTrue : &vFalse;
}
-unsigned long nrThunks = 0;
+static Counter nrThunks;
static inline void mkThunk(Value & v, Env & env, Expr * expr)
{
@@ -978,7 +1022,13 @@ void EvalState::mkPos(Value & v, PosIdx p)
auto origin = positions.originOf(p);
if (auto path = std::get_if(&origin)) {
auto attrs = buildBindings(3);
- attrs.alloc(sFile).mkString(path->path.abs());
+ if (path->accessor == rootFS && store->isInStore(path->path.abs()))
+ // FIXME: only do this for virtual store paths?
+ attrs.alloc(sFile).mkString(
+ path->path.abs(),
+ {NixStringContextElem::Path{.storePath = store->toStorePath(path->path.abs()).first}});
+ else
+ attrs.alloc(sFile).mkString(path->path.abs());
makePositionThunks(*this, p, attrs.alloc(sLine), attrs.alloc(sColumn));
v.mkAttrs(attrs);
} else
@@ -1025,6 +1075,7 @@ std::string EvalState::mkSingleDerivedPathStringRaw(const SingleDerivedPath & p)
auto optStaticOutputPath = std::visit(
overloaded{
[&](const SingleDerivedPath::Opaque & o) {
+ waitForPath(o.path);
auto drv = store->readDerivation(o.path);
auto i = drv.outputs.find(b.output);
if (i == drv.outputs.end())
@@ -1098,61 +1149,84 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
return &v;
}
-void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
+/**
+ * A helper `Expr` class to lets us parse and evaluate Nix expressions
+ * from a thunk, ensuring that every file is parsed/evaluated only
+ * once (via the thunk stored in `EvalState::fileEvalCache`).
+ */
+struct ExprParseFile : Expr
{
- FileEvalCache::iterator i;
- if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
- v = i->second;
- return;
- }
+ SourcePath & path;
+ bool mustBeTrivial;
- auto resolvedPath = resolveExprPath(path);
- if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) {
- v = i->second;
- return;
+ ExprParseFile(SourcePath & path, bool mustBeTrivial)
+ : path(path)
+ , mustBeTrivial(mustBeTrivial)
+ {
}
- printTalkative("evaluating file '%1%'", resolvedPath);
- Expr * e = nullptr;
+ void eval(EvalState & state, Env & env, Value & v) override
+ {
+ printTalkative("evaluating file '%s'", path);
+
+ auto e = state.parseExprFromFile(path);
- auto j = fileParseCache.find(resolvedPath);
- if (j != fileParseCache.end())
- e = j->second;
+ try {
+ auto dts =
+ state.debugRepl
+ ? makeDebugTraceStacker(
+ state, *e, state.baseEnv, e->getPos(), "while evaluating the file '%s':", path.to_string())
+ : nullptr;
+
+ // Enforce that 'flake.nix' is a direct attrset, not a
+ // computation.
+ if (mustBeTrivial && !(dynamic_cast(e)))
+ state.error("file '%s' must be an attribute set", path).debugThrow();
+
+ state.eval(e, v);
+ } catch (Error & e) {
+ state.addErrorTrace(e, "while evaluating the file '%s':", path.to_string());
+ throw;
+ }
+ }
+};
- if (!e)
- e = parseExprFromFile(resolvedPath);
+void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
+{
+ auto resolvedPath = getConcurrent(importResolutionCache->inner, path);
- fileParseCache.emplace(resolvedPath, e);
+ if (!resolvedPath) {
+ resolvedPath = resolveExprPath(path);
+ importResolutionCache->inner.emplace(path, *resolvedPath);
+ }
- try {
- auto dts = debugRepl ? makeDebugTraceStacker(
- *this,
- *e,
- this->baseEnv,
- e->getPos(),
- "while evaluating the file '%1%':",
- resolvedPath.to_string())
- : nullptr;
-
- // Enforce that 'flake.nix' is a direct attrset, not a
- // computation.
- if (mustBeTrivial && !(dynamic_cast(e)))
- error("file '%s' must be an attribute set", path).debugThrow();
- eval(e, v);
- } catch (Error & e) {
- addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
- throw;
+ if (auto v2 = getConcurrent(fileEvalCache->inner, *resolvedPath)) {
+ forceValue(**v2, noPos);
+ v = **v2;
+ return;
}
- fileEvalCache.emplace(resolvedPath, v);
- if (path != resolvedPath)
- fileEvalCache.emplace(path, v);
+ Value * vExpr;
+ ExprParseFile expr{*resolvedPath, mustBeTrivial};
+
+ fileEvalCache->inner.try_emplace_and_cvisit(
+ *resolvedPath,
+ nullptr,
+ [&](auto & i) {
+ vExpr = allocValue();
+ vExpr->mkThunk(&baseEnv, &expr);
+ i.second = vExpr;
+ },
+ [&](auto & i) { vExpr = i.second; });
+
+ forceValue(*vExpr, noPos);
+
+ v = *vExpr;
}
void EvalState::resetFileCache()
{
- fileEvalCache.clear();
- fileParseCache.clear();
+ fileEvalCache->inner.clear();
inputCache->clear();
}
@@ -1444,7 +1518,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
state.attrSelects[pos2]++;
}
- state.forceValue(*vAttrs, (pos2 ? pos2 : this->pos));
+ state.forceValue(*vAttrs, pos2 ? pos2 : this->pos);
} catch (Error & e) {
if (pos2) {
@@ -1503,6 +1577,8 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v)
v.mkLambda(&env, this);
}
+thread_local size_t EvalState::callDepth = 0;
+
void EvalState::callFunction(Value & fun, std::span args, Value & vRes, const PosIdx pos)
{
auto _level = addCallDepth(pos);
@@ -1518,15 +1594,16 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
forceValue(fun, pos);
- Value vCur(fun);
+ Value vCur = fun;
auto makeAppChain = [&]() {
- vRes = vCur;
for (auto arg : args) {
auto fun2 = allocValue();
- *fun2 = vRes;
- vRes.mkPrimOpApp(fun2, arg);
+ *fun2 = vCur;
+ vCur.reset();
+ vCur.mkPrimOpApp(fun2, arg);
}
+ vRes = vCur;
};
const Attr * functor;
@@ -1622,6 +1699,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
lambda.name ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda")
: nullptr;
+ vCur.reset();
lambda.body->eval(*this, env2, vCur);
} catch (Error & e) {
if (loggerSettings.showTrace.get()) {
@@ -1656,7 +1734,9 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
primOpCalls[fn->name]++;
try {
- fn->fun(*this, vCur.determinePos(noPos), args.data(), vCur);
+ auto pos = vCur.determinePos(noPos);
+ vCur.reset();
+ fn->fun(*this, pos, args.data(), vCur);
} catch (Error & e) {
if (fn->addTrace)
addErrorTrace(e, pos, "while calling the '%1%' builtin", fn->name);
@@ -1678,6 +1758,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
assert(primOp->isPrimOp());
auto arity = primOp->primOp()->arity;
auto argsLeft = arity - argsDone;
+ assert(argsLeft);
if (args.size() < argsLeft) {
/* We still don't have enough arguments, so extend the tPrimOpApp chain. */
@@ -1706,7 +1787,9 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
// 2. Create a fake env (arg1, arg2, etc.) and a fake expr (arg1: arg2: etc: builtins.name arg1 arg2
// etc)
// so the debugger allows to inspect the wrong parameters passed to the builtin.
- fn->fun(*this, vCur.determinePos(noPos), vArgs, vCur);
+ auto pos = vCur.determinePos(noPos);
+ vCur.reset();
+ fn->fun(*this, pos, vArgs, vCur);
} catch (Error & e) {
if (fn->addTrace)
addErrorTrace(e, pos, "while calling the '%1%' builtin", fn->name);
@@ -1723,6 +1806,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes,
heap-allocate a copy and use that instead. */
Value * args2[] = {allocValue(), args[0]};
*args2[0] = vCur;
+ vCur.reset();
try {
callFunction(*functor->value, args2, vCur, functor->pos);
} catch (Error & e) {
@@ -2094,7 +2178,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
else if (firstType == nFloat)
v.mkFloat(nf);
else if (firstType == nPath) {
- if (!context.empty())
+ if (hasContext(context))
state.error("a string that refers to a store path cannot be appended to a path")
.atPos(pos)
.withFrame(env, *this)
@@ -2109,16 +2193,6 @@ void ExprPos::eval(EvalState & state, Env & env, Value & v)
state.mkPos(v, pos);
}
-void ExprBlackHole::eval(EvalState & state, [[maybe_unused]] Env & env, Value & v)
-{
- throwInfiniteRecursionError(state, v);
-}
-
-[[gnu::noinline]] [[noreturn]] void ExprBlackHole::throwInfiniteRecursionError(EvalState & state, Value & v)
-{
- state.error("infinite recursion encountered").atPos(v.determinePos(noPos)).debugThrow();
-}
-
// always force this to be separate, otherwise forceValue may inline it and take
// a massive perf hit
[[gnu::noinline]]
@@ -2151,6 +2225,7 @@ void EvalState::forceValueDeep(Value & v)
for (auto & i : *v.attrs())
try {
// If the value is a thunk, we're evaling. Otherwise no trace necessary.
+ // FIXME: race, thunk might be updated by another thread
auto dts = debugRepl && i.value->isThunk() ? makeDebugTraceStacker(
*this,
*i.value->thunk().expr,
@@ -2298,10 +2373,15 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
{
auto s = forceString(v, pos, errorCtx);
if (v.context()) {
- error(
- "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string_view(), v.context()[0])
- .withTrace(pos, errorCtx)
- .debugThrow();
+ NixStringContext context;
+ copyContext(v, context);
+ if (hasContext(context))
+ error(
+ "the string '%1%' is not allowed to refer to a store path (such as '%2%')",
+ v.string_view(),
+ v.context()[0])
+ .withTrace(pos, errorCtx)
+ .debugThrow();
}
return s;
}
@@ -2356,12 +2436,21 @@ BackedStringView EvalState::coerceToString(
}
if (v.type() == nPath) {
+ // FIXME: instead of copying the path to the store, we could
+ // return a virtual store path that lazily copies the path to
+ // the store in devirtualize().
return !canonicalizePath && !copyToStore
? // FIXME: hack to preserve path literals that end in a
// slash, as in /foo/${x}.
v.pathStr()
- : copyToStore ? store->printStorePath(copyPathToStore(context, v.path()))
- : std::string(v.path().path.abs());
+ : copyToStore ? store->printStorePath(copyPathToStore(context, v.path(), v.determinePos(pos))) : ({
+ auto path = v.path();
+ if (path.accessor == rootFS && store->isInStore(path.path.abs())) {
+ context.insert(
+ NixStringContextElem::Path{.storePath = store->toStorePath(path.path.abs()).first});
+ }
+ std::string(path.path.abs());
+ });
}
if (v.type() == nAttrs) {
@@ -2432,12 +2521,12 @@ BackedStringView EvalState::coerceToString(
.debugThrow();
}
-StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path)
+StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path, PosIdx pos)
{
if (nix::isDerivation(path.path.abs()))
error("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
- auto dstPathCached = get(*srcToStore.lock(), path);
+ auto dstPathCached = getConcurrent(srcToStore->inner, path);
auto dstPath = dstPathCached ? *dstPathCached : [&]() {
auto dstPath = fetchToStore(
@@ -2445,12 +2534,12 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
*store,
path.resolveSymlinks(SymlinkResolution::Ancestors),
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
- path.baseName(),
+ computeBaseName(path, pos),
ContentAddressMethod::Raw::NixArchive,
nullptr,
repair);
allowPath(dstPath);
- srcToStore.lock()->try_emplace(path, dstPath);
+ srcToStore->inner.try_emplace(path, dstPath);
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
return dstPath;
}();
@@ -2497,7 +2586,9 @@ EvalState::coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & con
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (auto storePath = store->maybeParseStorePath(path))
return *storePath;
- error("path '%1%' is not in the Nix store", path).withTrace(pos, errorCtx).debugThrow();
+ error("cannot coerce '%s' to a store path because it is not a subpath of the Nix store", path)
+ .withTrace(pos, errorCtx)
+ .debugThrow();
}
std::pair EvalState::coerceToSingleDerivedPathUnchecked(
@@ -2521,6 +2612,9 @@ std::pair EvalState::coerceToSingleDerivedP
.debugThrow();
},
[&](NixStringContextElem::Built && b) -> SingleDerivedPath { return std::move(b); },
+ [&](NixStringContextElem::Path && p) -> SingleDerivedPath {
+ error("string '%s' has no context", s).withTrace(pos, errorCtx).debugThrow();
+ },
},
((NixStringContextElem &&) *context.begin()).raw);
return {
@@ -2755,8 +2849,11 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
}
return;
- case nThunk: // Must not be left by forceValue
- assert(false);
+ // Cannot be returned by forceValue().
+ case nThunk:
+ case nFailed:
+ unreachable();
+
default: // Note that we pass compiler flags that should make `default:` unreachable.
// Also note that this probably ran after `eqValues`, which implements
// the same logic more efficiently (without having to unwind stacks),
@@ -2848,8 +2945,11 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
// !!!
return v1.fpoint() == v2.fpoint();
- case nThunk: // Must not be left by forceValue
- assert(false);
+ // Cannot be returned by forceValue().
+ case nThunk:
+ case nFailed:
+ unreachable();
+
default: // Note that we pass compiler flags that should make `default:` unreachable.
error("eqValues: cannot compare %1% with %2%", showType(v1), showType(v2))
.withTrace(pos, errorCtx)
@@ -2872,11 +2972,11 @@ bool EvalState::fullGC()
#endif
}
+bool Counter::enabled = getEnv("NIX_SHOW_STATS").value_or("0") != "0";
+
void EvalState::maybePrintStats()
{
- bool showStats = getEnv("NIX_SHOW_STATS").value_or("0") != "0";
-
- if (showStats) {
+ if (Counter::enabled) {
// Make the final heap size more deterministic.
#if NIX_USE_BOEHMGC
if (!fullGC()) {
@@ -2930,18 +3030,18 @@ void EvalState::printStatistics()
#endif
};
topObj["envs"] = {
- {"number", nrEnvs},
- {"elements", nrValuesInEnvs},
+ {"number", nrEnvs.load()},
+ {"elements", nrValuesInEnvs.load()},
{"bytes", bEnvs},
};
- topObj["nrExprs"] = Expr::nrExprs;
+ topObj["nrExprs"] = Expr::nrExprs.load();
topObj["list"] = {
- {"elements", nrListElems},
+ {"elements", nrListElems.load()},
{"bytes", bLists},
- {"concats", nrListConcats},
+ {"concats", nrListConcats.load()},
};
topObj["values"] = {
- {"number", nrValues},
+ {"number", nrValues.load()},
{"bytes", bValues},
};
topObj["symbols"] = {
@@ -2949,9 +3049,9 @@ void EvalState::printStatistics()
{"bytes", symbols.totalSize()},
};
topObj["sets"] = {
- {"number", nrAttrsets},
+ {"number", nrAttrsets.load()},
{"bytes", bAttrsets},
- {"elements", nrAttrsInAttrsets},
+ {"elements", nrAttrsInAttrsets.load()},
};
topObj["sizes"] = {
{"Env", sizeof(Env)},
@@ -2959,13 +3059,18 @@ void EvalState::printStatistics()
{"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;
+ topObj["nrOpUpdates"] = nrOpUpdates.load();
+ topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied.load();
+ topObj["nrThunks"] = nrThunks.load();
+ topObj["nrThunksAwaited"] = nrThunksAwaited.load();
+ topObj["nrThunksAwaitedSlow"] = nrThunksAwaitedSlow.load();
+ topObj["nrSpuriousWakeups"] = nrSpuriousWakeups.load();
+ topObj["maxWaiting"] = maxWaiting.load();
+ topObj["waitingTime"] = microsecondsWaiting / (double) 1000000;
+ topObj["nrAvoided"] = nrAvoided.load();
+ topObj["nrLookups"] = nrLookups.load();
+ topObj["nrPrimOpCalls"] = nrPrimOpCalls.load();
+ topObj["nrFunctionCalls"] = nrFunctionCalls.load();
#if NIX_USE_BOEHMGC
topObj["gc"] = {
{"heapSize", heapSize},
@@ -3013,10 +3118,10 @@ void EvalState::printStatistics()
}
if (getEnv("NIX_SHOW_SYMBOLS").value_or("0") != "0") {
+ auto list = json::array();
+ symbols.dump([&](std::string_view s) { list.emplace_back(std::string(s)); });
// XXX: overrides earlier assignment
- topObj["symbols"] = json::array();
- auto & list = topObj["symbols"];
- symbols.dump([&](std::string_view s) { list.emplace_back(s); });
+ topObj["symbols"] = std::move(list);
}
if (outPath == "-") {
std::cerr << topObj.dump(2) << std::endl;
@@ -3112,6 +3217,11 @@ SourcePath EvalState::findFile(const LookupPath & lookupPath, const std::string_
auto res = (r / CanonPath(suffix)).resolveSymlinks();
if (res.pathExists())
return res;
+
+ // Backward compatibility hack: throw an exception if access
+ // to this path is not allowed.
+ if (auto accessor = res.accessor.dynamic_pointer_cast())
+ accessor->checkAccess(res.path);
}
if (hasPrefix(path, "nix/"))
@@ -3178,6 +3288,11 @@ std::optional EvalState::resolveLookupPathPath(const LookupPath::Pat
if (path.resolveSymlinks().pathExists())
return finish(std::move(path));
else {
+ // Backward compatibility hack: throw an exception if access
+ // to this path is not allowed.
+ if (auto accessor = path.accessor.dynamic_pointer_cast())
+ accessor->checkAccess(path.path);
+
logWarning({.msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value)});
}
}
@@ -3189,10 +3304,10 @@ Expr * EvalState::parse(
char * text, size_t length, Pos::Origin origin, const SourcePath & basePath, std::shared_ptr & staticEnv)
{
DocCommentMap tmpDocComments; // Only used when not origin is not a SourcePath
- DocCommentMap * docComments = &tmpDocComments;
+ auto * docComments = &tmpDocComments;
if (auto sourcePath = std::get_if(&origin)) {
- auto [it, _] = positionToDocComment.try_emplace(*sourcePath);
+ auto [it, _] = positionToDocComment.lock()->try_emplace(*sourcePath);
docComments = &it->second;
}
@@ -3211,8 +3326,10 @@ DocComment EvalState::getDocCommentForPos(PosIdx pos)
if (!path)
return {};
- auto table = positionToDocComment.find(*path);
- if (table == positionToDocComment.end())
+ auto positionToDocComment_ = positionToDocComment.readLock();
+
+ auto table = positionToDocComment_->find(*path);
+ if (table == positionToDocComment_->end())
return {};
auto it = table->second.find(pos);
@@ -3250,4 +3367,24 @@ void forceNoNullByte(std::string_view s, std::function pos)
}
}
+void EvalState::waitForPath(const StorePath & path)
+{
+ asyncPathWriter->waitForPath(path);
+}
+
+void EvalState::waitForPath(const SingleDerivedPath & path)
+{
+ std::visit(
+ overloaded{
+ [&](const DerivedPathOpaque & p) { waitForPath(p.path); },
+ [&](const SingleDerivedPathBuilt & p) { waitForPath(*p.drvPath); },
+ },
+ path.raw());
+}
+
+void EvalState::waitForAllPaths()
+{
+ asyncPathWriter->waitForAllPaths();
+}
+
} // namespace nix
diff --git a/src/libexpr/include/nix/expr/counter.hh b/src/libexpr/include/nix/expr/counter.hh
new file mode 100644
index 00000000000..6dde73d0301
--- /dev/null
+++ b/src/libexpr/include/nix/expr/counter.hh
@@ -0,0 +1,65 @@
+#pragma once
+
+#include
+#include
+
+namespace nix {
+
+// Counters are aligned on cache lines to prevent false sharing.
+struct alignas(64) Counter
+{
+ using value_type = uint64_t;
+
+ std::atomic inner{0};
+
+ static bool enabled;
+
+ Counter() {}
+
+ operator value_type() const noexcept
+ {
+ return inner;
+ }
+
+ void operator=(value_type n) noexcept
+ {
+ inner = n;
+ }
+
+ value_type load() const noexcept
+ {
+ return inner;
+ }
+
+ value_type operator++() noexcept
+ {
+ return enabled ? ++inner : 0;
+ }
+
+ value_type operator++(int) noexcept
+ {
+ return enabled ? inner++ : 0;
+ }
+
+ value_type operator--() noexcept
+ {
+ return enabled ? --inner : 0;
+ }
+
+ value_type operator--(int) noexcept
+ {
+ return enabled ? inner-- : 0;
+ }
+
+ value_type operator+=(value_type n) noexcept
+ {
+ return enabled ? inner += n : 0;
+ }
+
+ value_type operator-=(value_type n) noexcept
+ {
+ return enabled ? inner -= n : 0;
+ }
+};
+
+} // namespace nix
diff --git a/src/libexpr/include/nix/expr/eval-inline.hh b/src/libexpr/include/nix/expr/eval-inline.hh
index 749e51537c4..2668b948edb 100644
--- a/src/libexpr/include/nix/expr/eval-inline.hh
+++ b/src/libexpr/include/nix/expr/eval-inline.hh
@@ -33,6 +33,9 @@ Value * EvalState::allocValue()
GC_malloc_many returns a linked list of objects of the given size, where the first word
of each object is also the pointer to the next object in the list. This also means that we
have to explicitly clear the first word of every object we take. */
+ thread_local static std::shared_ptr valueAllocCache{
+ std::allocate_shared(traceable_allocator(), nullptr)};
+
if (!*valueAllocCache) {
*valueAllocCache = GC_malloc_many(sizeof(Value));
if (!*valueAllocCache)
@@ -63,6 +66,9 @@ Env & EvalState::allocEnv(size_t size)
#if NIX_USE_BOEHMGC
if (size == 1) {
/* see allocValue for explanations. */
+ thread_local static std::shared_ptr env1AllocCache{
+ std::allocate_shared(traceable_allocator(), nullptr)};
+
if (!*env1AllocCache) {
*env1AllocCache = GC_malloc_many(sizeof(Env) + sizeof(Value *));
if (!*env1AllocCache)
@@ -82,27 +88,57 @@ Env & EvalState::allocEnv(size_t size)
return *env;
}
-[[gnu::always_inline]]
-void EvalState::forceValue(Value & v, const PosIdx pos)
+template
+void ValueStorage>>::force(
+ EvalState & state, PosIdx pos)
{
- if (v.isThunk()) {
- Env * env = v.thunk().env;
- assert(env || v.isBlackhole());
- Expr * expr = v.thunk().expr;
+ auto p0_ = p0.load(std::memory_order_acquire);
+
+ auto pd = static_cast(p0_ & discriminatorMask);
+
+ if (pd == pdThunk) {
try {
- v.mkBlackhole();
- // checkInterrupt();
- if (env) [[likely]]
- expr->eval(*this, *env, v);
- else
- ExprBlackHole::throwInfiniteRecursionError(*this, v);
+ // The value we get here is only valid if we can set the
+ // thunk to pending.
+ auto p1_ = p1;
+
+ // Atomically set the thunk to "pending".
+ if (!p0.compare_exchange_strong(p0_, pdPending, std::memory_order_acquire, std::memory_order_acquire)) {
+ pd = static_cast(p0_ & discriminatorMask);
+ if (pd == pdPending || pd == pdAwaited) {
+ // The thunk is already "pending" or "awaited", so
+ // we need to wait for it.
+ p0_ = waitOnThunk(state, pd == pdAwaited);
+ goto done;
+ }
+ assert(pd != pdThunk);
+ // Another thread finished this thunk, no need to wait.
+ goto done;
+ }
+
+ bool isApp = p1_ & discriminatorMask;
+ if (isApp) {
+ auto left = untagPointer(p0_);
+ auto right = untagPointer(p1_);
+ state.callFunction(*left, *right, (Value &) *this, pos);
+ } else {
+ auto env = untagPointer(p0_);
+ auto expr = untagPointer(p1_);
+ expr->eval(state, *env, (Value &) *this);
+ }
} catch (...) {
- v.mkThunk(env, expr);
- tryFixupBlackHolePos(v, pos);
+ state.tryFixupBlackHolePos((Value &) *this, pos);
+ setStorage(new Value::Failed{.ex = std::current_exception()});
throw;
}
- } else if (v.isApp())
- callFunction(*v.app().left, *v.app().right, v, pos);
+ }
+
+ else if (pd == pdPending || pd == pdAwaited)
+ p0_ = waitOnThunk(state, pd == pdAwaited);
+
+done:
+ if (InternalType(p0_ & 0xff) == tFailed)
+ std::rethrow_exception((std::bit_cast(p1))->ex);
}
[[gnu::always_inline]]
diff --git a/src/libexpr/include/nix/expr/eval-settings.hh b/src/libexpr/include/nix/expr/eval-settings.hh
index 4c9db0c736b..bc0cfaebd14 100644
--- a/src/libexpr/include/nix/expr/eval-settings.hh
+++ b/src/libexpr/include/nix/expr/eval-settings.hh
@@ -91,7 +91,7 @@ struct EvalSettings : Config
- `$HOME/.nix-defexpr/channels`
- The [user channel link](@docroot@/command-ref/files/default-nix-expression.md#user-channel-link), pointing to the current state of [channels](@docroot@/command-ref/files/channels.md) for the current user.
+ The user channel link pointing to the current state of channels for the current user.
- `nixpkgs=$NIX_STATE_DIR/profiles/per-user/root/channels/nixpkgs`
@@ -101,7 +101,7 @@ struct EvalSettings : Config
The current state of all channels for the `root` user.
- These files are set up by the [Nix installer](@docroot@/installation/installing-binary.md).
+ These files are set up by the Nix installer.
See [`NIX_STATE_DIR`](@docroot@/command-ref/env-common.md#env-NIX_STATE_DIR) for details on the environment variable.
> **Note**
@@ -142,7 +142,7 @@ struct EvalSettings : Config
R"(
If set to `true`, the Nix evaluator doesn't allow access to any
files outside of
- [`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath),
+ [`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath)
or to URIs outside of
[`allowed-uris`](@docroot@/command-ref/conf-file.md#conf-allowed-uris).
)"};
@@ -271,7 +271,7 @@ struct EvalSettings : Config
"ignore-try",
R"(
If set to true, ignore exceptions inside 'tryEval' calls when evaluating Nix expressions in
- debug mode (using the --debugger flag). By default the debugger pauses on all exceptions.
+ debug mode (using the --debugger flag). By default, the debugger pauses on all exceptions.
)"};
Setting traceVerbose{
@@ -289,7 +289,7 @@ struct EvalSettings : Config
"debugger-on-trace",
R"(
If set to true and the `--debugger` flag is given, the following functions
- enter the debugger like [`builtins.break`](@docroot@/language/builtins.md#builtins-break):
+ enter the debugger like [`builtins.break`](@docroot@/language/builtins.md#builtins-break).
* [`builtins.trace`](@docroot@/language/builtins.md#builtins-trace)
* [`builtins.traceVerbose`](@docroot@/language/builtins.md#builtins-traceVerbose)
@@ -305,7 +305,7 @@ struct EvalSettings : Config
"debugger-on-warn",
R"(
If set to true and the `--debugger` flag is given, [`builtins.warn`](@docroot@/language/builtins.md#builtins-warn)
- will enter the debugger like [`builtins.break`](@docroot@/language/builtins.md#builtins-break).
+ enter the debugger like [`builtins.break`](@docroot@/language/builtins.md#builtins-break).
This is useful for debugging warnings in third-party Nix code.
@@ -319,7 +319,7 @@ struct EvalSettings : Config
R"(
If set to true, [`builtins.warn`](@docroot@/language/builtins.md#builtins-warn) throws an error when logging a warning.
- This will give you a stack trace that leads to the location of the warning.
+ This gives you a stack trace that leads to the location of the warning.
This is useful for finding information about warnings in third-party Nix code when you can not start the interactive debugger, such as when Nix is called from a non-interactive script. See [`debugger-on-warn`](#conf-debugger-on-warn).
@@ -342,6 +342,44 @@ struct EvalSettings : Config
This is useful for improving code readability and making path literals
more explicit.
)"};
+
+ Setting lazyTrees{
+ this,
+ false,
+ "lazy-trees",
+ R"(
+ If set to true, flakes and trees fetched by [`builtins.fetchTree`](@docroot@/language/builtins.md#builtins-fetchTree) are only copied to the Nix store when they're used as a dependency of a derivation. This avoids copying (potentially large) source trees unnecessarily.
+ )"};
+
+ // FIXME: this setting should really be in libflake, but it's
+ // currently needed in mountInput().
+ Setting lazyLocks{
+ this,
+ false,
+ "lazy-locks",
+ R"(
+ If enabled, Nix only includes NAR hashes in lock file entries if they're necessary to lock the input (i.e. when there is no other attribute that allows the content to be verified, like a Git revision).
+ This is not backward compatible with older versions of Nix.
+ If disabled, lock file entries always contain a NAR hash.
+ )"};
+
+ Setting evalCores{
+ this,
+ 1,
+ "eval-cores",
+ R"(
+ The number of threads used to evaluate Nix expressions. This currently affects the following commands:
+
+ * `nix search`
+ * `nix flake check`
+ * `nix flake show`
+ * `nix eval --json`
+ * Any evaluation that uses `builtins.parallel`
+
+ The value `0` causes Nix to use all available CPU cores in the system.
+
+ Note that enabling the debugger (`--debugger`) disables multi-threaded evaluation.
+ )"};
};
/**
@@ -349,4 +387,9 @@ struct EvalSettings : Config
*/
Path getNixDefExpr();
+/**
+ * Stack size for evaluator threads.
+ */
+constexpr size_t evalStackSize = 64 * 1024 * 1024;
+
} // namespace nix
diff --git a/src/libexpr/include/nix/expr/eval.hh b/src/libexpr/include/nix/expr/eval.hh
index d52ccb5457e..9563f53b5db 100644
--- a/src/libexpr/include/nix/expr/eval.hh
+++ b/src/libexpr/include/nix/expr/eval.hh
@@ -16,6 +16,7 @@
#include "nix/expr/search-path.hh"
#include "nix/expr/repl-exit-status.hh"
#include "nix/util/ref.hh"
+#include "nix/expr/counter.hh"
// For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS`
#include "nix/expr/config.hh"
@@ -38,6 +39,7 @@ class Store;
namespace fetchers {
struct Settings;
struct InputCache;
+struct Input;
} // namespace fetchers
struct EvalSettings;
class EvalState;
@@ -45,10 +47,13 @@ class StorePath;
struct SingleDerivedPath;
enum RepairFlag : bool;
struct MemorySourceAccessor;
+struct MountedSourceAccessor;
+struct AsyncPathWriter;
namespace eval_cache {
class EvalCache;
}
+struct Executor;
/**
* Increments a count on construction and decrements on destruction.
@@ -185,7 +190,7 @@ std::ostream & operator<<(std::ostream & os, const ValueType t);
struct RegexCache;
-std::shared_ptr makeRegexCache();
+ref makeRegexCache();
struct DebugTrace
{
@@ -218,6 +223,9 @@ class EvalState : public std::enable_shared_from_this
public:
const fetchers::Settings & fetchSettings;
const EvalSettings & settings;
+
+ ref executor;
+
SymbolTable symbols;
PosTable positions;
@@ -276,7 +284,7 @@ public:
/**
* The accessor corresponding to `store`.
*/
- const ref storeFS;
+ const ref storeFS;
/**
* The accessor for the root filesystem.
@@ -320,6 +328,8 @@ public:
std::list debugTraces;
std::map> exprEnvs;
+ ref asyncPathWriter;
+
const std::shared_ptr getStaticEnv(const Expr & expr) const
{
auto i = exprEnvs.find(&expr);
@@ -361,58 +371,37 @@ private:
/* Cache for calls to addToStore(); maps source paths to the store
paths. */
- Sync> srcToStore;
+ struct SrcToStore;
+ ref srcToStore;
/**
- * A cache from path names to parse trees.
+ * A cache that maps paths to "resolved" paths for importing Nix
+ * expressions, i.e. `/foo` to `/foo/default.nix`.
*/
- typedef std::unordered_map<
- SourcePath,
- Expr *,
- std::hash,
- std::equal_to,
- traceable_allocator>>
- FileParseCache;
- FileParseCache fileParseCache;
+ struct ImportResolutionCache;
+ ref importResolutionCache;
/**
- * A cache from path names to values.
+ * A cache from resolved paths to values.
*/
- typedef std::unordered_map<
- SourcePath,
- Value,
- std::hash,
- std::equal_to,
- traceable_allocator>>
- FileEvalCache;
- FileEvalCache fileEvalCache;
+ struct FileEvalCache;
+ ref fileEvalCache;
/**
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
* Grouped by file.
*/
- std::unordered_map positionToDocComment;
+ SharedSync> positionToDocComment;
LookupPath lookupPath;
+ // FIXME: make thread-safe.
std::map> lookupPathResolved;
/**
* Cache used by prim_match().
*/
- std::shared_ptr regexCache;
-
-#if NIX_USE_BOEHMGC
- /**
- * Allocation cache for GC'd Value objects.
- */
- std::shared_ptr valueAllocCache;
-
- /**
- * Allocation cache for size-1 Env objects.
- */
- std::shared_ptr env1AllocCache;
-#endif
+ ref regexCache;
public:
@@ -472,6 +461,16 @@ public:
void checkURI(const std::string & uri);
+ /**
+ * Mount an input on the Nix store.
+ */
+ StorePath mountInput(
+ fetchers::Input & input,
+ const fetchers::Input & originalInput,
+ ref accessor,
+ bool requireLockable,
+ bool forceNarHash = false);
+
/**
* Parse a Nix expression from the specified file.
*/
@@ -531,7 +530,10 @@ public:
* application, call the function and overwrite `v` with the
* result. Otherwise, this is a no-op.
*/
- inline void forceValue(Value & v, const PosIdx pos);
+ inline void forceValue(Value & v, const PosIdx pos)
+ {
+ v.force(*this, pos);
+ }
void tryFixupBlackHolePos(Value & v, PosIdx pos);
@@ -589,6 +591,12 @@ public:
std::optional tryAttrsToString(
const PosIdx pos, Value & v, NixStringContext & context, bool coerceMore = false, bool copyToStore = true);
+ StorePath devirtualize(const StorePath & path, StringMap * rewrites = nullptr);
+
+ SingleDerivedPath devirtualize(const SingleDerivedPath & path, StringMap * rewrites = nullptr);
+
+ std::string devirtualize(std::string_view s, const NixStringContext & context);
+
/**
* String coercion.
*
@@ -606,7 +614,19 @@ public:
bool copyToStore = true,
bool canonicalizePath = true);
- StorePath copyPathToStore(NixStringContext & context, const SourcePath & path);
+ StorePath copyPathToStore(NixStringContext & context, const SourcePath & path, PosIdx pos);
+
+ /**
+ * Compute the base name for a `SourcePath`. For non-store paths,
+ * this is just `SourcePath::baseName()`. But for store paths, for
+ * backwards compatibility, it needs to be `-source`,
+ * i.e. as if the path were copied to the Nix store. This results
+ * in a "double-copied" store path like
+ * `/nix/store/--source`. We don't need to
+ * materialize /nix/store/-source though. Still, this
+ * requires reading/hashing the path twice.
+ */
+ std::string computeBaseName(const SourcePath & path, PosIdx pos);
/**
* Path coercion.
@@ -749,10 +769,11 @@ private:
std::shared_ptr & staticEnv);
/**
- * Current Nix call stack depth, used with `max-call-depth` setting to throw stack overflow hopefully before we run
- * out of system stack.
+ * Current Nix call stack depth, used with `max-call-depth`
+ * setting to throw stack overflow hopefully before we run out of
+ * system stack.
*/
- size_t callDepth = 0;
+ thread_local static size_t callDepth;
public:
@@ -907,6 +928,10 @@ public:
DocComment getDocCommentForPos(PosIdx pos);
+ void waitForPath(const StorePath & path);
+ void waitForPath(const SingleDerivedPath & path);
+ void waitForAllPaths();
+
private:
/**
@@ -924,22 +949,32 @@ private:
*/
std::string mkSingleDerivedPathStringRaw(const SingleDerivedPath & p);
- unsigned long nrEnvs = 0;
- unsigned long nrValuesInEnvs = 0;
- unsigned long nrValues = 0;
- unsigned long nrListElems = 0;
- unsigned long nrLookups = 0;
- unsigned long nrAttrsets = 0;
- unsigned long nrAttrsInAttrsets = 0;
- unsigned long nrAvoided = 0;
- unsigned long nrOpUpdates = 0;
- unsigned long nrOpUpdateValuesCopied = 0;
- unsigned long nrListConcats = 0;
- unsigned long nrPrimOpCalls = 0;
- unsigned long nrFunctionCalls = 0;
+ Counter nrEnvs;
+ Counter nrValuesInEnvs;
+ Counter nrValues;
+ Counter nrListElems;
+ Counter nrLookups;
+ Counter nrAttrsets;
+ Counter nrAttrsInAttrsets;
+ Counter nrAvoided;
+ Counter nrOpUpdates;
+ Counter nrOpUpdateValuesCopied;
+ Counter nrListConcats;
+ Counter nrPrimOpCalls;
+ Counter nrFunctionCalls;
+public:
+ Counter nrThunksAwaited;
+ Counter nrThunksAwaitedSlow;
+ Counter microsecondsWaiting;
+ Counter currentlyWaiting;
+ Counter maxWaiting;
+ Counter nrSpuriousWakeups;
+
+private:
bool countCalls;
+ // FIXME: make thread-safe.
typedef std::map PrimOpCalls;
PrimOpCalls primOpCalls;
@@ -951,6 +986,7 @@ private:
void incrFunctionCall(ExprLambda * fun);
+ // FIXME: make thread-safe.
typedef std::map AttrSelects;
AttrSelects attrSelects;
diff --git a/src/libexpr/include/nix/expr/meson.build b/src/libexpr/include/nix/expr/meson.build
index 04f8eaf71ea..58881506c91 100644
--- a/src/libexpr/include/nix/expr/meson.build
+++ b/src/libexpr/include/nix/expr/meson.build
@@ -10,6 +10,7 @@ config_pub_h = configure_file(
headers = [ config_pub_h ] + files(
'attr-path.hh',
'attr-set.hh',
+ 'counter.hh',
'eval-cache.hh',
'eval-error.hh',
'eval-gc.hh',
@@ -23,6 +24,7 @@ headers = [ config_pub_h ] + files(
'get-drvs.hh',
'json-to-value.hh',
'nixexpr.hh',
+ 'parallel-eval.hh',
'parser-state.hh',
'primops.hh',
'print-ambiguous.hh',
diff --git a/src/libexpr/include/nix/expr/nixexpr.hh b/src/libexpr/include/nix/expr/nixexpr.hh
index 49bd7a3b659..8c72aa5eaf4 100644
--- a/src/libexpr/include/nix/expr/nixexpr.hh
+++ b/src/libexpr/include/nix/expr/nixexpr.hh
@@ -8,6 +8,7 @@
#include "nix/expr/symbol-table.hh"
#include "nix/expr/eval-error.hh"
#include "nix/util/pos-idx.hh"
+#include "nix/expr/counter.hh"
namespace nix {
@@ -89,7 +90,7 @@ struct Expr
Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
};
- static unsigned long nrExprs;
+ static Counter nrExprs;
Expr()
{
@@ -632,20 +633,6 @@ struct ExprPos : Expr
COMMON_METHODS
};
-/* only used to mark thunks as black holes. */
-struct ExprBlackHole : Expr
-{
- void show(const SymbolTable & symbols, std::ostream & str) const override {}
-
- void eval(EvalState & state, Env & env, Value & v) override;
-
- void bindVars(EvalState & es, const std::shared_ptr & env) override {}
-
- [[noreturn]] static void throwInfiniteRecursionError(EvalState & state, Value & v);
-};
-
-extern ExprBlackHole eBlackHole;
-
/* Static environments are used to map variable names onto (level,
displacement) pairs used to obtain the value of the variable at
runtime. */
diff --git a/src/libexpr/include/nix/expr/parallel-eval.hh b/src/libexpr/include/nix/expr/parallel-eval.hh
new file mode 100644
index 00000000000..4ccb3cfb843
--- /dev/null
+++ b/src/libexpr/include/nix/expr/parallel-eval.hh
@@ -0,0 +1,90 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "nix/util/sync.hh"
+#include "nix/util/logging.hh"
+#include "nix/util/environment-variables.hh"
+#include "nix/util/util.hh"
+#include "nix/util/signals.hh"
+
+#if NIX_USE_BOEHMGC
+# include
+#endif
+
+namespace nix {
+
+struct Executor
+{
+ using work_t = std::function;
+
+ struct Item
+ {
+ std::promise promise;
+ work_t work;
+ };
+
+ struct State
+ {
+ std::multimap queue;
+ std::vector threads;
+ };
+
+ std::atomic_bool quit{false};
+
+ const unsigned int evalCores;
+
+ const bool enabled;
+
+ const std::unique_ptr interruptCallback;
+
+ Sync state_;
+
+ std::condition_variable wakeup;
+
+ static unsigned int getEvalCores(const EvalSettings & evalSettings);
+
+ Executor(const EvalSettings & evalSettings);
+
+ ~Executor();
+
+ void createWorker(State & state);
+
+ void worker();
+
+ std::vector> spawn(std::vector> && items);
+
+ static thread_local bool amWorkerThread;
+};
+
+struct FutureVector
+{
+ Executor & executor;
+
+ struct State
+ {
+ std::vector> futures;
+ };
+
+ Sync state_;
+
+ ~FutureVector();
+
+ // FIXME: add a destructor that cancels/waits for all futures.
+
+ void spawn(std::vector> && work);
+
+ void spawn(uint8_t prioPrefix, Executor::work_t && work)
+ {
+ spawn({{std::move(work), prioPrefix}});
+ }
+
+ void finishAll();
+};
+
+} // namespace nix
diff --git a/src/libexpr/include/nix/expr/print-ambiguous.hh b/src/libexpr/include/nix/expr/print-ambiguous.hh
index c0d811d4b93..e64f7f9bf8d 100644
--- a/src/libexpr/include/nix/expr/print-ambiguous.hh
+++ b/src/libexpr/include/nix/expr/print-ambiguous.hh
@@ -15,7 +15,6 @@ namespace nix {
*
* See: https://github.com/NixOS/nix/issues/9730
*/
-void printAmbiguous(
- Value & v, const SymbolTable & symbols, std::ostream & str, std::set * seen, int depth);
+void printAmbiguous(EvalState & state, Value & v, std::ostream & str, std::set * seen, int depth);
} // namespace nix
diff --git a/src/libexpr/include/nix/expr/symbol-table.hh b/src/libexpr/include/nix/expr/symbol-table.hh
index ec1456e2d45..ff148d335a3 100644
--- a/src/libexpr/include/nix/expr/symbol-table.hh
+++ b/src/libexpr/include/nix/expr/symbol-table.hh
@@ -2,12 +2,13 @@
///@file
#include
+
#include "nix/expr/value.hh"
-#include "nix/util/chunked-vector.hh"
#include "nix/util/error.hh"
+#include "nix/util/sync.hh"
#include
-#include
+#include
namespace nix {
@@ -16,18 +17,28 @@ class SymbolValue : protected Value
friend class SymbolStr;
friend class SymbolTable;
- uint32_t size_;
- uint32_t idx;
-
- SymbolValue() = default;
-
-public:
operator std::string_view() const noexcept
{
- return {c_str(), size_};
+ // The actual string is stored directly after the value.
+ return reinterpret_cast(this + 1);
}
};
+struct ContiguousArena
+{
+ const char * data;
+ const size_t maxSize;
+
+ // Put this in a separate cache line to ensure that a thread
+ // adding a symbol doesn't slow down threads dereferencing symbols
+ // by invalidating the read-only `data` field.
+ alignas(64) std::atomic size{0};
+
+ ContiguousArena(size_t maxSize);
+
+ size_t allocate(size_t bytes);
+};
+
/**
* Symbols have the property that they can be compared efficiently
* (using an equality test), because the symbol table stores only one
@@ -39,6 +50,7 @@ class Symbol
friend class SymbolTable;
private:
+ /// The offset of the symbol in `SymbolTable::arena`.
uint32_t id;
explicit Symbol(uint32_t id) noexcept
@@ -80,25 +92,20 @@ class SymbolStr
{
friend class SymbolTable;
- constexpr static size_t chunkSize{8192};
- using SymbolValueStore = ChunkedVector;
-
const SymbolValue * s;
struct Key
{
using HashType = boost::hash;
- SymbolValueStore & store;
std::string_view s;
std::size_t hash;
- std::pmr::polymorphic_allocator & alloc;
+ ContiguousArena & arena;
- Key(SymbolValueStore & store, std::string_view s, std::pmr::polymorphic_allocator & stringAlloc)
- : store(store)
- , s(s)
+ Key(std::string_view s, ContiguousArena & arena)
+ : s(s)
, hash(HashType{}(s))
- , alloc(stringAlloc)
+ , arena(arena)
{
}
};
@@ -109,26 +116,7 @@ public:
{
}
- SymbolStr(const Key & key)
- {
- auto size = key.s.size();
- if (size >= std::numeric_limits::max()) {
- throw Error("Size of symbol exceeds 4GiB and cannot be stored");
- }
- // for multi-threaded implementations: lock store and allocator here
- const auto & [v, idx] = key.store.add(SymbolValue{});
- if (size == 0) {
- v.mkString("", nullptr);
- } else {
- auto s = key.alloc.allocate(size + 1);
- memcpy(s, key.s.data(), size);
- s[size] = '\0';
- v.mkString(s, nullptr);
- }
- v.size_ = size;
- v.idx = idx;
- this->s = &v;
- }
+ SymbolStr(const Key & key);
bool operator==(std::string_view s2) const noexcept
{
@@ -151,13 +139,13 @@ public:
[[gnu::always_inline]]
bool empty() const noexcept
{
- return s->size_ == 0;
+ return static_cast(*s).empty();
}
[[gnu::always_inline]]
size_t size() const noexcept
{
- return s->size_;
+ return static_cast(*s).size();
}
[[gnu::always_inline]]
@@ -166,11 +154,6 @@ public:
return s;
}
- explicit operator Symbol() const noexcept
- {
- return Symbol{s->idx + 1};
- }
-
struct Hash
{
using is_transparent = void;
@@ -221,58 +204,74 @@ private:
* SymbolTable is an append only data structure.
* During its lifetime the monotonic buffer holds all strings and nodes, if the symbol set is node based.
*/
- std::pmr::monotonic_buffer_resource buffer;
- std::pmr::polymorphic_allocator stringAlloc{&buffer};
- SymbolStr::SymbolValueStore store{16};
+ ContiguousArena arena;
/**
- * Transparent lookup of string view for a pointer to a ChunkedVector entry -> return offset into the store.
- * ChunkedVector references are never invalidated.
+ * Transparent lookup of string view for a pointer to a
+ * SymbolValue in the arena.
*/
- boost::unordered_flat_set symbols{SymbolStr::chunkSize};
+ boost::concurrent_flat_set symbols;
public:
+ constexpr static size_t alignment = alignof(SymbolValue);
+
+ SymbolTable()
+ : arena(1 << 30)
+ {
+ // Reserve symbol ID 0 and ensure alignment of the first allocation.
+ arena.allocate(alignment);
+ }
+
/**
* Converts a string into a symbol.
*/
- Symbol create(std::string_view s)
- {
- // Most symbols are looked up more than once, so we trade off insertion performance
- // for lookup performance.
- // FIXME: make this thread-safe.
- return Symbol(*symbols.insert(SymbolStr::Key{store, s, stringAlloc}).first);
- }
+ Symbol create(std::string_view s);
std::vector resolve(const std::vector & symbols) const
{
std::vector result;
result.reserve(symbols.size());
- for (auto sym : symbols)
+ for (auto & sym : symbols)
result.push_back((*this)[sym]);
return result;
}
SymbolStr operator[](Symbol s) const
{
- uint32_t idx = s.id - uint32_t(1);
- if (idx >= store.size())
- unreachable();
- return store[idx];
+ assert(s.id);
+ // Note: we don't check arena.size here to avoid a dependency
+ // on other threads creating new symbols.
+ return SymbolStr(*reinterpret_cast(arena.data + s.id));
}
- [[gnu::always_inline]]
size_t size() const noexcept
{
- return store.size();
+ return symbols.size();
}
- size_t totalSize() const;
+ size_t totalSize() const
+ {
+ return arena.size;
+ }
template
void dump(T callback) const
{
- store.forEach(callback);
+ std::string_view left{arena.data, arena.size};
+ left = left.substr(alignment);
+ while (true) {
+ if (left.empty())
+ break;
+ left = left.substr(sizeof(Value));
+ auto p = left.find('\0');
+ assert(p != left.npos);
+ auto sym = left.substr(0, p);
+ callback(sym);
+ // skip alignment padding
+ auto n = sym.size() + 1;
+ left = left.substr(n + (n % alignment ? alignment - (n % alignment) : 0));
+ }
}
};
diff --git a/src/libexpr/include/nix/expr/value.hh b/src/libexpr/include/nix/expr/value.hh
index a2833679bef..f69eb8f80ce 100644
--- a/src/libexpr/include/nix/expr/value.hh
+++ b/src/libexpr/include/nix/expr/value.hh
@@ -1,6 +1,7 @@
#pragma once
///@file
+#include
#include
#include
#include
@@ -19,6 +20,19 @@ namespace nix {
struct Value;
class BindingsBuilder;
+static constexpr int discriminatorBits = 3;
+
+enum PrimaryDiscriminator : int {
+ pdSingleDWord = 0,
+ pdThunk = 1,
+ pdPending = 2,
+ pdAwaited = 3,
+ pdPairOfPointers = 4,
+ pdListN = 5, // FIXME: get rid of this by putting the size in the first word
+ pdString = 6,
+ pdPath = 7, // FIXME: get rid of this by ditching the `accessor` field
+};
+
/**
* Internal type discriminator, which is more detailed than `ValueType`, as
* it specifies the exact representation used (for types that have multiple
@@ -29,27 +43,50 @@ class BindingsBuilder;
* This also restricts the number of internal types represented with distinct memory layouts.
*/
typedef enum {
- tUninitialized = 0,
- /* layout: Single/zero field payload */
- tInt = 1,
- tBool,
- tNull,
- tFloat,
- tExternal,
- tPrimOp,
- tAttrs,
- /* layout: Pair of pointers payload */
- tListSmall,
- tPrimOpApp,
- tApp,
- tThunk,
- tLambda,
- /* layout: Single untaggable field */
- tListN,
- tString,
- tPath,
+ /* Values that have more type bits in the first word, and the
+ payload (a single word) in the second word. */
+ tUninitialized = PrimaryDiscriminator::pdSingleDWord | (0 << discriminatorBits),
+ tInt = PrimaryDiscriminator::pdSingleDWord | (1 << discriminatorBits),
+ tFloat = PrimaryDiscriminator::pdSingleDWord | (2 << discriminatorBits),
+ tBool = PrimaryDiscriminator::pdSingleDWord | (3 << discriminatorBits),
+ tNull = PrimaryDiscriminator::pdSingleDWord | (4 << discriminatorBits),
+ tAttrs = PrimaryDiscriminator::pdSingleDWord | (5 << discriminatorBits),
+ tPrimOp = PrimaryDiscriminator::pdSingleDWord | (6 << discriminatorBits),
+ tFailed = PrimaryDiscriminator::pdSingleDWord | (7 << discriminatorBits),
+ tExternal = PrimaryDiscriminator::pdSingleDWord | (8 << discriminatorBits),
+
+ /* Thunks. */
+ tThunk = PrimaryDiscriminator::pdThunk | (0 << discriminatorBits),
+ tApp = PrimaryDiscriminator::pdThunk | (1 << discriminatorBits),
+
+ tPending = PrimaryDiscriminator::pdPending,
+ tAwaited = PrimaryDiscriminator::pdAwaited,
+
+ /* Values that consist of two pointers. The second word contains
+ more type bits in its alignment niche. */
+ tListSmall = PrimaryDiscriminator::pdPairOfPointers | (0 << discriminatorBits),
+ tPrimOpApp = PrimaryDiscriminator::pdPairOfPointers | (1 << discriminatorBits),
+ tLambda = PrimaryDiscriminator::pdPairOfPointers | (2 << discriminatorBits),
+
+ /* Special values. */
+ tListN = PrimaryDiscriminator::pdListN,
+ tString = PrimaryDiscriminator::pdString,
+ tPath = PrimaryDiscriminator::pdPath,
} InternalType;
+/**
+ * Return true if `type` denotes a "finished" value, i.e. a weak-head
+ * normal form.
+ *
+ * Note that tPrimOpApp is considered "finished" because it represents
+ * a primop call with an incomplete number of arguments, and therefore
+ * cannot be evaluated further.
+ */
+inline bool isFinished(InternalType t)
+{
+ return t != tUninitialized && t != tThunk && t != tApp && t != tPending && t != tAwaited;
+}
+
/**
* This type abstracts over all actual value types in the language,
* grouping together implementation details like tList*, different function
@@ -57,6 +94,7 @@ typedef enum {
*/
typedef enum {
nThunk,
+ nFailed,
nInt,
nFloat,
nBool,
@@ -73,7 +111,6 @@ class Bindings;
struct Env;
struct Expr;
struct ExprLambda;
-struct ExprBlackHole;
struct PrimOp;
class Symbol;
class SymbolStr;
@@ -189,7 +226,7 @@ namespace detail {
/**
* Implementation mixin class for defining the public types
- * In can be inherited from by the actual ValueStorage implementations
+ * In can be inherited by the actual ValueStorage implementations
* for free due to Empty Base Class Optimization (EBCO).
*/
struct ValueBase
@@ -265,6 +302,11 @@ struct ValueBase
size_t size;
Value * const * elems;
};
+
+ struct Failed : gc
+ {
+ std::exception_ptr ex;
+ };
};
template
@@ -291,6 +333,7 @@ struct PayloadTypeToInternalType
MACRO(PrimOp *, primOp, tPrimOp) \
MACRO(ValueBase::PrimOpApplicationThunk, primOpApp, tPrimOpApp) \
MACRO(ExternalValueBase *, external, tExternal) \
+ MACRO(ValueBase::Failed *, failed, tFailed) \
MACRO(NixFloat, fpoint, tFloat)
#define NIX_VALUE_PAYLOAD_TYPE(T, FIELD_NAME, DISCRIMINATOR) \
@@ -393,12 +436,44 @@ class ValueStorage::type;
- using Payload = std::array;
- Payload payload = {};
- static constexpr int discriminatorBits = 3;
+ /**
+ * For multithreaded evaluation, we have to make sure that thunks/apps
+ * (the only mutable types of values) are updated in a safe way. A
+ * value can have the following states (see `force()`):
+ *
+ * * "thunk"/"app". When forced, this value transitions to
+ * "pending". The current thread will evaluate the
+ * thunk/app. When done, it will override the value with the
+ * result. If the value is at that point in the "awaited" state,
+ * the thread will wake up any waiting threads.
+ *
+ * * "pending". This means it's currently being evaluated. If
+ * another thread forces this value, it transitions to "awaited"
+ * and the thread will wait for the value to be updated (see
+ * `waitOnThunk()`).
+ *
+ * * "awaited". Like pending, only it means that there already are
+ * one or more threads waiting for this thunk.
+ *
+ * To ensure race-free access, the non-atomic word `p1` must
+ * always be updated before `p0`. Writes to `p0` should use
+ * *release* semantics (so that `p1` and any referenced values become
+ * visible to threads that read `p0`), and reads from `p0` should
+ * use `*acquire* semantics.
+ *
+ * Note: at some point, we may want to switch to 128-bit atomics
+ * so that `p0` and `p1` can be updated together
+ * atomically. However, 128-bit atomics are a bit problematic at
+ * present on x86_64 (see
+ * e.g. https://ibraheem.ca/posts/128-bit-atomics/).
+ */
+ std::atomic p0{0};
+ PackedPointer p1{0};
+
static constexpr PackedPointer discriminatorMask = (PackedPointer(1) << discriminatorBits) - 1;
+ // FIXME: move/update
/**
* The value is stored as a pair of 8-byte double words. All pointers are assumed
* to be 8-byte aligned. This gives us at most 6 bits of discriminator bits
@@ -428,15 +503,6 @@ class ValueStorage
requires std::is_pointer_v
@@ -447,7 +513,7 @@ class ValueStorage(payload[0] & discriminatorMask);
+ return static_cast(p0 & discriminatorMask);
}
static void assertAligned(PackedPointer val) noexcept
@@ -455,13 +521,30 @@ class ValueStorage(p0_ & discriminatorMask);
+ if (pd == pdPending)
+ // Nothing to do; no thread is waiting on this thunk.
+ ;
+ else if (pd == pdAwaited)
+ // Slow path: wake up the threads that are waiting on this
+ // thunk.
+ notifyWaiters();
+ else if (pd == pdThunk)
+ unreachable();
+ }
+
template
void setSingleDWordPayload(PackedPointer untaggedVal) noexcept
{
- /* There's plenty of free upper bits in the first dword, which is
- used only for the discriminator. */
- payload[0] = static_cast(pdSingleDWord) | (static_cast(type) << discriminatorBits);
- payload[1] = untaggedVal;
+ /* There's plenty of free upper bits in the first byte, which
+ is used only for the discriminator. */
+ finish(static_cast(type), untaggedVal);
}
template
@@ -470,32 +553,42 @@ class ValueStorage= pdListN && discriminator <= pdPath);
auto firstFieldPayload = std::bit_cast(firstPtrField);
assertAligned(firstFieldPayload);
- payload[0] = static_cast(discriminator) | firstFieldPayload;
- payload[1] = std::bit_cast(untaggableField);
+ finish(static_cast(discriminator) | firstFieldPayload, std::bit_cast(untaggableField));
}
template
void setPairOfPointersPayload(T * firstPtrField, U * secondPtrField) noexcept
{
static_assert(type >= tListSmall && type <= tLambda);
- {
- auto firstFieldPayload = std::bit_cast(firstPtrField);
- assertAligned(firstFieldPayload);
- payload[0] = static_cast(pdPairOfPointers) | firstFieldPayload;
- }
- {
- auto secondFieldPayload = std::bit_cast(secondPtrField);
- assertAligned(secondFieldPayload);
- payload[1] = (type - tListSmall) | secondFieldPayload;
- }
+ auto firstFieldPayload = std::bit_cast(firstPtrField);
+ assertAligned(firstFieldPayload);
+ auto secondFieldPayload = std::bit_cast(secondPtrField);
+ assertAligned(secondFieldPayload);
+ finish(
+ static_cast(pdPairOfPointers) | firstFieldPayload,
+ ((type - tListSmall) >> discriminatorBits) | secondFieldPayload);
+ }
+
+ template
+ void setThunkPayload(T * firstPtrField, U * secondPtrField) noexcept
+ {
+ static_assert(type >= tThunk && type <= tApp);
+ auto secondFieldPayload = std::bit_cast(secondPtrField);
+ assertAligned(secondFieldPayload);
+ p1 = ((type - tThunk) >> discriminatorBits) | secondFieldPayload;
+ auto firstFieldPayload = std::bit_cast(firstPtrField);
+ assertAligned(firstFieldPayload);
+ // Note: awaited values can never become a thunk, so no need
+ // to check for waiters.
+ p0.store(static_cast(pdThunk) | firstFieldPayload, std::memory_order_release);
}
template
requires std::is_pointer_v && std::is_pointer_v
void getPairOfPointersPayload(T & firstPtrField, U & secondPtrField) const noexcept
{
- firstPtrField = untagPointer(payload[0]);
- secondPtrField = untagPointer(payload[1]);
+ firstPtrField = untagPointer(p0);
+ secondPtrField = untagPointer(p1);
}
protected:
@@ -503,42 +596,45 @@ protected:
InternalType getInternalType() const noexcept
{
switch (auto pd = getPrimaryDiscriminator()) {
- case pdUninitialized:
- /* Discriminator value of zero is used to distinguish uninitialized values. */
- return tUninitialized;
case pdSingleDWord:
- /* Payloads that only use up a single double word store the InternalType
- in the upper bits of the first double word. */
- return InternalType(payload[0] >> discriminatorBits);
+ /* Payloads that only use up a single double word store
+ the full InternalType in the first byte. */
+ return InternalType(p0 & 0xff);
+ case pdThunk:
+ return static_cast(tThunk + ((p1 & discriminatorMask) << discriminatorBits));
+ case pdPending:
+ return tPending;
+ case pdAwaited:
+ return tAwaited;
+ case pdPairOfPointers:
+ return static_cast(tListSmall + ((p1 & discriminatorMask) << discriminatorBits));
/* The order must match that of the enumerations defined in InternalType. */
case pdListN:
case pdString:
case pdPath:
return static_cast