forked from lix-project/lix
Merge remote-tracking branch 'origin/master' into best-effort-supplementary-groups
This commit is contained in:
commit
25b20b4ad2
|
@ -11,6 +11,10 @@ assignees: ''
|
||||||
|
|
||||||
<!-- describe your problem -->
|
<!-- describe your problem -->
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
<!-- propose a solution -->
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
<!-- make sure this issue is not redundant or obsolete -->
|
<!-- make sure this issue is not redundant or obsolete -->
|
||||||
|
@ -22,10 +26,6 @@ assignees: ''
|
||||||
[source]: https://github.com/NixOS/nix/tree/master/doc/manual/src
|
[source]: https://github.com/NixOS/nix/tree/master/doc/manual/src
|
||||||
[open documentation issues and pull requests]: https://github.com/NixOS/nix/labels/documentation
|
[open documentation issues and pull requests]: https://github.com/NixOS/nix/labels/documentation
|
||||||
|
|
||||||
## Proposal
|
|
||||||
|
|
||||||
<!-- propose a solution -->
|
|
||||||
|
|
||||||
## Priorities
|
## Priorities
|
||||||
|
|
||||||
Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
|
Add :+1: to [issues you find important](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc).
|
||||||
|
|
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
|
@ -16,7 +16,7 @@
|
||||||
"new-cli":
|
"new-cli":
|
||||||
- src/nix/**/*
|
- src/nix/**/*
|
||||||
|
|
||||||
"tests":
|
"with-tests":
|
||||||
# Unit tests
|
# Unit tests
|
||||||
- src/*/tests/**/*
|
- src/*/tests/**/*
|
||||||
# Functional and integration tests
|
# Functional and integration tests
|
||||||
|
|
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
# should be kept in sync with `version`
|
# should be kept in sync with `version`
|
||||||
uses: zeebe-io/backport-action@v1.2.0
|
uses: zeebe-io/backport-action@v1.3.1
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
|
@ -11,6 +11,7 @@ jobs:
|
||||||
tests:
|
tests:
|
||||||
needs: [check_secrets]
|
needs: [check_secrets]
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
@ -19,7 +20,10 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v22
|
||||||
|
with:
|
||||||
|
# The sandbox would otherwise be disabled by default on Darwin
|
||||||
|
extra_nix_config: "sandbox = true"
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/cachix-action@v12
|
- uses: cachix/cachix-action@v12
|
||||||
if: needs.check_secrets.outputs.cachix == 'true'
|
if: needs.check_secrets.outputs.cachix == 'true'
|
||||||
|
@ -58,7 +62,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v22
|
||||||
with:
|
with:
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||||
- uses: cachix/cachix-action@v12
|
- uses: cachix/cachix-action@v12
|
||||||
|
@ -73,13 +77,14 @@ jobs:
|
||||||
needs: [installer, check_secrets]
|
needs: [installer, check_secrets]
|
||||||
if: github.event_name == 'push' && needs.check_secrets.outputs.cachix == 'true'
|
if: github.event_name == 'push' && needs.check_secrets.outputs.cachix == 'true'
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v22
|
||||||
with:
|
with:
|
||||||
install_url: '${{needs.installer.outputs.installerURL}}'
|
install_url: '${{needs.installer.outputs.installerURL}}'
|
||||||
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
||||||
|
@ -106,7 +111,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v22
|
||||||
with:
|
with:
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -18,7 +18,7 @@ perl/Makefile.config
|
||||||
/doc/manual/generated/*
|
/doc/manual/generated/*
|
||||||
/doc/manual/nix.json
|
/doc/manual/nix.json
|
||||||
/doc/manual/conf-file.json
|
/doc/manual/conf-file.json
|
||||||
/doc/manual/builtins.json
|
/doc/manual/language.json
|
||||||
/doc/manual/xp-features.json
|
/doc/manual/xp-features.json
|
||||||
/doc/manual/src/SUMMARY.md
|
/doc/manual/src/SUMMARY.md
|
||||||
/doc/manual/src/command-ref/new-cli
|
/doc/manual/src/command-ref/new-cli
|
||||||
|
@ -26,6 +26,7 @@ perl/Makefile.config
|
||||||
/doc/manual/src/command-ref/experimental-features-shortlist.md
|
/doc/manual/src/command-ref/experimental-features-shortlist.md
|
||||||
/doc/manual/src/contributing/experimental-feature-descriptions.md
|
/doc/manual/src/contributing/experimental-feature-descriptions.md
|
||||||
/doc/manual/src/language/builtins.md
|
/doc/manual/src/language/builtins.md
|
||||||
|
/doc/manual/src/language/builtin-constants.md
|
||||||
|
|
||||||
# /scripts/
|
# /scripts/
|
||||||
/scripts/nix-profile.sh
|
/scripts/nix-profile.sh
|
||||||
|
@ -89,6 +90,7 @@ perl/Makefile.config
|
||||||
/tests/ca/config.nix
|
/tests/ca/config.nix
|
||||||
/tests/dyn-drv/config.nix
|
/tests/dyn-drv/config.nix
|
||||||
/tests/repl-result-out
|
/tests/repl-result-out
|
||||||
|
/tests/test-libstoreconsumer/test-libstoreconsumer
|
||||||
|
|
||||||
# /tests/lang/
|
# /tests/lang/
|
||||||
/tests/lang/*.out
|
/tests/lang/*.out
|
||||||
|
|
|
@ -5,7 +5,6 @@ We appreciate your support.
|
||||||
|
|
||||||
Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved.
|
Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved.
|
||||||
|
|
||||||
|
|
||||||
## Report a bug
|
## Report a bug
|
||||||
|
|
||||||
1. Check on the [GitHub issue tracker](https://github.com/NixOS/nix/issues) if your bug was already reported.
|
1. Check on the [GitHub issue tracker](https://github.com/NixOS/nix/issues) if your bug was already reported.
|
||||||
|
@ -30,6 +29,8 @@ Check out the [security policy](https://github.com/NixOS/nix/security/policy).
|
||||||
You can use [labels](https://github.com/NixOS/nix/labels) to filter for relevant topics.
|
You can use [labels](https://github.com/NixOS/nix/labels) to filter for relevant topics.
|
||||||
|
|
||||||
2. Search for related issues that cover what you're going to work on. It could help to mention there that you will work on the issue.
|
2. Search for related issues that cover what you're going to work on. It could help to mention there that you will work on the issue.
|
||||||
|
|
||||||
|
Issues labeled ["good first issue"](https://github.com/NixOS/nix/labels/good-first-issue) should be relatively easy to fix and are likely to get merged quickly.
|
||||||
Pull requests addressing issues labeled ["idea approved"](https://github.com/NixOS/nix/labels/idea%20approved) are especially welcomed by maintainers and will receive prioritised review.
|
Pull requests addressing issues labeled ["idea approved"](https://github.com/NixOS/nix/labels/idea%20approved) are especially welcomed by maintainers and will receive prioritised review.
|
||||||
|
|
||||||
3. Check the [Nix reference manual](https://nixos.org/manual/nix/unstable/contributing/hacking.html) for information on building Nix and running its tests.
|
3. Check the [Nix reference manual](https://nixos.org/manual/nix/unstable/contributing/hacking.html) for information on building Nix and running its tests.
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -27,6 +27,7 @@ makefiles += \
|
||||||
src/libstore/tests/local.mk \
|
src/libstore/tests/local.mk \
|
||||||
src/libexpr/tests/local.mk \
|
src/libexpr/tests/local.mk \
|
||||||
tests/local.mk \
|
tests/local.mk \
|
||||||
|
tests/test-libstoreconsumer/local.mk \
|
||||||
tests/plugins/local.mk
|
tests/plugins/local.mk
|
||||||
else
|
else
|
||||||
makefiles += \
|
makefiles += \
|
||||||
|
|
29
doc/manual/generate-builtin-constants.nix
Normal file
29
doc/manual/generate-builtin-constants.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
let
|
||||||
|
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||||
|
inherit (import ./utils.nix) optionalString squash;
|
||||||
|
in
|
||||||
|
|
||||||
|
builtinsInfo:
|
||||||
|
let
|
||||||
|
showBuiltin = name: { doc, type, impure-only }:
|
||||||
|
let
|
||||||
|
type' = optionalString (type != null) " (${type})";
|
||||||
|
|
||||||
|
impureNotice = optionalString impure-only ''
|
||||||
|
Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
squash ''
|
||||||
|
<dt id="builtin-constants-${name}">
|
||||||
|
<a href="#builtin-constants-${name}"><code>${name}</code>${type'}</a>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
${doc}
|
||||||
|
|
||||||
|
${impureNotice}
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
|
@ -1,24 +1,28 @@
|
||||||
let
|
let
|
||||||
inherit (builtins) concatStringsSep attrNames;
|
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||||
|
inherit (import ./utils.nix) optionalString squash;
|
||||||
in
|
in
|
||||||
|
|
||||||
builtinsInfo:
|
builtinsInfo:
|
||||||
let
|
let
|
||||||
showBuiltin = name:
|
showBuiltin = name: { doc, args, arity, experimental-feature }:
|
||||||
let
|
let
|
||||||
inherit (builtinsInfo.${name}) doc args;
|
experimentalNotice = optionalString (experimental-feature != null) ''
|
||||||
|
This function is only available if the [${experimental-feature}](@docroot@/contributing/experimental-features.md#xp-feature-${experimental-feature}) experimental feature is enabled.
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
''
|
squash ''
|
||||||
<dt id="builtins-${name}">
|
<dt id="builtins-${name}">
|
||||||
<a href="#builtins-${name}"><code>${name} ${listArgs args}</code></a>
|
<a href="#builtins-${name}"><code>${name} ${listArgs args}</code></a>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
||||||
${doc}
|
${doc}
|
||||||
|
|
||||||
|
${experimentalNotice}
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
'';
|
'';
|
||||||
listArgs = args: concatStringsSep " " (map (s: "<var>${s}</var>") args);
|
listArgs = args: concatStringsSep " " (map (s: "<var>${s}</var>") args);
|
||||||
in
|
in
|
||||||
concatStringsSep "\n" (map showBuiltin (attrNames builtinsInfo))
|
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
||||||
|
|
||||||
|
|
|
@ -128,14 +128,20 @@ $(d)/xp-features.json: $(bindir)/nix
|
||||||
$(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-xp-features > $@.tmp
|
$(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-xp-features > $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
$(d)/src/language/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(bindir)/nix
|
$(d)/src/language/builtins.md: $(d)/language.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(bindir)/nix
|
||||||
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
||||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp;
|
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<)).builtins' >> $@.tmp;
|
||||||
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
$(d)/builtins.json: $(bindir)/nix
|
$(d)/src/language/builtin-constants.md: $(d)/language.json $(d)/generate-builtin-constants.nix $(d)/src/language/builtin-constants-prefix.md $(bindir)/nix
|
||||||
$(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-builtins > $@.tmp
|
@cat doc/manual/src/language/builtin-constants-prefix.md > $@.tmp
|
||||||
|
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtin-constants.nix (builtins.fromJSON (builtins.readFile $<)).constants' >> $@.tmp;
|
||||||
|
@cat doc/manual/src/language/builtin-constants-suffix.md >> $@.tmp
|
||||||
|
@mv $@.tmp $@
|
||||||
|
|
||||||
|
$(d)/language.json: $(bindir)/nix
|
||||||
|
$(trace-gen) $(dummy-env) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-language > $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
# Generate the HTML manual.
|
# Generate the HTML manual.
|
||||||
|
@ -167,7 +173,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli
|
||||||
done
|
done
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md
|
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(d)/src/language/builtin-constants.md
|
||||||
$(trace-gen) \
|
$(trace-gen) \
|
||||||
tmp="$$(mktemp -d)"; \
|
tmp="$$(mktemp -d)"; \
|
||||||
cp -r doc/manual "$$tmp"; \
|
cp -r doc/manual "$$tmp"; \
|
||||||
|
|
|
@ -330,17 +330,31 @@ const redirects = {
|
||||||
"ssec-relnotes-2.0": "release-notes/rl-2.0.html",
|
"ssec-relnotes-2.0": "release-notes/rl-2.0.html",
|
||||||
"ssec-relnotes-2.1": "release-notes/rl-2.1.html",
|
"ssec-relnotes-2.1": "release-notes/rl-2.1.html",
|
||||||
"ssec-relnotes-2.2": "release-notes/rl-2.2.html",
|
"ssec-relnotes-2.2": "release-notes/rl-2.2.html",
|
||||||
"ssec-relnotes-2.3": "release-notes/rl-2.3.html"
|
"ssec-relnotes-2.3": "release-notes/rl-2.3.html",
|
||||||
},
|
},
|
||||||
"language/values.html": {
|
"language/values.html": {
|
||||||
"simple-values": "#primitives",
|
"simple-values": "#primitives",
|
||||||
"lists": "#list",
|
"lists": "#list",
|
||||||
"strings": "#string",
|
"strings": "#string",
|
||||||
"lists": "#list",
|
"lists": "#list",
|
||||||
"attribute-sets": "#attribute-set"
|
"attribute-sets": "#attribute-set",
|
||||||
},
|
},
|
||||||
"installation/installing-binary.html": {
|
"installation/installing-binary.html": {
|
||||||
"uninstalling": "uninstall.html"
|
"linux": "uninstall.html#linux",
|
||||||
|
"macos": "uninstall.html#macos",
|
||||||
|
"uninstalling": "uninstall.html",
|
||||||
|
}
|
||||||
|
"contributing/hacking.html": {
|
||||||
|
"nix-with-flakes": "#building-nix-with-flakes",
|
||||||
|
"classic-nix": "#building-nix",
|
||||||
|
"running-tests": "testing.html#running-tests",
|
||||||
|
"unit-tests": "testing.html#unit-tests",
|
||||||
|
"functional-tests": "testing.html#functional-tests",
|
||||||
|
"debugging-failing-functional-tests": "testing.html#debugging-failing-functional-tests",
|
||||||
|
"integration-tests": "testing.html#integration-tests",
|
||||||
|
"installer-tests": "testing.html#installer-tests",
|
||||||
|
"one-time-setup": "testing.html#one-time-setup",
|
||||||
|
"using-the-ci-generated-installer-for-manual-testing": "testing.html#using-the-ci-generated-installer-for-manual-testing",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -97,14 +97,20 @@
|
||||||
- [manifest.json](command-ref/files/manifest.json.md)
|
- [manifest.json](command-ref/files/manifest.json.md)
|
||||||
- [Channels](command-ref/files/channels.md)
|
- [Channels](command-ref/files/channels.md)
|
||||||
- [Default Nix expression](command-ref/files/default-nix-expression.md)
|
- [Default Nix expression](command-ref/files/default-nix-expression.md)
|
||||||
- [Architecture](architecture/architecture.md)
|
- [Architecture and Design](architecture/architecture.md)
|
||||||
|
- [File System Object](architecture/file-system-object.md)
|
||||||
|
- [Protocols](protocols/protocols.md)
|
||||||
|
- [Serving Tarball Flakes](protocols/tarball-fetcher.md)
|
||||||
- [Glossary](glossary.md)
|
- [Glossary](glossary.md)
|
||||||
- [Contributing](contributing/contributing.md)
|
- [Contributing](contributing/contributing.md)
|
||||||
- [Hacking](contributing/hacking.md)
|
- [Hacking](contributing/hacking.md)
|
||||||
|
- [Testing](contributing/testing.md)
|
||||||
- [Experimental Features](contributing/experimental-features.md)
|
- [Experimental Features](contributing/experimental-features.md)
|
||||||
- [CLI guideline](contributing/cli-guideline.md)
|
- [CLI guideline](contributing/cli-guideline.md)
|
||||||
|
- [C++ style guide](contributing/cxx.md)
|
||||||
- [Release Notes](release-notes/release-notes.md)
|
- [Release Notes](release-notes/release-notes.md)
|
||||||
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
||||||
|
- [Release 2.16 (2023-05-31)](release-notes/rl-2.16.md)
|
||||||
- [Release 2.15 (2023-04-11)](release-notes/rl-2.15.md)
|
- [Release 2.15 (2023-04-11)](release-notes/rl-2.15.md)
|
||||||
- [Release 2.14 (2023-02-28)](release-notes/rl-2.14.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.13 (2023-01-17)](release-notes/rl-2.13.md)
|
||||||
|
|
|
@ -48,13 +48,13 @@ If the build passes and is deterministic, Nix will exit with a status
|
||||||
code of 0:
|
code of 0:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A stable
|
$ nix-build ./deterministic.nix --attr stable
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
|
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
|
||||||
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
||||||
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
||||||
|
|
||||||
$ nix-build ./deterministic.nix -A stable --check
|
$ nix-build ./deterministic.nix --attr stable --check
|
||||||
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
||||||
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
||||||
```
|
```
|
||||||
|
@ -63,13 +63,13 @@ If the build is not deterministic, Nix will exit with a status code of
|
||||||
1:
|
1:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A unstable
|
$ nix-build ./deterministic.nix --attr unstable
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
|
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
|
||||||
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
|
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
|
||||||
|
|
||||||
$ nix-build ./deterministic.nix -A unstable --check
|
$ nix-build ./deterministic.nix --attr unstable --check
|
||||||
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
||||||
not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
|
not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
|
||||||
|
@ -89,7 +89,7 @@ Using `--check` with `--keep-failed` will cause Nix to keep the second
|
||||||
build's output in a special, `.check` path:
|
build's output in a special, `.check` path:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A unstable --check --keep-failed
|
$ nix-build ./deterministic.nix --attr unstable --check --keep-failed
|
||||||
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
|
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
|
||||||
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
||||||
|
|
|
@ -38,11 +38,9 @@ contains Nix.
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
> If you are building via the Nix daemon, it is the Nix daemon user
|
> If you are building via the Nix daemon, it is the Nix daemon user account (that is, `root`) that should have SSH access to a user (not necessarily `root`) on the remote machine.
|
||||||
> account (that is, `root`) that should have SSH access to the remote
|
>
|
||||||
> machine. If you can’t or don’t want to configure `root` to be able to
|
> If you can’t or don’t want to configure `root` to be able to access the remote machine, you can use a private Nix store instead by passing e.g. `--store ~/my-nix` when running a Nix command from the local machine.
|
||||||
> access to remote machine, you can use a private Nix store instead by
|
|
||||||
> passing e.g. `--store ~/my-nix`.
|
|
||||||
|
|
||||||
The list of remote machines can be specified on the command line or in
|
The list of remote machines can be specified on the command line or in
|
||||||
the Nix configuration file. The former is convenient for testing. For
|
the Nix configuration file. The former is convenient for testing. For
|
||||||
|
|
|
@ -90,7 +90,7 @@ Then, restart the `nix-daemon`.
|
||||||
Build any derivation, for example:
|
Build any derivation, for example:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -E '(import <nixpkgs> {}).writeText "example" (builtins.toString builtins.currentTime)'
|
$ nix-build --expr '(import <nixpkgs> {}).writeText "example" (builtins.toString builtins.currentTime)'
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
|
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
|
||||||
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
|
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
|
||||||
|
|
|
@ -7,11 +7,11 @@ It should help users understand why Nix behaves as it does, and it should help d
|
||||||
|
|
||||||
Nix consists of [hierarchical layers].
|
Nix consists of [hierarchical layers].
|
||||||
|
|
||||||
[hierarchical layers]: https://en.m.wikipedia.org/wiki/Multitier_architecture#Layers
|
[hierarchical layers]: https://en.wikipedia.org/wiki/Multitier_architecture#Layers
|
||||||
|
|
||||||
The following [concept map] shows its main components (rectangles), the objects they operate on (rounded rectangles), and their interactions (connecting phrases):
|
The following [concept map] shows its main components (rectangles), the objects they operate on (rounded rectangles), and their interactions (connecting phrases):
|
||||||
|
|
||||||
[concept map]: https://en.m.wikipedia.org/wiki/Concept_map
|
[concept map]: https://en.wikipedia.org/wiki/Concept_map
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ The result of a build task can be input to another build task.
|
||||||
The following [data flow diagram] shows a build plan for illustration.
|
The following [data flow diagram] shows a build plan for illustration.
|
||||||
Build inputs used as instructions to a build task are marked accordingly:
|
Build inputs used as instructions to a build task are marked accordingly:
|
||||||
|
|
||||||
[data flow diagram]: https://en.m.wikipedia.org/wiki/Data-flow_diagram
|
[data flow diagram]: https://en.wikipedia.org/wiki/Data-flow_diagram
|
||||||
|
|
||||||
```
|
```
|
||||||
+--------------------------------------------------------------------+
|
+--------------------------------------------------------------------+
|
||||||
|
|
64
doc/manual/src/architecture/file-system-object.md
Normal file
64
doc/manual/src/architecture/file-system-object.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# File System Object
|
||||||
|
|
||||||
|
Nix uses a simplified model of the file system, which consists of file system objects.
|
||||||
|
Every file system object is one of the following:
|
||||||
|
|
||||||
|
- File
|
||||||
|
|
||||||
|
- A possibly empty sequence of bytes for contents
|
||||||
|
- A single boolean representing the [executable](https://en.m.wikipedia.org/wiki/File-system_permissions#Permissions) permission
|
||||||
|
|
||||||
|
- Directory
|
||||||
|
|
||||||
|
Mapping of names to child file system objects
|
||||||
|
|
||||||
|
- [Symbolic link](https://en.m.wikipedia.org/wiki/Symbolic_link)
|
||||||
|
|
||||||
|
An arbitrary string.
|
||||||
|
Nix does not assign any semantics to symbolic links.
|
||||||
|
|
||||||
|
File system objects and their children form a tree.
|
||||||
|
A bare file or symlink can be a root file system object.
|
||||||
|
|
||||||
|
Nix does not encode any other file system notions such as [hard links](https://en.m.wikipedia.org/wiki/Hard_link), [permissions](https://en.m.wikipedia.org/wiki/File-system_permissions), timestamps, or other metadata.
|
||||||
|
|
||||||
|
## Examples of file system objects
|
||||||
|
|
||||||
|
A plain file:
|
||||||
|
|
||||||
|
```
|
||||||
|
50 B, executable: false
|
||||||
|
```
|
||||||
|
|
||||||
|
An executable file:
|
||||||
|
|
||||||
|
```
|
||||||
|
122 KB, executable: true
|
||||||
|
```
|
||||||
|
|
||||||
|
A symlink:
|
||||||
|
|
||||||
|
```
|
||||||
|
-> /usr/bin/sh
|
||||||
|
```
|
||||||
|
|
||||||
|
A directory with contents:
|
||||||
|
|
||||||
|
```
|
||||||
|
├── bin
|
||||||
|
│ └── hello: 35 KB, executable: true
|
||||||
|
└── share
|
||||||
|
├── info
|
||||||
|
│ └── hello.info: 36 KB, executable: false
|
||||||
|
└── man
|
||||||
|
└── man1
|
||||||
|
└── hello.1.gz: 790 B, executable: false
|
||||||
|
```
|
||||||
|
|
||||||
|
A directory that contains a symlink and other directories:
|
||||||
|
|
||||||
|
```
|
||||||
|
├── bin -> share/go/bin
|
||||||
|
├── nix-support/
|
||||||
|
└── share/
|
||||||
|
```
|
|
@ -4,49 +4,67 @@
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
By default Nix reads settings from the following places:
|
Nix supports a variety of configuration settings, which are read from configuration files or taken as command line flags.
|
||||||
|
|
||||||
- The system-wide configuration file `sysconfdir/nix/nix.conf` (i.e.
|
## Configuration file
|
||||||
`/etc/nix/nix.conf` on most systems), or `$NIX_CONF_DIR/nix.conf` if
|
|
||||||
`NIX_CONF_DIR` is set. Values loaded in this file are not forwarded
|
|
||||||
to the Nix daemon. The client assumes that the daemon has already
|
|
||||||
loaded them.
|
|
||||||
|
|
||||||
- If `NIX_USER_CONF_FILES` is set, then each path separated by `:`
|
By default Nix reads settings from the following places, in that order:
|
||||||
will be loaded in reverse order.
|
|
||||||
|
|
||||||
Otherwise it will look for `nix/nix.conf` files in `XDG_CONFIG_DIRS`
|
1. The system-wide configuration file `sysconfdir/nix/nix.conf` (i.e. `/etc/nix/nix.conf` on most systems), or `$NIX_CONF_DIR/nix.conf` if [`NIX_CONF_DIR`](./env-common.md#env-NIX_CONF_DIR) is set.
|
||||||
and `XDG_CONFIG_HOME`. If unset, `XDG_CONFIG_DIRS` defaults to
|
|
||||||
`/etc/xdg`, and `XDG_CONFIG_HOME` defaults to `$HOME/.config`
|
|
||||||
as per [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
|
|
||||||
|
|
||||||
- If `NIX_CONFIG` is set, its contents is treated as the contents of
|
Values loaded in this file are not forwarded to the Nix daemon.
|
||||||
a configuration file.
|
The client assumes that the daemon has already loaded them.
|
||||||
|
|
||||||
The configuration files consist of `name = value` pairs, one per
|
1. If [`NIX_USER_CONF_FILES`](./env-common.md#env-NIX_USER_CONF_FILES) is set, then each path separated by `:` will be loaded in reverse order.
|
||||||
line. Other files can be included with a line like `include path`,
|
|
||||||
where *path* is interpreted relative to the current conf file and a
|
|
||||||
missing file is an error unless `!include` is used instead. Comments
|
|
||||||
start with a `#` character. Here is an example configuration file:
|
|
||||||
|
|
||||||
keep-outputs = true # Nice for developers
|
Otherwise it will look for `nix/nix.conf` files in `XDG_CONFIG_DIRS` and [`XDG_CONFIG_HOME`](./env-common.md#env-XDG_CONFIG_HOME).
|
||||||
keep-derivations = true # Idem
|
If unset, `XDG_CONFIG_DIRS` defaults to `/etc/xdg`, and `XDG_CONFIG_HOME` defaults to `$HOME/.config` as per [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
|
||||||
|
|
||||||
You can override settings on the command line using the `--option`
|
1. If [`NIX_CONFIG`](./env-common.md#env-NIX_CONFIG) is set, its contents are treated as the contents of a configuration file.
|
||||||
flag, e.g. `--option keep-outputs false`. Every configuration setting
|
|
||||||
also has a corresponding command line flag, e.g. `--max-jobs 16`; for
|
|
||||||
Boolean settings, there are two flags to enable or disable the setting
|
|
||||||
(e.g. `--keep-failed` and `--no-keep-failed`).
|
|
||||||
|
|
||||||
A configuration setting usually overrides any previous value. However,
|
### File format
|
||||||
you can prefix the name of the setting by `extra-` to *append* to the
|
|
||||||
previous value. For instance,
|
|
||||||
|
|
||||||
substituters = a b
|
Configuration files consist of `name = value` pairs, one per line.
|
||||||
extra-substituters = c d
|
Comments start with a `#` character.
|
||||||
|
|
||||||
defines the `substituters` setting to be `a b c d`. This is also
|
Example:
|
||||||
available as a command line flag (e.g. `--extra-substituters`).
|
|
||||||
|
|
||||||
The following settings are currently available:
|
```
|
||||||
|
keep-outputs = true # Nice for developers
|
||||||
|
keep-derivations = true # Idem
|
||||||
|
```
|
||||||
|
|
||||||
|
Other files can be included with a line like `include <path>`, where `<path>` is interpreted relative to the current configuration file.
|
||||||
|
A missing file is an error unless `!include` is used instead.
|
||||||
|
|
||||||
|
A configuration setting usually overrides any previous value.
|
||||||
|
However, for settings that take a list of items, you can prefix the name of the setting by `extra-` to *append* to the previous value.
|
||||||
|
|
||||||
|
For instance,
|
||||||
|
|
||||||
|
```
|
||||||
|
substituters = a b
|
||||||
|
extra-substituters = c d
|
||||||
|
```
|
||||||
|
|
||||||
|
defines the `substituters` setting to be `a b c d`.
|
||||||
|
|
||||||
|
Unknown option names are not an error, and are simply ignored with a warning.
|
||||||
|
|
||||||
|
## Command line flags
|
||||||
|
|
||||||
|
Configuration options can be set on the command line, overriding the values set in the [configuration file](#configuration-file):
|
||||||
|
|
||||||
|
- Every configuration setting has corresponding command line flag (e.g. `--max-jobs 16`).
|
||||||
|
Boolean settings do not need an argument, and can be explicitly disabled with the `no-` prefix (e.g. `--keep-failed` and `--no-keep-failed`).
|
||||||
|
|
||||||
|
Unknown option names are invalid flags (unless there is already a flag with that name), and are rejected with an error.
|
||||||
|
|
||||||
|
- The flag `--option <name> <value>` is interpreted exactly like a `<name> = <value>` in a setting file.
|
||||||
|
|
||||||
|
Unknown option names are ignored with a warning.
|
||||||
|
|
||||||
|
The `extra-` prefix is supported for settings that take a list of items (e.g. `--extra-trusted users alice` or `--option extra-trusted-users alice`).
|
||||||
|
|
||||||
|
# Available settings
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,12 @@ Most Nix commands interpret the following environment variables:
|
||||||
Settings are separated by the newline character.
|
Settings are separated by the newline character.
|
||||||
|
|
||||||
- <span id="env-NIX_USER_CONF_FILES">[`NIX_USER_CONF_FILES`](#env-NIX_USER_CONF_FILES)</span>\
|
- <span id="env-NIX_USER_CONF_FILES">[`NIX_USER_CONF_FILES`](#env-NIX_USER_CONF_FILES)</span>\
|
||||||
Overrides the location of the user Nix configuration files to load
|
Overrides the location of the Nix user configuration files to load from.
|
||||||
from (defaults to the XDG spec locations). The variable is treated
|
|
||||||
as a list separated by the `:` token.
|
The default are the locations according to the [XDG Base Directory Specification].
|
||||||
|
See the [XDG Base Directories](#xdg-base-directories) sub-section for details.
|
||||||
|
|
||||||
|
The variable is treated as a list separated by the `:` token.
|
||||||
|
|
||||||
- <span id="env-TMPDIR">[`TMPDIR`](#env-TMPDIR)</span>\
|
- <span id="env-TMPDIR">[`TMPDIR`](#env-TMPDIR)</span>\
|
||||||
Use the specified directory to store temporary files. In particular,
|
Use the specified directory to store temporary files. In particular,
|
||||||
|
@ -103,15 +106,19 @@ Most Nix commands interpret the following environment variables:
|
||||||
384 MiB. Setting it to a low value reduces memory consumption, but
|
384 MiB. Setting it to a low value reduces memory consumption, but
|
||||||
will increase runtime due to the overhead of garbage collection.
|
will increase runtime due to the overhead of garbage collection.
|
||||||
|
|
||||||
## XDG Base Directory
|
## XDG Base Directories
|
||||||
|
|
||||||
New Nix commands conform to the [XDG Base Directory Specification], and use the following environment variables to determine locations of various state and configuration files:
|
Nix follows the [XDG Base Directory Specification].
|
||||||
|
|
||||||
|
For backwards compatibility, Nix commands will follow the standard only when [`use-xdg-base-directories`] is enabled.
|
||||||
|
[New Nix commands](@docroot@/command-ref/new-cli/nix.md) (experimental) conform to the standard by default.
|
||||||
|
|
||||||
|
The following environment variables are used to determine locations of various state and configuration files:
|
||||||
|
|
||||||
- [`XDG_CONFIG_HOME`]{#env-XDG_CONFIG_HOME} (default `~/.config`)
|
- [`XDG_CONFIG_HOME`]{#env-XDG_CONFIG_HOME} (default `~/.config`)
|
||||||
- [`XDG_STATE_HOME`]{#env-XDG_STATE_HOME} (default `~/.local/state`)
|
- [`XDG_STATE_HOME`]{#env-XDG_STATE_HOME} (default `~/.local/state`)
|
||||||
- [`XDG_CACHE_HOME`]{#env-XDG_CACHE_HOME} (default `~/.cache`)
|
- [`XDG_CACHE_HOME`]{#env-XDG_CACHE_HOME} (default `~/.cache`)
|
||||||
|
|
||||||
Classic Nix commands can also be made to follow this standard using the [`use-xdg-base-directories`] configuration option.
|
|
||||||
|
|
||||||
[XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
[XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||||
[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
|
[`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories
|
|
@ -51,8 +51,9 @@ derivation).
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
|
||||||
All options not listed here are passed to `nix-store --realise`,
|
All options not listed here are passed to
|
||||||
except for `--arg` and `--attr` / `-A` which are passed to `nix-instantiate`.
|
[`nix-store --realise`](nix-store/realise.md),
|
||||||
|
except for `--arg` and `--attr` / `-A` which are passed to [`nix-instantiate`](nix-instantiate.md).
|
||||||
|
|
||||||
- <span id="opt-no-out-link">[`--no-out-link`](#opt-no-out-link)<span>
|
- <span id="opt-no-out-link">[`--no-out-link`](#opt-no-out-link)<span>
|
||||||
|
|
||||||
|
@ -69,6 +70,8 @@ except for `--arg` and `--attr` / `-A` which are passed to `nix-instantiate`.
|
||||||
Change the name of the symlink to the output path created from
|
Change the name of the symlink to the output path created from
|
||||||
`result` to *outlink*.
|
`result` to *outlink*.
|
||||||
|
|
||||||
|
{{#include ./status-build-failure.md}}
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
{{#include ./env-common.md}}
|
{{#include ./env-common.md}}
|
||||||
|
@ -76,7 +79,7 @@ except for `--arg` and `--attr` / `-A` which are passed to `nix-instantiate`.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A firefox
|
$ nix-build '<nixpkgs>' --attr firefox
|
||||||
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
|
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
|
||||||
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
|
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
|
||||||
|
|
||||||
|
@ -91,7 +94,7 @@ If a derivation has multiple outputs, `nix-build` will build the default
|
||||||
(first) output. You can also build all outputs:
|
(first) output. You can also build all outputs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A openssl.all
|
$ nix-build '<nixpkgs>' --attr openssl.all
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a symlink for each output named `result-outputname`.
|
This will create a symlink for each output named `result-outputname`.
|
||||||
|
@ -101,7 +104,7 @@ outputs `out`, `bin` and `man`, `nix-build` will create symlinks
|
||||||
specific output:
|
specific output:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A openssl.man
|
$ nix-build '<nixpkgs>' --attr openssl.man
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a symlink `result-man`.
|
This will create a symlink `result-man`.
|
||||||
|
@ -109,7 +112,7 @@ This will create a symlink `result-man`.
|
||||||
Build a Nix expression given on the command line:
|
Build a Nix expression given on the command line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -E 'with import <nixpkgs> { }; runCommand "foo" { } "echo bar > $out"'
|
$ nix-build --expr 'with import <nixpkgs> { }; runCommand "foo" { } "echo bar > $out"'
|
||||||
$ cat ./result
|
$ cat ./result
|
||||||
bar
|
bar
|
||||||
```
|
```
|
||||||
|
@ -118,5 +121,5 @@ Build the GNU Hello package from the latest revision of the master
|
||||||
branch of Nixpkgs:
|
branch of Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz -A hello
|
$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz --attr hello
|
||||||
```
|
```
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# Synopsis
|
# Synopsis
|
||||||
|
|
||||||
`nix-channel` {`--add` url [*name*] | `--remove` *name* | `--list` | `--update` [*names…*] | `--rollback` [*generation*] }
|
`nix-channel` {`--add` url [*name*] | `--remove` *name* | `--list` | `--update` [*names…*] | `--list-generations` | `--rollback` [*generation*] }
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
|
@ -39,6 +39,15 @@ This command has the following operations:
|
||||||
for `nix-env` operations (by symlinking them from the directory
|
for `nix-env` operations (by symlinking them from the directory
|
||||||
`~/.nix-defexpr`).
|
`~/.nix-defexpr`).
|
||||||
|
|
||||||
|
- `--list-generations`\
|
||||||
|
Prints a list of all the current existing generations for the
|
||||||
|
channel profile.
|
||||||
|
|
||||||
|
Works the same way as
|
||||||
|
```
|
||||||
|
nix-env --profile /nix/var/nix/profiles/per-user/$USER/channels --list-generations
|
||||||
|
```
|
||||||
|
|
||||||
- `--rollback` \[*generation*\]\
|
- `--rollback` \[*generation*\]\
|
||||||
Reverts the previous call to `nix-channel
|
Reverts the previous call to `nix-channel
|
||||||
--update`. Optionally, you can specify a specific channel generation
|
--update`. Optionally, you can specify a specific channel generation
|
||||||
|
@ -52,6 +61,12 @@ The list of subscribed channels is stored in `~/.nix-channels`.
|
||||||
|
|
||||||
{{#include ./env-common.md}}
|
{{#include ./env-common.md}}
|
||||||
|
|
||||||
|
# Files
|
||||||
|
|
||||||
|
`nix-channel` operates on the following files.
|
||||||
|
|
||||||
|
{{#include ./files/channels.md}}
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
||||||
|
@ -59,18 +74,18 @@ To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
||||||
```console
|
```console
|
||||||
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
||||||
$ nix-channel --update
|
$ nix-channel --update
|
||||||
$ nix-env -iA nixpkgs.hello
|
$ nix-env --install --attr nixpkgs.hello
|
||||||
```
|
```
|
||||||
|
|
||||||
You can revert channel updates using `--rollback`:
|
You can revert channel updates using `--rollback`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
|
$ nix-instantiate --eval --expr '(import <nixpkgs> {}).lib.version'
|
||||||
"14.04.527.0e935f1"
|
"14.04.527.0e935f1"
|
||||||
|
|
||||||
$ nix-channel --rollback
|
$ nix-channel --rollback
|
||||||
switching from generation 483 to 482
|
switching from generation 483 to 482
|
||||||
|
|
||||||
$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
|
$ nix-instantiate --eval --expr '(import <nixpkgs> {}).lib.version'
|
||||||
"14.04.526.dbadfad"
|
"14.04.526.dbadfad"
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Name
|
# Name
|
||||||
|
|
||||||
`nix-collect-garbage` - delete unreachable store paths
|
`nix-collect-garbage` - delete unreachable [store objects]
|
||||||
|
|
||||||
# Synopsis
|
# Synopsis
|
||||||
|
|
||||||
|
@ -8,17 +8,57 @@
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
The command `nix-collect-garbage` is mostly an alias of [`nix-store
|
The command `nix-collect-garbage` is mostly an alias of [`nix-store --gc`](@docroot@/command-ref/nix-store/gc.md).
|
||||||
--gc`](@docroot@/command-ref/nix-store/gc.md), that is, it deletes all
|
That is, it deletes all unreachable [store objects] in the Nix store to clean up your system.
|
||||||
unreachable paths in the Nix store to clean up your system. However,
|
|
||||||
it provides two additional options: `-d` (`--delete-old`), which
|
However, it provides two additional options,
|
||||||
deletes all old generations of all profiles in `/nix/var/nix/profiles`
|
[`--delete-old`](#opt-delete-old) and [`--delete-older-than`](#opt-delete-older-than),
|
||||||
by invoking `nix-env --delete-generations old` on all profiles (of
|
which also delete old [profiles], allowing potentially more [store objects] to be deleted because profiles are also garbage collection roots.
|
||||||
course, this makes rollbacks to previous configurations impossible);
|
These options are the equivalent of running
|
||||||
and `--delete-older-than` *period*, where period is a value such as
|
[`nix-env --delete-generations`](@docroot@/command-ref/nix-env/delete-generations.md)
|
||||||
`30d`, which deletes all generations older than the specified number
|
with various augments on multiple profiles,
|
||||||
of days in all profiles in `/nix/var/nix/profiles` (except for the
|
prior to running `nix-collect-garbage` (or just `nix-store --gc`) without any flags.
|
||||||
generations that were active at that point in time).
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Deleting previous configurations makes rollbacks to them impossible.
|
||||||
|
|
||||||
|
These flags should be used with care, because they potentially delete generations of profiles used by other users on the system.
|
||||||
|
|
||||||
|
## Locations searched for profiles
|
||||||
|
|
||||||
|
`nix-collect-garbage` cannot know about all profiles; that information doesn't exist.
|
||||||
|
Instead, it looks in a few locations, and acts on all profiles it finds there:
|
||||||
|
|
||||||
|
1. The default profile locations as specified in the [profiles] section of the manual.
|
||||||
|
|
||||||
|
2. > **NOTE**
|
||||||
|
>
|
||||||
|
> Not stable; subject to change
|
||||||
|
>
|
||||||
|
> Do not rely on this functionality; it just exists for migration purposes and is may change in the future.
|
||||||
|
> These deprecated paths remain a private implementation detail of Nix.
|
||||||
|
|
||||||
|
`$NIX_STATE_DIR/profiles` and `$NIX_STATE_DIR/profiles/per-user`.
|
||||||
|
|
||||||
|
With the exception of `$NIX_STATE_DIR/profiles/per-user/root` and `$NIX_STATE_DIR/profiles/default`, these directories are no longer used by other commands.
|
||||||
|
`nix-collect-garbage` looks there anyways in order to clean up profiles from older versions of Nix.
|
||||||
|
|
||||||
|
# Options
|
||||||
|
|
||||||
|
These options are for deleting old [profiles] prior to deleting unreachable [store objects].
|
||||||
|
|
||||||
|
- <span id="opt-delete-old">[`--delete-old`](#opt-delete-old)</span> / `-d`\
|
||||||
|
Delete all old generations of profiles.
|
||||||
|
|
||||||
|
This is the equivalent of invoking `nix-env --delete-generations old` on each found profile.
|
||||||
|
|
||||||
|
- <span id="opt-delete-older-than">[`--delete-older-than`](#opt-delete-older-than)</span> *period*\
|
||||||
|
Delete all generations of profiles older than the specified amount (except for the generations that were active at that point in time).
|
||||||
|
*period* is a value such as `30d`, which would mean 30 days.
|
||||||
|
|
||||||
|
This is the equivalent of invoking [`nix-env --delete-generations <period>`](@docroot@/command-ref/nix-env/delete-generations.md#generations-time) on each found profile.
|
||||||
|
See the documentation of that command for additional information about the *period* argument.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
|
@ -32,3 +72,6 @@ generations of each profile, do
|
||||||
```console
|
```console
|
||||||
$ nix-collect-garbage -d
|
$ nix-collect-garbage -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[profiles]: @docroot@/command-ref/files/profiles.md
|
||||||
|
[store objects]: @docroot@/glossary.md#gloss-store-object
|
||||||
|
|
|
@ -87,5 +87,5 @@ environment:
|
||||||
```console
|
```console
|
||||||
$ nix-copy-closure --from alice@itchy.labs \
|
$ nix-copy-closure --from alice@itchy.labs \
|
||||||
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||||
$ nix-env -i /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
$ nix-env --install /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||||
```
|
```
|
||||||
|
|
|
@ -49,7 +49,7 @@ These pages can be viewed offline:
|
||||||
|
|
||||||
# Selectors
|
# Selectors
|
||||||
|
|
||||||
Several commands, such as `nix-env -q` and `nix-env -i`, take a list of
|
Several commands, such as `nix-env --query ` and `nix-env --install `, take a list of
|
||||||
arguments that specify the packages on which to operate. These are
|
arguments that specify the packages on which to operate. These are
|
||||||
extended regular expressions that must match the entire name of the
|
extended regular expressions that must match the entire name of the
|
||||||
package. (For details on regular expressions, see **regex**(7).) The match is
|
package. (For details on regular expressions, see **regex**(7).) The match is
|
||||||
|
@ -83,6 +83,8 @@ match. Here are some examples:
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
|
|
||||||
|
`nix-env` operates on the following files.
|
||||||
|
|
||||||
{{#include ./files/default-nix-expression.md}}
|
{{#include ./files/default-nix-expression.md}}
|
||||||
|
|
||||||
{{#include ./files/profiles.md}}
|
{{#include ./files/profiles.md}}
|
||||||
|
|
|
@ -9,14 +9,47 @@
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
This operation deletes the specified generations of the current profile.
|
This operation deletes the specified generations of the current profile.
|
||||||
The generations can be a list of generation numbers, the special value
|
|
||||||
`old` to delete all non-current generations, a value such as `30d` to
|
*generations* can be a one of the following:
|
||||||
delete all generations older than the specified number of days (except
|
|
||||||
for the generation that was active at that point in time), or a value
|
- <span id="generations-list">`<number>...`</span>:\
|
||||||
such as `+5` to keep the last `5` generations ignoring any newer than
|
A list of generation numbers, each one a separate command-line argument.
|
||||||
current, e.g., if `30` is the current generation `+5` will delete
|
|
||||||
generation `25` and all older generations. Periodically deleting old
|
Delete exactly the profile generations given by their generation number.
|
||||||
generations is important to make garbage collection effective.
|
Deleting the current generation is not allowed.
|
||||||
|
|
||||||
|
- The special value <span id="generations-old">`old`</span>
|
||||||
|
|
||||||
|
Delete all generations except the current one.
|
||||||
|
|
||||||
|
> **WARNING**
|
||||||
|
>
|
||||||
|
> Older *and newer* generations will be deleted by this operation.
|
||||||
|
>
|
||||||
|
> One might expect this to just delete older generations than the curent one, but that is only true if the current generation is also the latest.
|
||||||
|
> Because one can roll back to a previous generation, it is possible to have generations newer than the current one.
|
||||||
|
> They will also be deleted.
|
||||||
|
|
||||||
|
- <span id="generations-time">`<number>d`</span>:\
|
||||||
|
The last *number* days
|
||||||
|
|
||||||
|
*Example*: `30d`
|
||||||
|
|
||||||
|
Delete all generations created more than *number* days ago, except the most recent one of them.
|
||||||
|
This allows rolling back to generations that were available within the specified period.
|
||||||
|
|
||||||
|
- <span id="generations-count">`+<number>`</span>:\
|
||||||
|
The last *number* generations up to the present
|
||||||
|
|
||||||
|
*Example*: `+5`
|
||||||
|
|
||||||
|
Keep the last *number* generations, along with any newer than current.
|
||||||
|
|
||||||
|
Periodically deleting old generations is important to make garbage collection
|
||||||
|
effective.
|
||||||
|
The is because profiles are also garbage collection roots — any [store object] reachable from a profile is "alive" and ineligible for deletion.
|
||||||
|
|
||||||
|
[store object]: @docroot@/glossary.md#gloss-store-object
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
|
@ -28,19 +61,35 @@ generations is important to make garbage collection effective.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
## Delete explicit generation numbers
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --delete-generations 3 4 8
|
$ nix-env --delete-generations 3 4 8
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Delete the generations numbered 3, 4, and 8, so long as the current active generation is not any of those.
|
||||||
|
|
||||||
|
## Keep most-recent by count (number of generations)
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --delete-generations +5
|
$ nix-env --delete-generations +5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Suppose `30` is the current generation, and we currently have generations numbered `20` through `32`.
|
||||||
|
|
||||||
|
Then this command will delete generations `20` through `25` (`<= 30 - 5`),
|
||||||
|
and keep generations `26` through `31` (`> 30 - 5`).
|
||||||
|
|
||||||
|
## Keep most-recent by time (number of days)
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --delete-generations 30d
|
$ nix-env --delete-generations 30d
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
This command will delete all generations older than 30 days, except for the generation that was active 30 days ago (if it currently exists).
|
||||||
$ nix-env -p other_profile --delete-generations old
|
|
||||||
```
|
|
||||||
|
|
||||||
|
## Delete all older
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-env --profile other_profile --delete-generations old
|
||||||
|
```
|
||||||
|
|
|
@ -36,7 +36,7 @@ a number of possible ways:
|
||||||
then the derivation with the highest version will be installed.
|
then the derivation with the highest version will be installed.
|
||||||
|
|
||||||
You can force the installation of multiple derivations with the same
|
You can force the installation of multiple derivations with the same
|
||||||
name by being specific about the versions. For instance, `nix-env -i
|
name by being specific about the versions. For instance, `nix-env --install
|
||||||
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
|
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
|
||||||
probably cause a user environment conflict\!).
|
probably cause a user environment conflict\!).
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ a number of possible ways:
|
||||||
paths* that select attributes from the top-level Nix
|
paths* that select attributes from the top-level Nix
|
||||||
expression. This is faster than using derivation names and
|
expression. This is faster than using derivation names and
|
||||||
unambiguous. To find out the attribute paths of available
|
unambiguous. To find out the attribute paths of available
|
||||||
packages, use `nix-env -qaP`.
|
packages, use `nix-env --query --available --attr-path `.
|
||||||
|
|
||||||
- If `--from-profile` *path* is given, *args* is a set of names
|
- If `--from-profile` *path* is given, *args* is a set of names
|
||||||
denoting installed store paths in the profile *path*. This is an
|
denoting installed store paths in the profile *path*. This is an
|
||||||
|
@ -87,7 +87,7 @@ a number of possible ways:
|
||||||
|
|
||||||
- `--remove-all` / `-r`\
|
- `--remove-all` / `-r`\
|
||||||
Remove all previously installed packages first. This is equivalent
|
Remove all previously installed packages first. This is equivalent
|
||||||
to running `nix-env -e '.*'` first, except that everything happens
|
to running `nix-env --uninstall '.*'` first, except that everything happens
|
||||||
in a single transaction.
|
in a single transaction.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
@ -103,9 +103,9 @@ a number of possible ways:
|
||||||
To install a package using a specific attribute path from the active Nix expression:
|
To install a package using a specific attribute path from the active Nix expression:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA gcc40mips
|
$ nix-env --install --attr gcc40mips
|
||||||
installing `gcc-4.0.2'
|
installing `gcc-4.0.2'
|
||||||
$ nix-env -iA xorg.xorgserver
|
$ nix-env --install --attr xorg.xorgserver
|
||||||
installing `xorg-server-1.2.0'
|
installing `xorg-server-1.2.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -133,32 +133,32 @@ installing `gcc-3.3.2'
|
||||||
To install all derivations in the Nix expression `foo.nix`:
|
To install all derivations in the Nix expression `foo.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ~/foo.nix -i '.*'
|
$ nix-env --file ~/foo.nix --install '.*'
|
||||||
```
|
```
|
||||||
|
|
||||||
To copy the store path with symbolic name `gcc` from another profile:
|
To copy the store path with symbolic name `gcc` from another profile:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i --from-profile /nix/var/nix/profiles/foo gcc
|
$ nix-env --install --from-profile /nix/var/nix/profiles/foo gcc
|
||||||
```
|
```
|
||||||
|
|
||||||
To install a specific [store derivation] (typically created by
|
To install a specific [store derivation] (typically created by
|
||||||
`nix-instantiate`):
|
`nix-instantiate`):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
|
$ nix-env --install /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
|
||||||
```
|
```
|
||||||
|
|
||||||
To install a specific output path:
|
To install a specific output path:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
|
$ nix-env --install /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
|
||||||
```
|
```
|
||||||
|
|
||||||
To install from a Nix expression specified on the command-line:
|
To install from a Nix expression specified on the command-line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ./foo.nix -i -E \
|
$ nix-env --file ./foo.nix --install --expr \
|
||||||
'f: (f {system = "i686-linux";}).subversionWithJava'
|
'f: (f {system = "i686-linux";}).subversionWithJava'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ function defined in `./foo.nix`.
|
||||||
A dry-run tells you which paths will be downloaded or built from source:
|
A dry-run tells you which paths will be downloaded or built from source:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f '<nixpkgs>' -iA hello --dry-run
|
$ nix-env --file '<nixpkgs>' --install --attr hello --dry-run
|
||||||
(dry run; not doing anything)
|
(dry run; not doing anything)
|
||||||
installing ‘hello-2.10’
|
installing ‘hello-2.10’
|
||||||
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
|
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
|
||||||
|
@ -182,6 +182,6 @@ To install Firefox from the latest revision in the Nixpkgs/NixOS 14.12
|
||||||
channel:
|
channel:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz -iA firefox
|
$ nix-env --file https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz --install --attr firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ derivation is shown unless `--no-name` is specified.
|
||||||
To show installed packages:
|
To show installed packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
bison-1.875c
|
bison-1.875c
|
||||||
docbook-xml-4.2
|
docbook-xml-4.2
|
||||||
firefox-1.0.4
|
firefox-1.0.4
|
||||||
|
@ -149,7 +149,7 @@ ORBit2-2.8.3
|
||||||
To show available packages:
|
To show available packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa
|
$ nix-env --query --available
|
||||||
firefox-1.0.7
|
firefox-1.0.7
|
||||||
GConf-2.4.0.1
|
GConf-2.4.0.1
|
||||||
MPlayer-1.0pre7
|
MPlayer-1.0pre7
|
||||||
|
@ -160,7 +160,7 @@ ORBit2-2.8.3
|
||||||
To show the status of available packages:
|
To show the status of available packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qas
|
$ nix-env --query --available --status
|
||||||
-P- firefox-1.0.7 (not installed but present)
|
-P- firefox-1.0.7 (not installed but present)
|
||||||
--S GConf-2.4.0.1 (not present, but there is a substitute for fast installation)
|
--S GConf-2.4.0.1 (not present, but there is a substitute for fast installation)
|
||||||
--S MPlayer-1.0pre3 (i.e., this is not the installed MPlayer, even though the version is the same!)
|
--S MPlayer-1.0pre3 (i.e., this is not the installed MPlayer, even though the version is the same!)
|
||||||
|
@ -171,14 +171,14 @@ IP- ORBit2-2.8.3 (installed and by definition present)
|
||||||
To show available packages in the Nix expression `foo.nix`:
|
To show available packages in the Nix expression `foo.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ./foo.nix -qa
|
$ nix-env --file ./foo.nix --query --available
|
||||||
foo-1.2.3
|
foo-1.2.3
|
||||||
```
|
```
|
||||||
|
|
||||||
To compare installed versions to what’s available:
|
To compare installed versions to what’s available:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qc
|
$ nix-env --query --compare-versions
|
||||||
...
|
...
|
||||||
acrobat-reader-7.0 - ? (package is not available at all)
|
acrobat-reader-7.0 - ? (package is not available at all)
|
||||||
autoconf-2.59 = 2.59 (same version)
|
autoconf-2.59 = 2.59 (same version)
|
||||||
|
@ -189,7 +189,7 @@ firefox-1.0.4 < 1.0.7 (a more recent version is available)
|
||||||
To show all packages with “`zip`” in the name:
|
To show all packages with “`zip`” in the name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa '.*zip.*'
|
$ nix-env --query --available '.*zip.*'
|
||||||
bzip2-1.0.6
|
bzip2-1.0.6
|
||||||
gzip-1.6
|
gzip-1.6
|
||||||
zip-3.0
|
zip-3.0
|
||||||
|
@ -199,7 +199,7 @@ zip-3.0
|
||||||
To show all packages with “`firefox`” or “`chromium`” in the name:
|
To show all packages with “`firefox`” or “`chromium`” in the name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa '.*(firefox|chromium).*'
|
$ nix-env --query --available '.*(firefox|chromium).*'
|
||||||
chromium-37.0.2062.94
|
chromium-37.0.2062.94
|
||||||
chromium-beta-38.0.2125.24
|
chromium-beta-38.0.2125.24
|
||||||
firefox-32.0.3
|
firefox-32.0.3
|
||||||
|
@ -210,6 +210,6 @@ firefox-with-plugins-13.0.1
|
||||||
To show all packages in the latest revision of the Nixpkgs repository:
|
To show all packages in the latest revision of the Nixpkgs repository:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f https://github.com/NixOS/nixpkgs/archive/master.tar.gz -qa
|
$ nix-env --file https://github.com/NixOS/nixpkgs/archive/master.tar.gz --query --available
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -46,16 +46,16 @@ To prevent the currently installed Firefox from being upgraded:
|
||||||
$ nix-env --set-flag keep true firefox
|
$ nix-env --set-flag keep true firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
After this, `nix-env -u` will ignore Firefox.
|
After this, `nix-env --upgrade ` will ignore Firefox.
|
||||||
|
|
||||||
To disable the currently installed Firefox, then install a new Firefox
|
To disable the currently installed Firefox, then install a new Firefox
|
||||||
while the old remains part of the profile:
|
while the old remains part of the profile:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
firefox-2.0.0.9 (the current one)
|
firefox-2.0.0.9 (the current one)
|
||||||
|
|
||||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
$ nix-env --preserve-installed --install firefox-2.0.0.11
|
||||||
installing `firefox-2.0.0.11'
|
installing `firefox-2.0.0.11'
|
||||||
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
||||||
collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
||||||
|
@ -65,10 +65,10 @@ collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
||||||
$ nix-env --set-flag active false firefox
|
$ nix-env --set-flag active false firefox
|
||||||
setting flag on `firefox-2.0.0.9'
|
setting flag on `firefox-2.0.0.9'
|
||||||
|
|
||||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
$ nix-env --preserve-installed --install firefox-2.0.0.11
|
||||||
installing `firefox-2.0.0.11'
|
installing `firefox-2.0.0.11'
|
||||||
|
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
firefox-2.0.0.11 (the enabled one)
|
firefox-2.0.0.11 (the enabled one)
|
||||||
firefox-2.0.0.9 (the disabled one)
|
firefox-2.0.0.9 (the disabled one)
|
||||||
```
|
```
|
||||||
|
|
|
@ -25,6 +25,6 @@ The following updates a profile such that its current generation will
|
||||||
contain just Firefox:
|
contain just Firefox:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -p /nix/var/nix/profiles/browser --set firefox
|
$ nix-env --profile /nix/var/nix/profiles/browser --set firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ Switching will fail if the specified generation does not exist.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -G 42
|
$ nix-env --switch-generation 42
|
||||||
switching from generation 50 to 42
|
switching from generation 50 to 42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -22,5 +22,5 @@ the symlink `~/.nix-profile` is made to point to *path*.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -S ~/my-profile
|
$ nix-env --switch-profile ~/my-profile
|
||||||
```
|
```
|
||||||
|
|
|
@ -24,5 +24,5 @@ designated by the symbolic names *drvnames* are removed.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --uninstall gcc
|
$ nix-env --uninstall gcc
|
||||||
$ nix-env -e '.*' (remove everything)
|
$ nix-env --uninstall '.*' (remove everything)
|
||||||
```
|
```
|
||||||
|
|
|
@ -76,21 +76,21 @@ version is installed.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.gcc
|
$ nix-env --upgrade --attr nixpkgs.gcc
|
||||||
upgrading `gcc-3.3.1' to `gcc-3.4'
|
upgrading `gcc-3.3.1' to `gcc-3.4'
|
||||||
```
|
```
|
||||||
|
|
||||||
When there are no updates available, nothing will happen:
|
When there are no updates available, nothing will happen:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.pan
|
$ nix-env --upgrade --attr nixpkgs.pan
|
||||||
```
|
```
|
||||||
|
|
||||||
Using `-A` is preferred when possible, as it is faster and unambiguous but
|
Using `-A` is preferred when possible, as it is faster and unambiguous but
|
||||||
it is also possible to upgrade to a specific version by matching the derivation name:
|
it is also possible to upgrade to a specific version by matching the derivation name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u gcc-3.3.2 --always
|
$ nix-env --upgrade gcc-3.3.2 --always
|
||||||
upgrading `gcc-3.4' to `gcc-3.3.2'
|
upgrading `gcc-3.4' to `gcc-3.3.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ To try to upgrade everything
|
||||||
(matching packages based on the part of the derivation name without version):
|
(matching packages based on the part of the derivation name without version):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
upgrading `hello-2.1.2' to `hello-2.1.3'
|
upgrading `hello-2.1.2' to `hello-2.1.3'
|
||||||
upgrading `mozilla-1.2' to `mozilla-1.4'
|
upgrading `mozilla-1.2' to `mozilla-1.4'
|
||||||
```
|
```
|
||||||
|
|
|
@ -88,7 +88,7 @@ Instantiate [store derivation]s from a Nix expression, and build them using `nix
|
||||||
$ nix-instantiate test.nix (instantiate)
|
$ nix-instantiate test.nix (instantiate)
|
||||||
/nix/store/cigxbmvy6dzix98dxxh9b6shg7ar5bvs-perl-BerkeleyDB-0.26.drv
|
/nix/store/cigxbmvy6dzix98dxxh9b6shg7ar5bvs-perl-BerkeleyDB-0.26.drv
|
||||||
|
|
||||||
$ nix-store -r $(nix-instantiate test.nix) (build)
|
$ nix-store --realise $(nix-instantiate test.nix) (build)
|
||||||
...
|
...
|
||||||
/nix/store/qhqk4n8ci095g3sdp93x7rgwyh9rdvgk-perl-BerkeleyDB-0.26 (output path)
|
/nix/store/qhqk4n8ci095g3sdp93x7rgwyh9rdvgk-perl-BerkeleyDB-0.26 (output path)
|
||||||
|
|
||||||
|
@ -100,30 +100,30 @@ dr-xr-xr-x 2 eelco users 4096 1970-01-01 01:00 lib
|
||||||
You can also give a Nix expression on the command line:
|
You can also give a Nix expression on the command line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate -E 'with import <nixpkgs> { }; hello'
|
$ nix-instantiate --expr 'with import <nixpkgs> { }; hello'
|
||||||
/nix/store/j8s4zyv75a724q38cb0r87rlczaiag4y-hello-2.8.drv
|
/nix/store/j8s4zyv75a724q38cb0r87rlczaiag4y-hello-2.8.drv
|
||||||
```
|
```
|
||||||
|
|
||||||
This is equivalent to:
|
This is equivalent to:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate '<nixpkgs>' -A hello
|
$ nix-instantiate '<nixpkgs>' --attr hello
|
||||||
```
|
```
|
||||||
|
|
||||||
Parsing and evaluating Nix expressions:
|
Parsing and evaluating Nix expressions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --parse -E '1 + 2'
|
$ nix-instantiate --parse --expr '1 + 2'
|
||||||
1 + 2
|
1 + 2
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval -E '1 + 2'
|
$ nix-instantiate --eval --expr '1 + 2'
|
||||||
3
|
3
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml -E '1 + 2'
|
$ nix-instantiate --eval --xml --expr '1 + 2'
|
||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<expr>
|
<expr>
|
||||||
<int value="3" />
|
<int value="3" />
|
||||||
|
@ -133,7 +133,7 @@ $ nix-instantiate --eval --xml -E '1 + 2'
|
||||||
The difference between non-strict and strict evaluation:
|
The difference between non-strict and strict evaluation:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml -E 'rec { x = "foo"; y = x; }'
|
$ nix-instantiate --eval --xml --expr 'rec { x = "foo"; y = x; }'
|
||||||
...
|
...
|
||||||
<attr name="x">
|
<attr name="x">
|
||||||
<string value="foo" />
|
<string value="foo" />
|
||||||
|
@ -148,7 +148,7 @@ Note that `y` is left unevaluated (the XML representation doesn’t
|
||||||
attempt to show non-normal forms).
|
attempt to show non-normal forms).
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml --strict -E 'rec { x = "foo"; y = x; }'
|
$ nix-instantiate --eval --xml --strict --expr 'rec { x = "foo"; y = x; }'
|
||||||
...
|
...
|
||||||
<attr name="x">
|
<attr name="x">
|
||||||
<string value="foo" />
|
<string value="foo" />
|
||||||
|
|
|
@ -89,7 +89,7 @@ All options not listed here are passed to `nix-store
|
||||||
- `--packages` / `-p` *packages*…\
|
- `--packages` / `-p` *packages*…\
|
||||||
Set up an environment in which the specified packages are present.
|
Set up an environment in which the specified packages are present.
|
||||||
The command line arguments are interpreted as attribute names inside
|
The command line arguments are interpreted as attribute names inside
|
||||||
the Nix Packages collection. Thus, `nix-shell -p libjpeg openjdk`
|
the Nix Packages collection. Thus, `nix-shell --packages libjpeg openjdk`
|
||||||
will start a shell in which the packages denoted by the attribute
|
will start a shell in which the packages denoted by the attribute
|
||||||
names `libjpeg` and `openjdk` are present.
|
names `libjpeg` and `openjdk` are present.
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ To build the dependencies of the package Pan, and start an interactive
|
||||||
shell in which to build it:
|
shell in which to build it:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan
|
$ nix-shell '<nixpkgs>' --attr pan
|
||||||
[nix-shell]$ eval ${unpackPhase:-unpackPhase}
|
[nix-shell]$ eval ${unpackPhase:-unpackPhase}
|
||||||
[nix-shell]$ cd $sourceRoot
|
[nix-shell]$ cd $sourceRoot
|
||||||
[nix-shell]$ eval ${patchPhase:-patchPhase}
|
[nix-shell]$ eval ${patchPhase:-patchPhase}
|
||||||
|
@ -137,7 +137,7 @@ To clear the environment first, and do some additional automatic
|
||||||
initialisation of the interactive shell:
|
initialisation of the interactive shell:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan --pure \
|
$ nix-shell '<nixpkgs>' --attr pan --pure \
|
||||||
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
|
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -146,13 +146,13 @@ Nix expressions can also be given on the command line using the `-E` and
|
||||||
packages `sqlite` and `libX11`:
|
packages `sqlite` and `libX11`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -E 'with import <nixpkgs> { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
|
$ nix-shell --expr 'with import <nixpkgs> { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
|
||||||
```
|
```
|
||||||
|
|
||||||
A shorter way to do the same is:
|
A shorter way to do the same is:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p sqlite xorg.libX11
|
$ nix-shell --packages sqlite xorg.libX11
|
||||||
[nix-shell]$ echo $NIX_LDFLAGS
|
[nix-shell]$ echo $NIX_LDFLAGS
|
||||||
… -L/nix/store/j1zg5v…-sqlite-3.8.0.2/lib -L/nix/store/0gmcz9…-libX11-1.6.1/lib …
|
… -L/nix/store/j1zg5v…-sqlite-3.8.0.2/lib -L/nix/store/0gmcz9…-libX11-1.6.1/lib …
|
||||||
```
|
```
|
||||||
|
@ -162,7 +162,7 @@ the `buildInputs = [ ... ]` shown above, not only package names. So the
|
||||||
following is also legal:
|
following is also legal:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p sqlite 'git.override { withManual = false; }'
|
$ nix-shell --packages sqlite 'git.override { withManual = false; }'
|
||||||
```
|
```
|
||||||
|
|
||||||
The `-p` flag looks up Nixpkgs in the Nix search path. You can override
|
The `-p` flag looks up Nixpkgs in the Nix search path. You can override
|
||||||
|
@ -171,7 +171,7 @@ gives you a shell containing the Pan package from a specific revision of
|
||||||
Nixpkgs:
|
Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
|
$ nix-shell --packages pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
|
||||||
|
|
||||||
[nix-shell:~]$ pan --version
|
[nix-shell:~]$ pan --version
|
||||||
Pan 0.139
|
Pan 0.139
|
||||||
|
@ -185,7 +185,7 @@ done by starting the script with the following lines:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i real-interpreter -p packages
|
#! nix-shell -i real-interpreter --packages packages
|
||||||
```
|
```
|
||||||
|
|
||||||
where *real-interpreter* is the “real” script interpreter that will be
|
where *real-interpreter* is the “real” script interpreter that will be
|
||||||
|
@ -202,7 +202,7 @@ For example, here is a Python script that depends on Python and the
|
||||||
|
|
||||||
```python
|
```python
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i python -p python pythonPackages.prettytable
|
#! nix-shell -i python --packages python pythonPackages.prettytable
|
||||||
|
|
||||||
import prettytable
|
import prettytable
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ requires Perl and the `HTML::TokeParser::Simple` and `LWP` packages:
|
||||||
|
|
||||||
```perl
|
```perl
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
|
#! nix-shell -i perl --packages perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
|
||||||
|
|
||||||
use HTML::TokeParser::Simple;
|
use HTML::TokeParser::Simple;
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ package like Terraform:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i bash -p "terraform.withPlugins (plugins: [ plugins.openstack ])"
|
#! nix-shell -i bash --packages "terraform.withPlugins (plugins: [ plugins.openstack ])"
|
||||||
|
|
||||||
terraform apply
|
terraform apply
|
||||||
```
|
```
|
||||||
|
@ -251,7 +251,7 @@ branch):
|
||||||
|
|
||||||
```haskell
|
```haskell
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
|
#! nix-shell -i runghc --packages "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
|
||||||
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
|
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
|
||||||
|
|
||||||
import Network.Curl.Download
|
import Network.Curl.Download
|
||||||
|
|
|
@ -23,7 +23,7 @@ produce the same NAR archive. For instance, directory entries are
|
||||||
always sorted so that the actual on-disk order doesn’t influence the
|
always sorted so that the actual on-disk order doesn’t influence the
|
||||||
result. This means that the cryptographic hash of a NAR dump of a
|
result. This means that the cryptographic hash of a NAR dump of a
|
||||||
path is usable as a fingerprint of the contents of the path. Indeed,
|
path is usable as a fingerprint of the contents of the path. Indeed,
|
||||||
the hashes of store paths stored in Nix’s database (see `nix-store -q
|
the hashes of store paths stored in Nix’s database (see `nix-store --query
|
||||||
--hash`) are SHA-256 hashes of the NAR dump of each store path.
|
--hash`) are SHA-256 hashes of the NAR dump of each store path.
|
||||||
|
|
||||||
NAR archives support filenames of unlimited length and 64-bit file
|
NAR archives support filenames of unlimited length and 64-bit file
|
||||||
|
|
|
@ -31,7 +31,7 @@ To copy a whole closure, do something
|
||||||
like:
|
like:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --export $(nix-store -qR paths) > out
|
$ nix-store --export $(nix-store --query --requisites paths) > out
|
||||||
```
|
```
|
||||||
|
|
||||||
To import the whole closure again, run:
|
To import the whole closure again, run:
|
||||||
|
|
|
@ -11,7 +11,7 @@ The following options are allowed for all `nix-store` operations, but may not al
|
||||||
be created in `/nix/var/nix/gcroots/auto/`. For instance,
|
be created in `/nix/var/nix/gcroots/auto/`. For instance,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --add-root /home/eelco/bla/result -r ...
|
$ nix-store --add-root /home/eelco/bla/result --realise ...
|
||||||
|
|
||||||
$ ls -l /nix/var/nix/gcroots/auto
|
$ ls -l /nix/var/nix/gcroots/auto
|
||||||
lrwxrwxrwx 1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result
|
lrwxrwxrwx 1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result
|
||||||
|
|
|
@ -145,7 +145,7 @@ Print the closure (runtime dependencies) of the `svn` program in the
|
||||||
current user environment:
|
current user environment:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -qR $(which svn)
|
$ nix-store --query --requisites $(which svn)
|
||||||
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
||||||
/nix/store/9lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
|
/nix/store/9lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
|
||||||
...
|
...
|
||||||
|
@ -154,7 +154,7 @@ $ nix-store -qR $(which svn)
|
||||||
Print the build-time dependencies of `svn`:
|
Print the build-time dependencies of `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -qR $(nix-store -qd $(which svn))
|
$ nix-store --query --requisites $(nix-store --query --deriver $(which svn))
|
||||||
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
|
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
|
||||||
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
|
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
|
||||||
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
|
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
|
||||||
|
@ -168,7 +168,7 @@ the derivation (`-qd`), not the closure of the output path that contains
|
||||||
Show the build-time dependencies as a tree:
|
Show the build-time dependencies as a tree:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --tree $(nix-store -qd $(which svn))
|
$ nix-store --query --tree $(nix-store --query --deriver $(which svn))
|
||||||
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
|
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
|
||||||
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
|
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
|
||||||
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
|
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
|
||||||
|
@ -180,7 +180,7 @@ $ nix-store -q --tree $(nix-store -qd $(which svn))
|
||||||
Show all paths that depend on the same OpenSSL library as `svn`:
|
Show all paths that depend on the same OpenSSL library as `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --referrers $(nix-store -q --binding openssl $(nix-store -qd $(which svn)))
|
$ nix-store --query --referrers $(nix-store --query --binding openssl $(nix-store --query --deriver $(which svn)))
|
||||||
/nix/store/23ny9l9wixx21632y2wi4p585qhva1q8-sylpheed-1.0.0
|
/nix/store/23ny9l9wixx21632y2wi4p585qhva1q8-sylpheed-1.0.0
|
||||||
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
||||||
/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3
|
/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3
|
||||||
|
@ -191,7 +191,7 @@ Show all paths that directly or indirectly depend on the Glibc (C
|
||||||
library) used by `svn`:
|
library) used by `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
|
$ nix-store --query --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
|
||||||
/nix/store/034a6h4vpz9kds5r6kzb9lhh81mscw43-libgnomeprintui-2.8.2
|
/nix/store/034a6h4vpz9kds5r6kzb9lhh81mscw43-libgnomeprintui-2.8.2
|
||||||
/nix/store/15l3yi0d45prm7a82pcrknxdh6nzmxza-gawk-3.1.4
|
/nix/store/15l3yi0d45prm7a82pcrknxdh6nzmxza-gawk-3.1.4
|
||||||
...
|
...
|
||||||
|
@ -204,7 +204,7 @@ Make a picture of the runtime dependency graph of the current user
|
||||||
environment:
|
environment:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --graph ~/.nix-profile | dot -Tps > graph.ps
|
$ nix-store --query --graph ~/.nix-profile | dot -Tps > graph.ps
|
||||||
$ gv graph.ps
|
$ gv graph.ps
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ Show every garbage collector root that points to a store path that
|
||||||
depends on `svn`:
|
depends on `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --roots $(which svn)
|
$ nix-store --query --roots $(which svn)
|
||||||
/nix/var/nix/profiles/default-81-link
|
/nix/var/nix/profiles/default-81-link
|
||||||
/nix/var/nix/profiles/default-82-link
|
/nix/var/nix/profiles/default-82-link
|
||||||
/home/eelco/.local/state/nix/profiles/profile-97-link
|
/home/eelco/.local/state/nix/profiles/profile-97-link
|
||||||
|
|
|
@ -27,7 +27,7 @@ substitute, then the log is unavailable.
|
||||||
# Example
|
# Example
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -l $(which ktorrent)
|
$ nix-store --read-log $(which ktorrent)
|
||||||
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
|
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
|
||||||
unpacking sources
|
unpacking sources
|
||||||
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
|
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
|
||||||
|
|
|
@ -54,36 +54,7 @@ The following flags are available:
|
||||||
previous build, the new output path is left in
|
previous build, the new output path is left in
|
||||||
`/nix/store/name.check.`
|
`/nix/store/name.check.`
|
||||||
|
|
||||||
Special exit codes:
|
{{#include ../status-build-failure.md}}
|
||||||
|
|
||||||
- `100`\
|
|
||||||
Generic build failure, the builder process returned with a non-zero
|
|
||||||
exit code.
|
|
||||||
|
|
||||||
- `101`\
|
|
||||||
Build timeout, the build was aborted because it did not complete
|
|
||||||
within the specified `timeout`.
|
|
||||||
|
|
||||||
- `102`\
|
|
||||||
Hash mismatch, the build output was rejected because it does not
|
|
||||||
match the [`outputHash` attribute of the
|
|
||||||
derivation](@docroot@/language/advanced-attributes.md).
|
|
||||||
|
|
||||||
- `104`\
|
|
||||||
Not deterministic, the build succeeded in check mode but the
|
|
||||||
resulting output is not binary reproducible.
|
|
||||||
|
|
||||||
With the `--keep-going` flag it's possible for multiple failures to
|
|
||||||
occur, in this case the 1xx status codes are or combined using binary
|
|
||||||
or.
|
|
||||||
|
|
||||||
1100100
|
|
||||||
^^^^
|
|
||||||
|||`- timeout
|
|
||||||
||`-- output hash mismatch
|
|
||||||
|`--- build failure
|
|
||||||
`---- not deterministic
|
|
||||||
|
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
|
||||||
|
@ -99,7 +70,7 @@ This operation is typically used to build [store derivation]s produced by
|
||||||
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -r $(nix-instantiate ./test.nix)
|
$ nix-store --realise $(nix-instantiate ./test.nix)
|
||||||
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
|
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -108,7 +79,7 @@ This is essentially what [`nix-build`](@docroot@/command-ref/nix-build.md) does.
|
||||||
To test whether a previously-built derivation is deterministic:
|
To test whether a previously-built derivation is deterministic:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A hello --check -K
|
$ nix-build '<nixpkgs>' --attr hello --check -K
|
||||||
```
|
```
|
||||||
|
|
||||||
Use [`nix-store --read-log`](./read-log.md) to show the stderr and stdout of a build:
|
Use [`nix-store --read-log`](./read-log.md) to show the stderr and stdout of a build:
|
||||||
|
|
|
@ -24,6 +24,6 @@ path has changed, and 1 otherwise.
|
||||||
To verify the integrity of the `svn` command and all its dependencies:
|
To verify the integrity of the `svn` command and all its dependencies:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --verify-path $(nix-store -qR $(which svn))
|
$ nix-store --verify-path $(nix-store --query --requisites $(which svn))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -162,11 +162,11 @@ Most Nix commands accept the following command-line options:
|
||||||
}: ...
|
}: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
So if you call this Nix expression (e.g., when you do `nix-env -iA
|
So if you call this Nix expression (e.g., when you do `nix-env --install --attr
|
||||||
pkgname`), the function will be called automatically using the
|
pkgname`), the function will be called automatically using the
|
||||||
value [`builtins.currentSystem`](@docroot@/language/builtins.md) for
|
value [`builtins.currentSystem`](@docroot@/language/builtins.md) for
|
||||||
the `system` argument. You can override this using `--arg`, e.g.,
|
the `system` argument. You can override this using `--arg`, e.g.,
|
||||||
`nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
|
`nix-env --install --attr pkgname --arg system \"i686-freebsd\"`. (Note that
|
||||||
since the argument is a Nix string literal, you have to escape the
|
since the argument is a Nix string literal, you have to escape the
|
||||||
quotes.)
|
quotes.)
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ Most Nix commands accept the following command-line options:
|
||||||
For `nix-shell`, this option is commonly used to give you a shell in
|
For `nix-shell`, this option is commonly used to give you a shell in
|
||||||
which you can build the packages returned by the expression. If you
|
which you can build the packages returned by the expression. If you
|
||||||
want to get a shell which contain the *built* packages ready for
|
want to get a shell which contain the *built* packages ready for
|
||||||
use, give your expression to the `nix-shell -p` convenience flag
|
use, give your expression to the `nix-shell --packages ` convenience flag
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
- <span id="opt-I">[`-I`](#opt-I)</span> *path*\
|
- <span id="opt-I">[`-I`](#opt-I)</span> *path*\
|
||||||
|
|
34
doc/manual/src/command-ref/status-build-failure.md
Normal file
34
doc/manual/src/command-ref/status-build-failure.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Special exit codes for build failure
|
||||||
|
|
||||||
|
1xx status codes are used when requested builds failed.
|
||||||
|
The following codes are in use:
|
||||||
|
|
||||||
|
- `100` Generic build failure
|
||||||
|
|
||||||
|
The builder process returned with a non-zero exit code.
|
||||||
|
|
||||||
|
- `101` Build timeout
|
||||||
|
|
||||||
|
The build was aborted because it did not complete within the specified `timeout`.
|
||||||
|
|
||||||
|
- `102` Hash mismatch
|
||||||
|
|
||||||
|
The build output was rejected because it does not match the
|
||||||
|
[`outputHash` attribute of the derivation](@docroot@/language/advanced-attributes.md).
|
||||||
|
|
||||||
|
- `104` Not deterministic
|
||||||
|
|
||||||
|
The build succeeded in check mode but the resulting output is not binary reproducible.
|
||||||
|
|
||||||
|
With the `--keep-going` flag it's possible for multiple failures to occur.
|
||||||
|
In this case the 1xx status codes are or combined using
|
||||||
|
[bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation#OR).
|
||||||
|
|
||||||
|
```
|
||||||
|
0b1100100
|
||||||
|
^^^^
|
||||||
|
|||`- timeout
|
||||||
|
||`-- output hash mismatch
|
||||||
|
|`--- build failure
|
||||||
|
`---- not deterministic
|
||||||
|
```
|
28
doc/manual/src/contributing/cxx.md
Normal file
28
doc/manual/src/contributing/cxx.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# C++ style guide
|
||||||
|
|
||||||
|
Some miscellaneous notes on how we write C++.
|
||||||
|
Formatting we hope to eventually normalize automatically, so this section is free to just discuss higher-level concerns.
|
||||||
|
|
||||||
|
## The `*-impl.hh` pattern
|
||||||
|
|
||||||
|
Let's start with some background info first.
|
||||||
|
Headers, are supposed to contain declarations, not definitions.
|
||||||
|
This allows us to change a definition without changing the declaration, and have a very small rebuild during development.
|
||||||
|
Templates, however, need to be specialized to use-sites.
|
||||||
|
Absent fancier techniques, templates require that the definition, not just mere declaration, must be available at use-sites in order to make that specialization on the fly as part of compiling those use-sites.
|
||||||
|
Making definitions available like that means putting them in headers, but that is unfortunately means we get all the extra rebuilds we want to avoid by just putting declarations there as described above.
|
||||||
|
|
||||||
|
The `*-impl.hh` pattern is a ham-fisted partial solution to this problem.
|
||||||
|
It constitutes:
|
||||||
|
|
||||||
|
- Declaring items only in the main `foo.hh`, including templates.
|
||||||
|
|
||||||
|
- Putting template definitions in a companion `foo-impl.hh` header.
|
||||||
|
|
||||||
|
Most C++ developers would accompany this by having `foo.hh` include `foo-impl.hh`, to ensure any file getting the template declarations also got the template definitions.
|
||||||
|
But we've found not doing this has some benefits and fewer than imagined downsides.
|
||||||
|
The fact remains that headers are rarely as minimal as they could be;
|
||||||
|
there is often code that needs declarations from the headers but not the templates within them.
|
||||||
|
With our pattern where `foo.hh` doesn't include `foo-impl.hh`, that means they can just include `foo.hh`
|
||||||
|
Code that needs both just includes `foo.hh` and `foo-impl.hh`.
|
||||||
|
This does make linking error possible where something forgets to include `foo-impl.hh` that needs it, but those are build-time only as easy to fix.
|
|
@ -12,14 +12,15 @@ The following instructions assume you already have some version of Nix installed
|
||||||
|
|
||||||
[installation instructions]: ../installation/installation.md
|
[installation instructions]: ../installation/installation.md
|
||||||
|
|
||||||
## Nix with flakes
|
## Building Nix with flakes
|
||||||
|
|
||||||
This section assumes you are using Nix with [flakes] enabled. See the [next section](#classic-nix) for equivalent instructions which don't require flakes.
|
This section assumes you are using Nix with the [`flakes`] and [`nix-command`] experimental features enabled.
|
||||||
|
See the [Building Nix](#building-nix) section for equivalent instructions using stable Nix interfaces.
|
||||||
|
|
||||||
[flakes]: ../command-ref/new-cli/nix3-flake.md#description
|
[`flakes`]: @docroot@/contributing/experimental-features.md#xp-feature-flakes
|
||||||
|
[`nix-command`]: @docroot@/contributing/experimental-features.md#xp-nix-command
|
||||||
|
|
||||||
To build all dependencies and start a shell in which all environment
|
To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:
|
||||||
variables are set up so that those dependencies can be found:
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix develop
|
$ nix develop
|
||||||
|
@ -55,20 +56,17 @@ To install it in `$(pwd)/outputs` and test it:
|
||||||
nix (Nix) 2.12
|
nix (Nix) 2.12
|
||||||
```
|
```
|
||||||
|
|
||||||
To build a release version of Nix:
|
To build a release version of Nix for the current operating system and CPU architecture:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix build
|
$ nix build
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build Nix for one of the [supported target platforms](#target-platforms).
|
You can also build Nix for one of the [supported platforms](#platforms).
|
||||||
|
|
||||||
## Classic Nix
|
## Building Nix
|
||||||
|
|
||||||
This section is for Nix without [flakes].
|
To build all dependencies and start a shell in which all environment variables are set up so that those dependencies can be found:
|
||||||
|
|
||||||
To build all dependencies and start a shell in which all environment
|
|
||||||
variables are set up so that those dependencies can be found:
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell
|
$ nix-shell
|
||||||
|
@ -77,7 +75,7 @@ $ nix-shell
|
||||||
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -A devShells.x86_64-linux.native-clang11StdenvPackages
|
$ nix-shell --attr devShells.x86_64-linux.native-clang11StdenvPackages
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
|
@ -102,13 +100,13 @@ To install it in `$(pwd)/outputs` and test it:
|
||||||
nix (Nix) 2.12
|
nix (Nix) 2.12
|
||||||
```
|
```
|
||||||
|
|
||||||
To build Nix for the current operating system and CPU architecture use
|
To build a release version of Nix for the current operating system and CPU architecture:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build
|
$ nix-build
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build Nix for one of the [supported target platforms](#target-platforms).
|
You can also build Nix for one of the [supported platforms](#platforms).
|
||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
|
|
||||||
|
@ -139,7 +137,7 @@ $ nix build .#packages.aarch64-linux.default
|
||||||
for flake-enabled Nix, or
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -A packages.aarch64-linux.default
|
$ nix-build --attr packages.aarch64-linux.default
|
||||||
```
|
```
|
||||||
|
|
||||||
for classic Nix.
|
for classic Nix.
|
||||||
|
@ -166,7 +164,7 @@ $ nix build .#nix-ccacheStdenv
|
||||||
for flake-enabled Nix, or
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -A nix-ccacheStdenv
|
$ nix-build --attr nix-ccacheStdenv
|
||||||
```
|
```
|
||||||
|
|
||||||
for classic Nix.
|
for classic Nix.
|
||||||
|
@ -192,171 +190,6 @@ Configure your editor to use the `clangd` from the shell, either by running it i
|
||||||
> Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs and [vim-lsp](https://github.com/prabirshrestha/vim-lsp) for vim).
|
> Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs and [vim-lsp](https://github.com/prabirshrestha/vim-lsp) for vim).
|
||||||
> Editor-specific setup is typically opinionated, so we will not cover it here in more detail.
|
> Editor-specific setup is typically opinionated, so we will not cover it here in more detail.
|
||||||
|
|
||||||
## Running tests
|
|
||||||
|
|
||||||
### Unit-tests
|
|
||||||
|
|
||||||
The unit-tests for each Nix library (`libexpr`, `libstore`, etc..) are defined
|
|
||||||
under `src/{library_name}/tests` using the
|
|
||||||
[googletest](https://google.github.io/googletest/) and
|
|
||||||
[rapidcheck](https://github.com/emil-e/rapidcheck) frameworks.
|
|
||||||
|
|
||||||
You can run the whole testsuite with `make check`, or the tests for a specific component with `make libfoo-tests_RUN`. Finer-grained filtering is also possible using the [--gtest_filter](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) command-line option.
|
|
||||||
|
|
||||||
### Functional tests
|
|
||||||
|
|
||||||
The functional tests reside under the `tests` directory and are listed in `tests/local.mk`.
|
|
||||||
Each test is a bash script.
|
|
||||||
|
|
||||||
The whole test suite can be run with:
|
|
||||||
|
|
||||||
```shell-session
|
|
||||||
$ make install && make installcheck
|
|
||||||
ran test tests/foo.sh... [PASS]
|
|
||||||
ran test tests/bar.sh... [PASS]
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Individual tests can be run with `make`:
|
|
||||||
|
|
||||||
```shell-session
|
|
||||||
$ make tests/${testName}.sh.test
|
|
||||||
ran test tests/${testName}.sh... [PASS]
|
|
||||||
```
|
|
||||||
|
|
||||||
or without `make`:
|
|
||||||
|
|
||||||
```shell-session
|
|
||||||
$ ./mk/run-test.sh tests/${testName}.sh
|
|
||||||
ran test tests/${testName}.sh... [PASS]
|
|
||||||
```
|
|
||||||
|
|
||||||
To see the complete output, one can also run:
|
|
||||||
|
|
||||||
```shell-session
|
|
||||||
$ ./mk/debug-test.sh tests/${testName}.sh
|
|
||||||
+ foo
|
|
||||||
output from foo
|
|
||||||
+ bar
|
|
||||||
output from bar
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
The test script will then be traced with `set -x` and the output displayed as it happens, regardless of whether the test succeeds or fails.
|
|
||||||
|
|
||||||
#### Debugging failing functional tests
|
|
||||||
|
|
||||||
When a functional test fails, it usually does so somewhere in the middle of the script.
|
|
||||||
|
|
||||||
To figure out what's wrong, it is convenient to run the test regularly up to the failing `nix` command, and then run that command with a debugger like GDB.
|
|
||||||
|
|
||||||
For example, if the script looks like:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
foo
|
|
||||||
nix blah blub
|
|
||||||
bar
|
|
||||||
```
|
|
||||||
edit it like so:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
foo
|
|
||||||
-nix blah blub
|
|
||||||
+gdb --args nix blah blub
|
|
||||||
bar
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, running the test with `./mk/debug-test.sh` will drop you into GDB once the script reaches that point:
|
|
||||||
|
|
||||||
```shell-session
|
|
||||||
$ ./mk/debug-test.sh tests/${testName}.sh
|
|
||||||
...
|
|
||||||
+ gdb blash blub
|
|
||||||
GNU gdb (GDB) 12.1
|
|
||||||
...
|
|
||||||
(gdb)
|
|
||||||
```
|
|
||||||
|
|
||||||
One can debug the Nix invocation in all the usual ways.
|
|
||||||
For example, enter `run` to start the Nix invocation.
|
|
||||||
|
|
||||||
### Integration tests
|
|
||||||
|
|
||||||
The integration tests are defined in the Nix flake under the `hydraJobs.tests` attribute.
|
|
||||||
These tests include everything that needs to interact with external services or run Nix in a non-trivial distributed setup.
|
|
||||||
Because these tests are expensive and require more than what the standard github-actions setup provides, they only run on the master branch (on <https://hydra.nixos.org/jobset/nix/master>).
|
|
||||||
|
|
||||||
You can run them manually with `nix build .#hydraJobs.tests.{testName}` or `nix-build -A hydraJobs.tests.{testName}`
|
|
||||||
|
|
||||||
### Installer tests
|
|
||||||
|
|
||||||
After a one-time setup, the Nix repository's GitHub Actions continuous integration (CI) workflow can test the installer each time you push to a branch.
|
|
||||||
|
|
||||||
Creating a Cachix cache for your installer tests and adding its authorization token to GitHub enables [two installer-specific jobs in the CI workflow](https://github.com/NixOS/nix/blob/88a45d6149c0e304f6eb2efcc2d7a4d0d569f8af/.github/workflows/ci.yml#L50-L91):
|
|
||||||
|
|
||||||
- The `installer` job generates installers for the platforms below and uploads them to your Cachix cache:
|
|
||||||
- `x86_64-linux`
|
|
||||||
- `armv6l-linux`
|
|
||||||
- `armv7l-linux`
|
|
||||||
- `x86_64-darwin`
|
|
||||||
|
|
||||||
- The `installer_test` job (which runs on `ubuntu-latest` and `macos-latest`) will try to install Nix with the cached installer and run a trivial Nix command.
|
|
||||||
|
|
||||||
#### One-time setup
|
|
||||||
|
|
||||||
1. Have a GitHub account with a fork of the [Nix repository](https://github.com/NixOS/nix).
|
|
||||||
2. At cachix.org:
|
|
||||||
- Create or log in to an account.
|
|
||||||
- Create a Cachix cache using the format `<github-username>-nix-install-tests`.
|
|
||||||
- Navigate to the new cache > Settings > Auth Tokens.
|
|
||||||
- Generate a new Cachix auth token and copy the generated value.
|
|
||||||
3. At github.com:
|
|
||||||
- Navigate to your Nix fork > Settings > Secrets > Actions > New repository secret.
|
|
||||||
- Name the secret `CACHIX_AUTH_TOKEN`.
|
|
||||||
- Paste the copied value of the Cachix cache auth token.
|
|
||||||
|
|
||||||
#### Using the CI-generated installer for manual testing
|
|
||||||
|
|
||||||
After the CI run completes, you can check the output to extract the installer URL:
|
|
||||||
1. Click into the detailed view of the CI run.
|
|
||||||
2. Click into any `installer_test` run (the URL you're here to extract will be the same in all of them).
|
|
||||||
3. Click into the `Run cachix/install-nix-action@v...` step and click the detail triangle next to the first log line (it will also be `Run cachix/install-nix-action@v...`)
|
|
||||||
4. Copy the value of `install_url`
|
|
||||||
5. To generate an install command, plug this `install_url` and your GitHub username into this template:
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -L <install_url> | sh -s -- --tarball-url-prefix https://<github-username>-nix-install-tests.cachix.org/serve
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- #### Manually generating test installers
|
|
||||||
|
|
||||||
There's obviously a manual way to do this, and it's still the only way for
|
|
||||||
platforms that lack GA runners.
|
|
||||||
|
|
||||||
I did do this back in Fall 2020 (before the GA approach encouraged here). I'll
|
|
||||||
sketch what I recall in case it encourages someone to fill in detail, but: I
|
|
||||||
didn't know what I was doing at the time and had to fumble/ask around a lot--
|
|
||||||
so I don't want to uphold any of it as "right". It may have been dumb or
|
|
||||||
the _hard_ way from the getgo. Fundamentals may have changed since.
|
|
||||||
|
|
||||||
Here's the build command I used to do this on and for x86_64-darwin:
|
|
||||||
nix build --out-link /tmp/foo ".#checks.x86_64-darwin.binaryTarball"
|
|
||||||
|
|
||||||
I used the stable out-link to make it easier to script the next steps:
|
|
||||||
link=$(readlink /tmp/foo)
|
|
||||||
cp $link/*-darwin.tar.xz ~/somewheres
|
|
||||||
|
|
||||||
I've lost the last steps and am just going from memory:
|
|
||||||
|
|
||||||
From here, I think I had to extract and modify the `install` script to point
|
|
||||||
it at this tarball (which I scped to my own site, but it might make more sense
|
|
||||||
to just share them locally). I extracted this script once and then just
|
|
||||||
search/replaced in it for each new build.
|
|
||||||
|
|
||||||
The installer now supports a `--tarball-url-prefix` flag which _may_ have
|
|
||||||
solved this need?
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Checking links in the manual
|
### Checking links in the manual
|
||||||
|
|
||||||
The build checks for broken internal links.
|
The build checks for broken internal links.
|
||||||
|
@ -378,7 +211,7 @@ rm $(git ls-files doc/manual/ -o | grep -F '.md') && rmdir doc/manual/src/comman
|
||||||
[`mdbook-linkcheck`] does not implement checking [URI fragments] yet.
|
[`mdbook-linkcheck`] does not implement checking [URI fragments] yet.
|
||||||
|
|
||||||
[`mdbook-linkcheck`]: https://github.com/Michael-F-Bryan/mdbook-linkcheck
|
[`mdbook-linkcheck`]: https://github.com/Michael-F-Bryan/mdbook-linkcheck
|
||||||
[URI fragments]: https://en.m.wikipedia.org/wiki/URI_fragment
|
[URI fragments]: https://en.wikipedia.org/wiki/URI_fragment
|
||||||
|
|
||||||
#### `@docroot@` variable
|
#### `@docroot@` variable
|
||||||
|
|
||||||
|
|
167
doc/manual/src/contributing/testing.md
Normal file
167
doc/manual/src/contributing/testing.md
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
# Running tests
|
||||||
|
|
||||||
|
## Unit-tests
|
||||||
|
|
||||||
|
The unit-tests for each Nix library (`libexpr`, `libstore`, etc..) are defined
|
||||||
|
under `src/{library_name}/tests` using the
|
||||||
|
[googletest](https://google.github.io/googletest/) and
|
||||||
|
[rapidcheck](https://github.com/emil-e/rapidcheck) frameworks.
|
||||||
|
|
||||||
|
You can run the whole testsuite with `make check`, or the tests for a specific component with `make libfoo-tests_RUN`. Finer-grained filtering is also possible using the [--gtest_filter](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) command-line option.
|
||||||
|
|
||||||
|
## Functional tests
|
||||||
|
|
||||||
|
The functional tests reside under the `tests` directory and are listed in `tests/local.mk`.
|
||||||
|
Each test is a bash script.
|
||||||
|
|
||||||
|
The whole test suite can be run with:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ make install && make installcheck
|
||||||
|
ran test tests/foo.sh... [PASS]
|
||||||
|
ran test tests/bar.sh... [PASS]
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Individual tests can be run with `make`:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ make tests/${testName}.sh.test
|
||||||
|
ran test tests/${testName}.sh... [PASS]
|
||||||
|
```
|
||||||
|
|
||||||
|
or without `make`:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ ./mk/run-test.sh tests/${testName}.sh
|
||||||
|
ran test tests/${testName}.sh... [PASS]
|
||||||
|
```
|
||||||
|
|
||||||
|
To see the complete output, one can also run:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ ./mk/debug-test.sh tests/${testName}.sh
|
||||||
|
+ foo
|
||||||
|
output from foo
|
||||||
|
+ bar
|
||||||
|
output from bar
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
The test script will then be traced with `set -x` and the output displayed as it happens, regardless of whether the test succeeds or fails.
|
||||||
|
|
||||||
|
### Debugging failing functional tests
|
||||||
|
|
||||||
|
When a functional test fails, it usually does so somewhere in the middle of the script.
|
||||||
|
|
||||||
|
To figure out what's wrong, it is convenient to run the test regularly up to the failing `nix` command, and then run that command with a debugger like GDB.
|
||||||
|
|
||||||
|
For example, if the script looks like:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
foo
|
||||||
|
nix blah blub
|
||||||
|
bar
|
||||||
|
```
|
||||||
|
edit it like so:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
foo
|
||||||
|
-nix blah blub
|
||||||
|
+gdb --args nix blah blub
|
||||||
|
bar
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, running the test with `./mk/debug-test.sh` will drop you into GDB once the script reaches that point:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ ./mk/debug-test.sh tests/${testName}.sh
|
||||||
|
...
|
||||||
|
+ gdb blash blub
|
||||||
|
GNU gdb (GDB) 12.1
|
||||||
|
...
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
|
|
||||||
|
One can debug the Nix invocation in all the usual ways.
|
||||||
|
For example, enter `run` to start the Nix invocation.
|
||||||
|
|
||||||
|
## Integration tests
|
||||||
|
|
||||||
|
The integration tests are defined in the Nix flake under the `hydraJobs.tests` attribute.
|
||||||
|
These tests include everything that needs to interact with external services or run Nix in a non-trivial distributed setup.
|
||||||
|
Because these tests are expensive and require more than what the standard github-actions setup provides, they only run on the master branch (on <https://hydra.nixos.org/jobset/nix/master>).
|
||||||
|
|
||||||
|
You can run them manually with `nix build .#hydraJobs.tests.{testName}` or `nix-build -A hydraJobs.tests.{testName}`
|
||||||
|
|
||||||
|
## Installer tests
|
||||||
|
|
||||||
|
After a one-time setup, the Nix repository's GitHub Actions continuous integration (CI) workflow can test the installer each time you push to a branch.
|
||||||
|
|
||||||
|
Creating a Cachix cache for your installer tests and adding its authorization token to GitHub enables [two installer-specific jobs in the CI workflow](https://github.com/NixOS/nix/blob/88a45d6149c0e304f6eb2efcc2d7a4d0d569f8af/.github/workflows/ci.yml#L50-L91):
|
||||||
|
|
||||||
|
- The `installer` job generates installers for the platforms below and uploads them to your Cachix cache:
|
||||||
|
- `x86_64-linux`
|
||||||
|
- `armv6l-linux`
|
||||||
|
- `armv7l-linux`
|
||||||
|
- `x86_64-darwin`
|
||||||
|
|
||||||
|
- The `installer_test` job (which runs on `ubuntu-latest` and `macos-latest`) will try to install Nix with the cached installer and run a trivial Nix command.
|
||||||
|
|
||||||
|
### One-time setup
|
||||||
|
|
||||||
|
1. Have a GitHub account with a fork of the [Nix repository](https://github.com/NixOS/nix).
|
||||||
|
2. At cachix.org:
|
||||||
|
- Create or log in to an account.
|
||||||
|
- Create a Cachix cache using the format `<github-username>-nix-install-tests`.
|
||||||
|
- Navigate to the new cache > Settings > Auth Tokens.
|
||||||
|
- Generate a new Cachix auth token and copy the generated value.
|
||||||
|
3. At github.com:
|
||||||
|
- Navigate to your Nix fork > Settings > Secrets > Actions > New repository secret.
|
||||||
|
- Name the secret `CACHIX_AUTH_TOKEN`.
|
||||||
|
- Paste the copied value of the Cachix cache auth token.
|
||||||
|
|
||||||
|
## Working on documentation
|
||||||
|
|
||||||
|
### Using the CI-generated installer for manual testing
|
||||||
|
|
||||||
|
After the CI run completes, you can check the output to extract the installer URL:
|
||||||
|
1. Click into the detailed view of the CI run.
|
||||||
|
2. Click into any `installer_test` run (the URL you're here to extract will be the same in all of them).
|
||||||
|
3. Click into the `Run cachix/install-nix-action@v...` step and click the detail triangle next to the first log line (it will also be `Run cachix/install-nix-action@v...`)
|
||||||
|
4. Copy the value of `install_url`
|
||||||
|
5. To generate an install command, plug this `install_url` and your GitHub username into this template:
|
||||||
|
|
||||||
|
```console
|
||||||
|
curl -L <install_url> | sh -s -- --tarball-url-prefix https://<github-username>-nix-install-tests.cachix.org/serve
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- #### Manually generating test installers
|
||||||
|
|
||||||
|
There's obviously a manual way to do this, and it's still the only way for
|
||||||
|
platforms that lack GA runners.
|
||||||
|
|
||||||
|
I did do this back in Fall 2020 (before the GA approach encouraged here). I'll
|
||||||
|
sketch what I recall in case it encourages someone to fill in detail, but: I
|
||||||
|
didn't know what I was doing at the time and had to fumble/ask around a lot--
|
||||||
|
so I don't want to uphold any of it as "right". It may have been dumb or
|
||||||
|
the _hard_ way from the getgo. Fundamentals may have changed since.
|
||||||
|
|
||||||
|
Here's the build command I used to do this on and for x86_64-darwin:
|
||||||
|
nix build --out-link /tmp/foo ".#checks.x86_64-darwin.binaryTarball"
|
||||||
|
|
||||||
|
I used the stable out-link to make it easier to script the next steps:
|
||||||
|
link=$(readlink /tmp/foo)
|
||||||
|
cp $link/*-darwin.tar.xz ~/somewheres
|
||||||
|
|
||||||
|
I've lost the last steps and am just going from memory:
|
||||||
|
|
||||||
|
From here, I think I had to extract and modify the `install` script to point
|
||||||
|
it at this tarball (which I scped to my own site, but it might make more sense
|
||||||
|
to just share them locally). I extracted this script once and then just
|
||||||
|
search/replaced in it for each new build.
|
||||||
|
|
||||||
|
The installer now supports a `--tarball-url-prefix` flag which _may_ have
|
||||||
|
solved this need?
|
||||||
|
-->
|
||||||
|
|
|
@ -85,12 +85,17 @@
|
||||||
|
|
||||||
[store path]: #gloss-store-path
|
[store path]: #gloss-store-path
|
||||||
|
|
||||||
|
- [file system object]{#gloss-store-object}\
|
||||||
|
The Nix data model for representing simplified file system data.
|
||||||
|
|
||||||
|
See [File System Object](@docroot@/architecture/file-system-object.md) for details.
|
||||||
|
|
||||||
|
[file system object]: #gloss-file-system-object
|
||||||
|
|
||||||
- [store object]{#gloss-store-object}\
|
- [store object]{#gloss-store-object}\
|
||||||
A file that is an immediate child of the Nix store directory. These
|
|
||||||
can be regular files, but also entire directory trees. Store objects
|
A store object consists of a [file system object], [reference]s to other store objects, and other metadata.
|
||||||
can be sources (objects copied from outside of the store),
|
It can be referred to by a [store path].
|
||||||
derivation outputs (objects produced by running a build task), or
|
|
||||||
derivations (files describing a build task).
|
|
||||||
|
|
||||||
[store object]: #gloss-store-object
|
[store object]: #gloss-store-object
|
||||||
|
|
||||||
|
@ -101,11 +106,8 @@
|
||||||
derivation.
|
derivation.
|
||||||
|
|
||||||
- [output-addressed store object]{#gloss-output-addressed-store-object}\
|
- [output-addressed store object]{#gloss-output-addressed-store-object}\
|
||||||
A store object whose store path hashes its content. This
|
A [store object] whose [store path] is determined by its contents.
|
||||||
includes derivations, the outputs of
|
This includes derivations, the outputs of [content-addressed derivations](#gloss-content-addressed-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
|
||||||
[content-addressed derivations](#gloss-content-addressed-derivation),
|
|
||||||
and the outputs of
|
|
||||||
[fixed-output derivations](#gloss-fixed-output-derivation).
|
|
||||||
|
|
||||||
- [substitute]{#gloss-substitute}\
|
- [substitute]{#gloss-substitute}\
|
||||||
A substitute is a command invocation stored in the [Nix database] that
|
A substitute is a command invocation stored in the [Nix database] that
|
||||||
|
@ -115,9 +117,10 @@
|
||||||
from some server.
|
from some server.
|
||||||
|
|
||||||
- [substituter]{#gloss-substituter}\
|
- [substituter]{#gloss-substituter}\
|
||||||
A *substituter* is an additional store from which Nix will
|
An additional [store]{#gloss-store} from which Nix can obtain store objects instead of building them.
|
||||||
copy store objects it doesn't have. For details, see the
|
Often the substituter is a [binary cache](#gloss-binary-cache), but any store can serve as substituter.
|
||||||
[`substituters` option](./command-ref/conf-file.md#conf-substituters).
|
|
||||||
|
See the [`substituters` configuration option](./command-ref/conf-file.md#conf-substituters) for details.
|
||||||
|
|
||||||
[substituter]: #gloss-substituter
|
[substituter]: #gloss-substituter
|
||||||
|
|
||||||
|
@ -163,7 +166,7 @@
|
||||||
build-time dependencies, while the closure of its output path is
|
build-time dependencies, while the closure of its output path is
|
||||||
equivalent to its runtime dependencies. For correct deployment it
|
equivalent to its runtime dependencies. For correct deployment it
|
||||||
is necessary to deploy whole closures, since otherwise at runtime
|
is necessary to deploy whole closures, since otherwise at runtime
|
||||||
files could be missing. The command `nix-store -qR` prints out
|
files could be missing. The command `nix-store --query --requisites ` prints out
|
||||||
closures of store paths.
|
closures of store paths.
|
||||||
|
|
||||||
As an example, if the [store object] at path `P` contains a [reference]
|
As an example, if the [store object] at path `P` contains a [reference]
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
- Bash Shell. The `./configure` script relies on bashisms, so Bash is
|
- Bash Shell. The `./configure` script relies on bashisms, so Bash is
|
||||||
required.
|
required.
|
||||||
|
|
||||||
- A version of GCC or Clang that supports C++17.
|
- A version of GCC or Clang that supports C++20.
|
||||||
|
|
||||||
- `pkg-config` to locate dependencies. If your distribution does not
|
- `pkg-config` to locate dependencies. If your distribution does not
|
||||||
provide it, you can get it from
|
provide it, you can get it from
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
Multi-user Nix users on macOS can upgrade Nix by running: `sudo -i sh -c
|
Multi-user Nix users on macOS can upgrade Nix by running: `sudo -i sh -c
|
||||||
'nix-channel --update &&
|
'nix-channel --update &&
|
||||||
nix-env -iA nixpkgs.nix &&
|
nix-env --install --attr nixpkgs.nix &&
|
||||||
launchctl remove org.nixos.nix-daemon &&
|
launchctl remove org.nixos.nix-daemon &&
|
||||||
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'`
|
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'`
|
||||||
|
|
||||||
Single-user installations of Nix should run this: `nix-channel --update;
|
Single-user installations of Nix should run this: `nix-channel --update;
|
||||||
nix-env -iA nixpkgs.nix nixpkgs.cacert`
|
nix-env --install --attr nixpkgs.nix nixpkgs.cacert`
|
||||||
|
|
||||||
Multi-user Nix users on Linux should run this with sudo: `nix-channel
|
Multi-user Nix users on Linux should run this with sudo: `nix-channel
|
||||||
--update; nix-env -iA nixpkgs.nix nixpkgs.cacert; systemctl
|
--update; nix-env --install --attr nixpkgs.nix nixpkgs.cacert; systemctl
|
||||||
daemon-reload; systemctl restart nix-daemon`
|
daemon-reload; systemctl restart nix-daemon`
|
||||||
|
|
|
@ -76,7 +76,7 @@ there after an upgrade. This means that you can _roll back_ to the
|
||||||
old version:
|
old version:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.some-package
|
$ nix-env --upgrade --attr nixpkgs.some-package
|
||||||
$ nix-env --rollback
|
$ nix-env --rollback
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ Nix expressions generally describe how to build a package from
|
||||||
source, so an installation action like
|
source, so an installation action like
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --install -A nixpkgs.firefox
|
$ nix-env --install --attr nixpkgs.firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
_could_ cause quite a bit of build activity, as not only Firefox but
|
_could_ cause quite a bit of build activity, as not only Firefox but
|
||||||
|
@ -158,7 +158,7 @@ Pan newsreader, as described by [its
|
||||||
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
|
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan
|
$ nix-shell '<nixpkgs>' --attr pan
|
||||||
```
|
```
|
||||||
|
|
||||||
You’re then dropped into a shell where you can edit, build and test
|
You’re then dropped into a shell where you can edit, build and test
|
||||||
|
|
5
doc/manual/src/language/builtin-constants-prefix.md
Normal file
5
doc/manual/src/language/builtin-constants-prefix.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Built-in Constants
|
||||||
|
|
||||||
|
These constants are built into the Nix language evaluator:
|
||||||
|
|
||||||
|
<dl>
|
1
doc/manual/src/language/builtin-constants-suffix.md
Normal file
1
doc/manual/src/language/builtin-constants-suffix.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
</dl>
|
|
@ -1,19 +0,0 @@
|
||||||
# Built-in Constants
|
|
||||||
|
|
||||||
These constants are built into the Nix language evaluator:
|
|
||||||
|
|
||||||
- [`builtins`]{#builtins-builtins} (attribute set)
|
|
||||||
|
|
||||||
Contains all the [built-in functions](./builtins.md) and values, in order to avoid polluting the global scope.
|
|
||||||
|
|
||||||
Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
if builtins ? getEnv then builtins.getEnv "PATH" else ""
|
|
||||||
```
|
|
||||||
|
|
||||||
- [`builtins.currentSystem`]{#builtins-currentSystem} (string)
|
|
||||||
|
|
||||||
The built-in value `currentSystem` evaluates to the Nix platform
|
|
||||||
identifier for the Nix installation on which the expression is being
|
|
||||||
evaluated, such as `"i686-linux"` or `"x86_64-darwin"`.
|
|
|
@ -3,7 +3,7 @@
|
||||||
This section lists the functions built into the Nix language evaluator.
|
This section lists the functions built into the Nix language evaluator.
|
||||||
All built-in functions are available through the global [`builtins`](./builtin-constants.md#builtins-builtins) constant.
|
All built-in functions are available through the global [`builtins`](./builtin-constants.md#builtins-builtins) constant.
|
||||||
|
|
||||||
For convenience, some built-ins are can be accessed directly:
|
For convenience, some built-ins can be accessed directly:
|
||||||
|
|
||||||
- [`derivation`](#builtins-derivation)
|
- [`derivation`](#builtins-derivation)
|
||||||
- [`import`](#builtins-import)
|
- [`import`](#builtins-import)
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
## Recursive sets
|
## Recursive sets
|
||||||
|
|
||||||
Recursive sets are just normal sets, but the attributes can refer to
|
Recursive sets are like normal [attribute sets](./values.md#attribute-set), but the attributes can refer to each other.
|
||||||
each other. For example,
|
|
||||||
|
> *rec-attrset* = `rec {` [ *name* `=` *expr* `;` `]`... `}`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
rec {
|
rec {
|
||||||
|
@ -12,7 +15,9 @@ rec {
|
||||||
}.x
|
}.x
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `123`. Note that without `rec` the binding `x = y;` would
|
This evaluates to `123`.
|
||||||
|
|
||||||
|
Note that without `rec` the binding `x = y;` would
|
||||||
refer to the variable `y` in the surrounding scope, if one exists, and
|
refer to the variable `y` in the surrounding scope, if one exists, and
|
||||||
would be invalid if no such variable exists. That is, in a normal
|
would be invalid if no such variable exists. That is, in a normal
|
||||||
(non-recursive) set, attributes are not added to the lexical scope; in a
|
(non-recursive) set, attributes are not added to the lexical scope; in a
|
||||||
|
@ -33,7 +38,10 @@ will crash with an `infinite recursion encountered` error message.
|
||||||
## Let-expressions
|
## Let-expressions
|
||||||
|
|
||||||
A let-expression allows you to define local variables for an expression.
|
A let-expression allows you to define local variables for an expression.
|
||||||
For instance,
|
|
||||||
|
> *let-in* = `let` [ *identifier* = *expr* ]... `in` *expr*
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let
|
let
|
||||||
|
@ -42,18 +50,19 @@ let
|
||||||
in x + y
|
in x + y
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `"foobar"`.
|
This evaluates to `"foobar"`.
|
||||||
|
|
||||||
## Inheriting attributes
|
## Inheriting attributes
|
||||||
|
|
||||||
When defining a set or in a let-expression it is often convenient to
|
When defining an [attribute set](./values.md#attribute-set) or in a [let-expression](#let-expressions) it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes).
|
||||||
copy variables from the surrounding lexical scope (e.g., when you want
|
This can be shortened using the `inherit` keyword.
|
||||||
to propagate attributes). This can be shortened using the `inherit`
|
|
||||||
keyword. For instance,
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let x = 123; in
|
let x = 123; in
|
||||||
{ inherit x;
|
{
|
||||||
|
inherit x;
|
||||||
y = 456;
|
y = 456;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -62,15 +71,23 @@ is equivalent to
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let x = 123; in
|
let x = 123; in
|
||||||
{ x = x;
|
{
|
||||||
|
x = x;
|
||||||
y = 456;
|
y = 456;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
and both evaluate to `{ x = 123; y = 456; }`. (Note that this works
|
and both evaluate to `{ x = 123; y = 456; }`.
|
||||||
because `x` is added to the lexical scope by the `let` construct.) It is
|
|
||||||
also possible to inherit attributes from another set. For instance, in
|
> **Note**
|
||||||
this fragment from `all-packages.nix`,
|
>
|
||||||
|
> This works because `x` is added to the lexical scope by the `let` construct.
|
||||||
|
|
||||||
|
It is also possible to inherit attributes from another attribute set.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
In this fragment from `all-packages.nix`,
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
graphviz = (import ../tools/graphics/graphviz) {
|
graphviz = (import ../tools/graphics/graphviz) {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
# Nix Language
|
# Nix Language
|
||||||
|
|
||||||
The Nix language is
|
The Nix language is designed for conveniently creating and composing *derivations* – precise descriptions of how contents of existing files are used to derive new files.
|
||||||
|
It is:
|
||||||
|
|
||||||
- *domain-specific*
|
- *domain-specific*
|
||||||
|
|
||||||
It only exists for the Nix package manager:
|
It comes with [built-in functions](@docroot@/language/builtins.md) to integrate with the Nix store, which manages files and performs the derivations declared in the Nix language.
|
||||||
to describe packages and configurations as well as their variants and compositions.
|
|
||||||
It is not intended for general purpose use.
|
|
||||||
|
|
||||||
- *declarative*
|
- *declarative*
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ The Nix language is
|
||||||
|
|
||||||
- *lazy*
|
- *lazy*
|
||||||
|
|
||||||
Expressions are only evaluated when their value is needed.
|
Values are only computed when they are needed.
|
||||||
|
|
||||||
- *dynamically typed*
|
- *dynamically typed*
|
||||||
|
|
||||||
|
|
|
@ -35,17 +35,14 @@
|
||||||
|
|
||||||
## Attribute selection
|
## Attribute selection
|
||||||
|
|
||||||
|
> *attrset* `.` *attrpath* \[ `or` *expr* \]
|
||||||
|
|
||||||
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
|
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
|
||||||
If the attribute doesn’t exist, return the *expr* after `or` if provided, otherwise abort evaluation.
|
If the attribute doesn’t exist, return the *expr* after `or` if provided, otherwise abort evaluation.
|
||||||
|
|
||||||
<!-- FIXME: the following should to into its own language syntax section, but that needs more work to fit in well -->
|
An attribute path is a dot-separated list of [attribute names](./values.md#attribute-set).
|
||||||
|
|
||||||
An attribute path is a dot-separated list of attribute names.
|
> *attrpath* = *name* [ `.` *name* ]...
|
||||||
An attribute name can be an identifier or a string.
|
|
||||||
|
|
||||||
> *attrpath* = *name* [ `.` *name* ]... \
|
|
||||||
> *name* = *identifier* | *string* \
|
|
||||||
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
|
|
||||||
|
|
||||||
[Attribute selection]: #attribute-selection
|
[Attribute selection]: #attribute-selection
|
||||||
|
|
||||||
|
|
|
@ -164,9 +164,17 @@ Note that lists are only lazy in values, and they are strict in length.
|
||||||
|
|
||||||
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
||||||
|
|
||||||
|
An attribute name can be an identifier or a [string](#string).
|
||||||
|
An identifier must start with a letter (`a-z`, `A-Z`) or underscore (`_`), and can otherwise contain letters (`a-z`, `A-Z`), numbers (`0-9`), underscores (`_`), apostrophes (`'`), or dashes (`-`).
|
||||||
|
|
||||||
|
> *name* = *identifier* | *string* \
|
||||||
|
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
|
||||||
|
|
||||||
Names and values are separated by an equal sign (`=`).
|
Names and values are separated by an equal sign (`=`).
|
||||||
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
||||||
|
|
||||||
|
> *attrset* = `{` [ *name* `=` *expr* `;` `]`... `}`
|
||||||
|
|
||||||
Attributes can appear in any order.
|
Attributes can appear in any order.
|
||||||
An attribute name may only occur once.
|
An attribute name may only occur once.
|
||||||
|
|
||||||
|
@ -182,15 +190,19 @@ Example:
|
||||||
|
|
||||||
This defines a set with attributes named `x`, `text`, `y`.
|
This defines a set with attributes named `x`, `text`, `y`.
|
||||||
|
|
||||||
Attributes can be selected from a set using the `.` operator. For
|
Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection).
|
||||||
instance,
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ a = "Foo"; b = "Bar"; }.a
|
{ a = "Foo"; b = "Bar"; }.a
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `"Foo"`. It is possible to provide a default value in an
|
This evaluates to `"Foo"`.
|
||||||
attribute selection using the `or` keyword:
|
|
||||||
|
It is possible to provide a default value in an attribute selection using the `or` keyword.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
||||||
|
|
|
@ -47,7 +47,7 @@ $ nix-channel --update
|
||||||
You can view the set of available packages in Nixpkgs:
|
You can view the set of available packages in Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP
|
$ nix-env --query --available --attr-path
|
||||||
nixpkgs.aterm aterm-2.2
|
nixpkgs.aterm aterm-2.2
|
||||||
nixpkgs.bash bash-3.0
|
nixpkgs.bash bash-3.0
|
||||||
nixpkgs.binutils binutils-2.15
|
nixpkgs.binutils binutils-2.15
|
||||||
|
@ -65,7 +65,7 @@ If you downloaded Nixpkgs yourself, or if you checked it out from GitHub,
|
||||||
then you need to pass the path to your Nixpkgs tree using the `-f` flag:
|
then you need to pass the path to your Nixpkgs tree using the `-f` flag:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaPf /path/to/nixpkgs
|
$ nix-env --query --available --attr-path --file /path/to/nixpkgs
|
||||||
aterm aterm-2.2
|
aterm aterm-2.2
|
||||||
bash bash-3.0
|
bash bash-3.0
|
||||||
…
|
…
|
||||||
|
@ -77,7 +77,7 @@ Nixpkgs.
|
||||||
You can filter the packages by name:
|
You can filter the packages by name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP firefox
|
$ nix-env --query --available --attr-path firefox
|
||||||
nixpkgs.firefox-esr firefox-91.3.0esr
|
nixpkgs.firefox-esr firefox-91.3.0esr
|
||||||
nixpkgs.firefox firefox-94.0.1
|
nixpkgs.firefox firefox-94.0.1
|
||||||
```
|
```
|
||||||
|
@ -85,7 +85,7 @@ nixpkgs.firefox firefox-94.0.1
|
||||||
and using regular expressions:
|
and using regular expressions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP 'firefox.*'
|
$ nix-env --query --available --attr-path 'firefox.*'
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to see the *status* of available packages, i.e.,
|
It is also possible to see the *status* of available packages, i.e.,
|
||||||
|
@ -93,7 +93,7 @@ whether they are installed into the user environment and/or present in
|
||||||
the system:
|
the system:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaPs
|
$ nix-env --query --available --attr-path --status
|
||||||
…
|
…
|
||||||
-PS nixpkgs.bash bash-3.0
|
-PS nixpkgs.bash bash-3.0
|
||||||
--S nixpkgs.binutils binutils-2.15
|
--S nixpkgs.binutils binutils-2.15
|
||||||
|
@ -110,10 +110,10 @@ which is Nix’s mechanism for doing binary deployment. It just means that
|
||||||
Nix knows that it can fetch a pre-built package from somewhere
|
Nix knows that it can fetch a pre-built package from somewhere
|
||||||
(typically a network server) instead of building it locally.
|
(typically a network server) instead of building it locally.
|
||||||
|
|
||||||
You can install a package using `nix-env -iA`. For instance,
|
You can install a package using `nix-env --install --attr `. For instance,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion
|
$ nix-env --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
|
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
|
||||||
|
@ -143,14 +143,14 @@ instead of the attribute path, as `nix-env` does not record which attribute
|
||||||
was used for installing:
|
was used for installing:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -e subversion
|
$ nix-env --uninstall subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
Upgrading to a new version is just as easy. If you have a new release of
|
Upgrading to a new version is just as easy. If you have a new release of
|
||||||
Nix Packages, you can do:
|
Nix Packages, you can do:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -uA nixpkgs.subversion
|
$ nix-env --upgrade --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
This will *only* upgrade Subversion if there is a “newer” version in the
|
This will *only* upgrade Subversion if there is a “newer” version in the
|
||||||
|
@ -163,15 +163,15 @@ whatever version is in the Nix expressions, use `-i` instead of `-u`;
|
||||||
You can also upgrade all packages for which there are newer versions:
|
You can also upgrade all packages for which there are newer versions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
Sometimes it’s useful to be able to ask what `nix-env` would do, without
|
Sometimes it’s useful to be able to ask what `nix-env` would do, without
|
||||||
actually doing it. For instance, to find out what packages would be
|
actually doing it. For instance, to find out what packages would be
|
||||||
upgraded by `nix-env -u`, you can do
|
upgraded by `nix-env --upgrade `, you can do
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u --dry-run
|
$ nix-env --upgrade --dry-run
|
||||||
(dry run; not doing anything)
|
(dry run; not doing anything)
|
||||||
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
|
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
|
||||||
upgrading `graphviz-1.10' to `graphviz-1.12'
|
upgrading `graphviz-1.10' to `graphviz-1.12'
|
||||||
|
|
|
@ -9,7 +9,7 @@ The daemon that handles binary cache requests via HTTP, `nix-serve`, is
|
||||||
not part of the Nix distribution, but you can install it from Nixpkgs:
|
not part of the Nix distribution, but you can install it from Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.nix-serve
|
$ nix-env --install --attr nixpkgs.nix-serve
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then start the server, listening for HTTP connections on
|
You can then start the server, listening for HTTP connections on
|
||||||
|
@ -35,7 +35,7 @@ On the client side, you can tell Nix to use your binary cache using
|
||||||
`--substituters`, e.g.:
|
`--substituters`, e.g.:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.firefox --substituters http://avalon:8080/
|
$ nix-env --install --attr nixpkgs.firefox --substituters http://avalon:8080/
|
||||||
```
|
```
|
||||||
|
|
||||||
The option `substituters` tells Nix to use this binary cache in
|
The option `substituters` tells Nix to use this binary cache in
|
||||||
|
|
|
@ -43,7 +43,7 @@ operations (via the symlink `~/.nix-defexpr/channels`). Consequently,
|
||||||
you can then say
|
you can then say
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
to upgrade all packages in your profile to the latest versions available
|
to upgrade all packages in your profile to the latest versions available
|
||||||
|
|
|
@ -15,7 +15,7 @@ With `nix-store
|
||||||
path (that is, the path and all its dependencies) to a file, and then
|
path (that is, the path and all its dependencies) to a file, and then
|
||||||
unpack that file into another Nix store. For example,
|
unpack that file into another Nix store. For example,
|
||||||
|
|
||||||
$ nix-store --export $(nix-store -qR $(type -p firefox)) > firefox.closure
|
$ nix-store --export $(nix-store --query --requisites $(type -p firefox)) > firefox.closure
|
||||||
|
|
||||||
writes the closure of Firefox to a file. You can then copy this file to
|
writes the closure of Firefox to a file. You can then copy this file to
|
||||||
another machine and install the closure:
|
another machine and install the closure:
|
||||||
|
@ -27,7 +27,7 @@ store are ignored. It is also possible to pipe the export into another
|
||||||
command, e.g. to copy and install a closure directly to/on another
|
command, e.g. to copy and install a closure directly to/on another
|
||||||
machine:
|
machine:
|
||||||
|
|
||||||
$ nix-store --export $(nix-store -qR $(type -p firefox)) | bzip2 | \
|
$ nix-store --export $(nix-store --query --requisites $(type -p firefox)) | bzip2 | \
|
||||||
ssh alice@itchy.example.org "bunzip2 | nix-store --import"
|
ssh alice@itchy.example.org "bunzip2 | nix-store --import"
|
||||||
|
|
||||||
However, `nix-copy-closure` is generally more efficient because it only
|
However, `nix-copy-closure` is generally more efficient because it only
|
||||||
|
|
|
@ -39,7 +39,7 @@ just Subversion 1.1.2 (arrows in the figure indicate symlinks). This
|
||||||
would be what we would obtain if we had done
|
would be what we would obtain if we had done
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion
|
$ nix-env --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
on a set of Nix expressions that contained Subversion 1.1.2.
|
on a set of Nix expressions that contained Subversion 1.1.2.
|
||||||
|
@ -54,7 +54,7 @@ environment is generated based on the current one. For instance,
|
||||||
generation 43 was created from generation 42 when we did
|
generation 43 was created from generation 42 when we did
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion nixpkgs.firefox
|
$ nix-env --install --attr nixpkgs.subversion nixpkgs.firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
on a set of Nix expressions that contained Firefox and a new version of
|
on a set of Nix expressions that contained Firefox and a new version of
|
||||||
|
@ -127,7 +127,7 @@ All `nix-env` operations work on the profile pointed to by
|
||||||
(abbreviation `-p`):
|
(abbreviation `-p`):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -p /nix/var/nix/profiles/other-profile -iA nixpkgs.subversion
|
$ nix-env --profile /nix/var/nix/profiles/other-profile --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
This will *not* change the `~/.nix-profile` symlink.
|
This will *not* change the `~/.nix-profile` symlink.
|
||||||
|
|
|
@ -6,7 +6,7 @@ automatically fetching any store paths in Firefox’s closure if they are
|
||||||
available on the server `avalon`:
|
available on the server `avalon`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.firefox --substituters ssh://alice@avalon
|
$ nix-env --install --attr nixpkgs.firefox --substituters ssh://alice@avalon
|
||||||
```
|
```
|
||||||
|
|
||||||
This works similar to the binary cache substituter that Nix usually
|
This works similar to the binary cache substituter that Nix usually
|
||||||
|
@ -25,7 +25,7 @@ You can also copy the closure of some store path, without installing it
|
||||||
into your profile, e.g.
|
into your profile, e.g.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -r /nix/store/m85bxg…-firefox-34.0.5 --substituters
|
$ nix-store --realise /nix/store/m85bxg…-firefox-34.0.5 --substituters
|
||||||
ssh://alice@avalon
|
ssh://alice@avalon
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
4
doc/manual/src/protocols/protocols.md
Normal file
4
doc/manual/src/protocols/protocols.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Protocols
|
||||||
|
|
||||||
|
This chapter documents various developer-facing interfaces provided by
|
||||||
|
Nix.
|
42
doc/manual/src/protocols/tarball-fetcher.md
Normal file
42
doc/manual/src/protocols/tarball-fetcher.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# Lockable HTTP Tarball Protocol
|
||||||
|
|
||||||
|
Tarball flakes can be served as regular tarballs via HTTP or the file
|
||||||
|
system (for `file://` URLs). Unless the server implements the Lockable
|
||||||
|
HTTP Tarball protocol, it is the responsibility of the user to make sure that
|
||||||
|
the URL always produces the same tarball contents.
|
||||||
|
|
||||||
|
An HTTP server can return an "immutable" HTTP URL appropriate for lock
|
||||||
|
files. This allows users to specify a tarball flake input in
|
||||||
|
`flake.nix` that requests the latest version of a flake
|
||||||
|
(e.g. `https://example.org/hello/latest.tar.gz`), while `flake.lock`
|
||||||
|
will record a URL whose contents will not change
|
||||||
|
(e.g. `https://example.org/hello/<revision>.tar.gz`). To do so, the
|
||||||
|
server must return an [HTTP `Link` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) with the `rel` attribute set to
|
||||||
|
`immutable`, as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
Link: <flakeref>; rel="immutable"
|
||||||
|
```
|
||||||
|
|
||||||
|
(Note the required `<` and `>` characters around *flakeref*.)
|
||||||
|
|
||||||
|
*flakeref* must be a tarball flakeref. It can contain flake attributes
|
||||||
|
such as `narHash`, `rev` and `revCount`. If `narHash` is included, its
|
||||||
|
value must be the NAR hash of the unpacked tarball (as computed via
|
||||||
|
`nix hash path`). Nix checks the contents of the returned tarball
|
||||||
|
against the `narHash` attribute. The `rev` and `revCount` attributes
|
||||||
|
are useful when the tarball flake is a mirror of a fetcher type that
|
||||||
|
has those attributes, such as Git or GitHub. They are not checked by
|
||||||
|
Nix.
|
||||||
|
|
||||||
|
```
|
||||||
|
Link: <https://example.org/hello/442793d9ec0584f6a6e82fa253850c8085bb150a.tar.gz
|
||||||
|
?rev=442793d9ec0584f6a6e82fa253850c8085bb150a
|
||||||
|
&revCount=835
|
||||||
|
&narHash=sha256-GUm8Uh/U74zFCwkvt9Mri4DSM%2BmHj3tYhXUkYpiv31M%3D>; rel="immutable"
|
||||||
|
```
|
||||||
|
|
||||||
|
(The linebreaks in this example are for clarity and must not be included in the actual response.)
|
||||||
|
|
||||||
|
For tarball flakes, the value of the `lastModified` flake attribute is
|
||||||
|
defined as the timestamp of the newest file inside the tarball.
|
8
doc/manual/src/release-notes/rl-2.16.md
Normal file
8
doc/manual/src/release-notes/rl-2.16.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Release 2.16 (2023-05-31)
|
||||||
|
|
||||||
|
* Speed-up of downloads from binary caches.
|
||||||
|
The number of parallel downloads (also known as substitutions) has been separated from the [`--max-jobs` setting](../command-ref/conf-file.md#conf-max-jobs).
|
||||||
|
The new setting is called [`max-substitution-jobs`](../command-ref/conf-file.md#conf-max-substitution-jobs).
|
||||||
|
The number of parallel downloads is now set to 16 by default (previously, the default was 1 due to the coupling to build jobs).
|
||||||
|
|
||||||
|
* The function [`builtins.replaceStrings`](@docroot@/language/builtins.md#builtins-replaceStrings) is now lazy in the value of its second argument `to`. That is, `to` is only evaluated when its corresponding pattern in `from` is matched in the string `s`.
|
|
@ -1,6 +1,8 @@
|
||||||
# Release X.Y (202?-??-??)
|
# Release X.Y (202?-??-??)
|
||||||
|
|
||||||
- Speed-up of downloads from binary caches.
|
- [`nix-channel`](../command-ref/nix-channel.md) now supports a `--list-generations` subcommand
|
||||||
The number of parallel downloads (also known as substitutions) has been separated from the [`--max-jobs` setting](../command-ref/conf-file.md#conf-max-jobs).
|
|
||||||
The new setting is called [`max-substitution-jobs`](../command-ref/conf-file.md#conf-max-substitution-jobs).
|
* The function [`builtins.fetchClosure`](../language/builtins.md#builtins-fetchClosure) can now fetch input-addressed paths in [pure evaluation mode](../command-ref/conf-file.md#conf-pure-eval), as those are not impure.
|
||||||
The number of parallel downloads is now set to 16 by default (previously, the default was 1 due to the coupling to build jobs).
|
|
||||||
|
- Nix now allows unprivileged/[`allowed-users`](../command-ref/conf-file.md#conf-allowed-users) to sign paths.
|
||||||
|
Previously, only [`trusted-users`](../command-ref/conf-file.md#conf-trusted-users) users could sign paths.
|
||||||
|
|
14
docker.nix
14
docker.nix
|
@ -190,6 +190,12 @@ let
|
||||||
cp -a ${rootEnv}/* $out/
|
cp -a ${rootEnv}/* $out/
|
||||||
ln -s ${manifest} $out/manifest.nix
|
ln -s ${manifest} $out/manifest.nix
|
||||||
'';
|
'';
|
||||||
|
flake-registry-path = if (flake-registry == null) then
|
||||||
|
null
|
||||||
|
else if (builtins.readFileType (toString flake-registry)) == "directory" then
|
||||||
|
"${flake-registry}/flake-registry.json"
|
||||||
|
else
|
||||||
|
flake-registry;
|
||||||
in
|
in
|
||||||
pkgs.runCommand "base-system"
|
pkgs.runCommand "base-system"
|
||||||
{
|
{
|
||||||
|
@ -202,7 +208,7 @@ let
|
||||||
];
|
];
|
||||||
allowSubstitutes = false;
|
allowSubstitutes = false;
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
} ''
|
} (''
|
||||||
env
|
env
|
||||||
set -x
|
set -x
|
||||||
mkdir -p $out/etc
|
mkdir -p $out/etc
|
||||||
|
@ -249,15 +255,15 @@ let
|
||||||
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
||||||
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
||||||
|
|
||||||
'' + (lib.optionalString (flake-registry != null) ''
|
'' + (lib.optionalString (flake-registry-path != null) ''
|
||||||
nixCacheDir="/root/.cache/nix"
|
nixCacheDir="/root/.cache/nix"
|
||||||
mkdir -p $out$nixCacheDir
|
mkdir -p $out$nixCacheDir
|
||||||
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
||||||
ln -s ${flake-registry}/flake-registry.json $out$globalFlakeRegistryPath
|
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
|
||||||
mkdir -p $out/nix/var/nix/gcroots/auto
|
mkdir -p $out/nix/var/nix/gcroots/auto
|
||||||
rootName=$(${pkgs.nix}/bin/nix --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
|
rootName=$(${pkgs.nix}/bin/nix --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
|
||||||
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
|
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
|
||||||
'');
|
''));
|
||||||
|
|
||||||
in
|
in
|
||||||
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
|
|
@ -590,6 +590,8 @@
|
||||||
|
|
||||||
tests.sourcehutFlakes = runNixOSTestFor "x86_64-linux" ./tests/nixos/sourcehut-flakes.nix;
|
tests.sourcehutFlakes = runNixOSTestFor "x86_64-linux" ./tests/nixos/sourcehut-flakes.nix;
|
||||||
|
|
||||||
|
tests.tarballFlakes = runNixOSTestFor "x86_64-linux" ./tests/nixos/tarball-flakes.nix;
|
||||||
|
|
||||||
tests.containers = runNixOSTestFor "x86_64-linux" ./tests/nixos/containers/containers.nix;
|
tests.containers = runNixOSTestFor "x86_64-linux" ./tests/nixos/containers/containers.nix;
|
||||||
|
|
||||||
tests.setuid = lib.genAttrs
|
tests.setuid = lib.genAttrs
|
||||||
|
|
|
@ -117,6 +117,7 @@ Pull requests in this column are reviewed together during work meetings.
|
||||||
This is both for spreading implementation knowledge and for establishing common values in code reviews.
|
This is both for spreading implementation knowledge and for establishing common values in code reviews.
|
||||||
|
|
||||||
When the overall direction is agreed upon, even when further changes are required, the pull request is assigned to one team member.
|
When the overall direction is agreed upon, even when further changes are required, the pull request is assigned to one team member.
|
||||||
|
If significant changes are requested or reviewers cannot come to a conclusion in reasonable time, the pull request is [marked as draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#converting-a-pull-request-to-a-draft).
|
||||||
|
|
||||||
### Assigned
|
### Assigned
|
||||||
|
|
||||||
|
|
|
@ -119,8 +119,7 @@ release:
|
||||||
TODO: This script requires the right AWS credentials. Document.
|
TODO: This script requires the right AWS credentials. Document.
|
||||||
|
|
||||||
TODO: This script currently requires a
|
TODO: This script currently requires a
|
||||||
`/home/eelco/Dev/nix-pristine` and
|
`/home/eelco/Dev/nix-pristine`.
|
||||||
`/home/eelco/Dev/nixpkgs-pristine`.
|
|
||||||
|
|
||||||
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
|
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
|
||||||
|
|
||||||
|
@ -141,7 +140,7 @@ release:
|
||||||
$ git checkout master
|
$ git checkout master
|
||||||
$ git pull
|
$ git pull
|
||||||
$ NEW_VERSION=2.13.0
|
$ NEW_VERSION=2.13.0
|
||||||
$ echo -n $NEW_VERSION > .version
|
$ echo $NEW_VERSION > .version
|
||||||
$ git checkout -b bump-$NEW_VERSION
|
$ git checkout -b bump-$NEW_VERSION
|
||||||
$ git commit -a -m 'Bump version'
|
$ git commit -a -m 'Bump version'
|
||||||
$ git push --set-upstream origin bump-$NEW_VERSION
|
$ git push --set-upstream origin bump-$NEW_VERSION
|
||||||
|
|
|
@ -15,7 +15,6 @@ my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n";
|
||||||
|
|
||||||
my $releasesBucketName = "nix-releases";
|
my $releasesBucketName = "nix-releases";
|
||||||
my $channelsBucketName = "nix-channels";
|
my $channelsBucketName = "nix-channels";
|
||||||
my $nixpkgsDir = "/home/eelco/Dev/nixpkgs-pristine";
|
|
||||||
|
|
||||||
my $TMPDIR = $ENV{'TMPDIR'} // "/tmp";
|
my $TMPDIR = $ENV{'TMPDIR'} // "/tmp";
|
||||||
|
|
||||||
|
@ -81,6 +80,38 @@ my $s3_us = Net::Amazon::S3->new(
|
||||||
|
|
||||||
my $channelsBucket = $s3_us->bucket($channelsBucketName) or die;
|
my $channelsBucket = $s3_us->bucket($channelsBucketName) or die;
|
||||||
|
|
||||||
|
sub getStorePath {
|
||||||
|
my ($jobName, $output) = @_;
|
||||||
|
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
|
||||||
|
return $buildInfo->{buildoutputs}->{$output or "out"}->{path} or die "cannot get store path for '$jobName'";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub copyManual {
|
||||||
|
my $manual = getStorePath("build.x86_64-linux", "doc");
|
||||||
|
print "$manual\n";
|
||||||
|
|
||||||
|
my $manualNar = "$tmpDir/$releaseName-manual.nar.xz";
|
||||||
|
print "$manualNar\n";
|
||||||
|
|
||||||
|
unless (-e $manualNar) {
|
||||||
|
system("NIX_REMOTE=$binaryCache nix store dump-path '$manual' | xz > '$manualNar'.tmp") == 0
|
||||||
|
or die "unable to fetch $manual\n";
|
||||||
|
rename("$manualNar.tmp", $manualNar) or die;
|
||||||
|
}
|
||||||
|
|
||||||
|
unless (-e "$tmpDir/manual") {
|
||||||
|
system("xz -d < '$manualNar' | nix-store --restore $tmpDir/manual.tmp") == 0
|
||||||
|
or die "unable to unpack $manualNar\n";
|
||||||
|
rename("$tmpDir/manual.tmp/share/doc/nix/manual", "$tmpDir/manual") or die;
|
||||||
|
system("rm -rf '$tmpDir/manual.tmp'") == 0 or die;
|
||||||
|
}
|
||||||
|
|
||||||
|
system("aws s3 sync '$tmpDir/manual' s3://$releasesBucketName/$releaseDir/manual") == 0
|
||||||
|
or die "syncing manual to S3\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
copyManual;
|
||||||
|
|
||||||
sub downloadFile {
|
sub downloadFile {
|
||||||
my ($jobName, $productNr, $dstName) = @_;
|
my ($jobName, $productNr, $dstName) = @_;
|
||||||
|
|
||||||
|
@ -180,9 +211,20 @@ if ($isLatest) {
|
||||||
system("docker manifest push nixos/nix:latest") == 0 or die;
|
system("docker manifest push nixos/nix:latest") == 0 or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Upload nix-fallback-paths.nix.
|
||||||
|
write_file("$tmpDir/fallback-paths.nix",
|
||||||
|
"{\n" .
|
||||||
|
" x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
|
||||||
|
" i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
|
||||||
|
" aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
|
||||||
|
" x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
|
||||||
|
" aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
|
||||||
|
"}\n");
|
||||||
|
|
||||||
# Upload release files to S3.
|
# Upload release files to S3.
|
||||||
for my $fn (glob "$tmpDir/*") {
|
for my $fn (glob "$tmpDir/*") {
|
||||||
my $name = basename($fn);
|
my $name = basename($fn);
|
||||||
|
next if $name eq "manual";
|
||||||
my $dstKey = "$releaseDir/" . $name;
|
my $dstKey = "$releaseDir/" . $name;
|
||||||
unless (defined $releasesBucket->head_key($dstKey)) {
|
unless (defined $releasesBucket->head_key($dstKey)) {
|
||||||
print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n";
|
print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n";
|
||||||
|
@ -190,8 +232,7 @@ for my $fn (glob "$tmpDir/*") {
|
||||||
my $configuration = ();
|
my $configuration = ();
|
||||||
$configuration->{content_type} = "application/octet-stream";
|
$configuration->{content_type} = "application/octet-stream";
|
||||||
|
|
||||||
if ($fn =~ /.sha256|install/) {
|
if ($fn =~ /.sha256|install|\.nix$/) {
|
||||||
# Text files
|
|
||||||
$configuration->{content_type} = "text/plain";
|
$configuration->{content_type} = "text/plain";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,28 +241,6 @@ for my $fn (glob "$tmpDir/*") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update nix-fallback-paths.nix.
|
|
||||||
if ($isLatest) {
|
|
||||||
system("cd $nixpkgsDir && git pull") == 0 or die;
|
|
||||||
|
|
||||||
sub getStorePath {
|
|
||||||
my ($jobName) = @_;
|
|
||||||
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
|
|
||||||
return $buildInfo->{buildoutputs}->{out}->{path} or die "cannot get store path for '$jobName'";
|
|
||||||
}
|
|
||||||
|
|
||||||
write_file("$nixpkgsDir/nixos/modules/installer/tools/nix-fallback-paths.nix",
|
|
||||||
"{\n" .
|
|
||||||
" x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
|
|
||||||
" i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
|
|
||||||
" aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
|
|
||||||
" x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
|
|
||||||
" aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
|
|
||||||
"}\n");
|
|
||||||
|
|
||||||
system("cd $nixpkgsDir && git commit -a -m 'nix-fallback-paths.nix: Update to $version'") == 0 or die;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Update the "latest" symlink.
|
# Update the "latest" symlink.
|
||||||
$channelsBucket->add_key(
|
$channelsBucket->add_key(
|
||||||
"nix-latest/install", "",
|
"nix-latest/install", "",
|
||||||
|
|
|
@ -10,6 +10,7 @@ ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket
|
||||||
ExecStart=@@bindir@/nix-daemon nix-daemon --daemon
|
ExecStart=@@bindir@/nix-daemon nix-daemon --daemon
|
||||||
KillMode=process
|
KillMode=process
|
||||||
LimitNOFILE=1048576
|
LimitNOFILE=1048576
|
||||||
|
TasksMax=1048576
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -100,7 +100,7 @@ poly_extra_try_me_commands() {
|
||||||
poly_configure_nix_daemon_service() {
|
poly_configure_nix_daemon_service() {
|
||||||
task "Setting up the nix-daemon LaunchDaemon"
|
task "Setting up the nix-daemon LaunchDaemon"
|
||||||
_sudo "to set up the nix-daemon as a LaunchDaemon" \
|
_sudo "to set up the nix-daemon as a LaunchDaemon" \
|
||||||
/bin/cp -f "/nix/var/nix/profiles/default$NIX_DAEMON_DEST" "$NIX_DAEMON_DEST"
|
/usr/bin/install -m -rw-r--r-- "/nix/var/nix/profiles/default$NIX_DAEMON_DEST" "$NIX_DAEMON_DEST"
|
||||||
|
|
||||||
_sudo "to load the LaunchDaemon plist for nix-daemon" \
|
_sudo "to load the LaunchDaemon plist for nix-daemon" \
|
||||||
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist
|
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist
|
||||||
|
|
|
@ -246,8 +246,15 @@ printf -v _OLD_LINE_FMT "%b" $'\033[1;7;31m-'"$ESC ${RED}%L${ESC}"
|
||||||
printf -v _NEW_LINE_FMT "%b" $'\033[1;7;32m+'"$ESC ${GREEN}%L${ESC}"
|
printf -v _NEW_LINE_FMT "%b" $'\033[1;7;32m+'"$ESC ${GREEN}%L${ESC}"
|
||||||
|
|
||||||
_diff() {
|
_diff() {
|
||||||
|
# macOS Ventura doesn't ship with GNU diff. Print similar output except
|
||||||
|
# without +/- markers or dimming
|
||||||
|
if diff --version | grep -q "Apple diff"; then
|
||||||
|
printf -v CHANGED_GROUP_FORMAT "%b" "${GREEN}%>${RED}%<${ESC}"
|
||||||
|
diff --changed-group-format="$CHANGED_GROUP_FORMAT" "$@"
|
||||||
|
else
|
||||||
# simple colorized diff comatible w/ pre `--color` versions
|
# simple colorized diff comatible w/ pre `--color` versions
|
||||||
diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
|
diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm_rm() {
|
confirm_rm() {
|
||||||
|
@ -693,6 +700,10 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
welcome_to_nix() {
|
welcome_to_nix() {
|
||||||
|
local -r NIX_UID_RANGES="${NIX_FIRST_BUILD_UID}..$((NIX_FIRST_BUILD_UID + NIX_USER_COUNT - 1))"
|
||||||
|
local -r RANGE_TEXT=$(echo -ne "${BLUE}(uids [${NIX_UID_RANGES}])${ESC}")
|
||||||
|
local -r GROUP_TEXT=$(echo -ne "${BLUE}(gid ${NIX_BUILD_GROUP_ID})${ESC}")
|
||||||
|
|
||||||
ok "Welcome to the Multi-User Nix Installation"
|
ok "Welcome to the Multi-User Nix Installation"
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
@ -706,8 +717,8 @@ manager. This will happen in a few stages:
|
||||||
2. Show you what I am going to install and where. Then I will ask
|
2. Show you what I am going to install and where. Then I will ask
|
||||||
if you are ready to continue.
|
if you are ready to continue.
|
||||||
|
|
||||||
3. Create the system users and groups that the Nix daemon uses to run
|
3. Create the system users ${RANGE_TEXT} and groups ${GROUP_TEXT}
|
||||||
builds.
|
that the Nix daemon uses to run builds.
|
||||||
|
|
||||||
4. Perform the basic installation of the Nix files daemon.
|
4. Perform the basic installation of the Nix files daemon.
|
||||||
|
|
||||||
|
@ -873,7 +884,7 @@ configure_shell_profile() {
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
task "Setting up shell profiles for Fish with with ${PROFILE_FISH_SUFFIX} inside ${PROFILE_FISH_PREFIXES[*]}"
|
task "Setting up shell profiles for Fish with ${PROFILE_FISH_SUFFIX} inside ${PROFILE_FISH_PREFIXES[*]}"
|
||||||
for fish_prefix in "${PROFILE_FISH_PREFIXES[@]}"; do
|
for fish_prefix in "${PROFILE_FISH_PREFIXES[@]}"; do
|
||||||
if [ ! -d "$fish_prefix" ]; then
|
if [ ! -d "$fish_prefix" ]; then
|
||||||
# this specific prefix (ie: /etc/fish) is very likely to exist
|
# this specific prefix (ie: /etc/fish) is very likely to exist
|
||||||
|
|
|
@ -299,7 +299,7 @@ connected:
|
||||||
!trusted || *trusted;
|
!trusted || *trusted;
|
||||||
});
|
});
|
||||||
|
|
||||||
// See the very large comment in `case wopBuildDerivation:` in
|
// See the very large comment in `case WorkerProto::Op::BuildDerivation:` in
|
||||||
// `src/libstore/daemon.cc` that explains the trust model here.
|
// `src/libstore/daemon.cc` that explains the trust model here.
|
||||||
//
|
//
|
||||||
// This condition mirrors that: that code enforces the "rules" outlined there;
|
// This condition mirrors that: that code enforces the "rules" outlined there;
|
||||||
|
|
|
@ -239,9 +239,7 @@ void MixProfile::updateProfile(const StorePath & storePath)
|
||||||
if (!store) throw Error("'--profile' is not supported for this Nix store");
|
if (!store) throw Error("'--profile' is not supported for this Nix store");
|
||||||
auto profile2 = absPath(*profile);
|
auto profile2 = absPath(*profile);
|
||||||
switchLink(profile2,
|
switchLink(profile2,
|
||||||
createGeneration(
|
createGeneration(*store, profile2, storePath));
|
||||||
ref<LocalFSStore>(store),
|
|
||||||
profile2, storePath));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixProfile::updateProfile(const BuiltPaths & buildables)
|
void MixProfile::updateProfile(const BuiltPaths & buildables)
|
||||||
|
|
|
@ -105,7 +105,9 @@ MixEvalArgs::MixEvalArgs()
|
||||||
)",
|
)",
|
||||||
.category = category,
|
.category = category,
|
||||||
.labels = {"path"},
|
.labels = {"path"},
|
||||||
.handler = {[&](std::string s) { searchPath.push_back(s); }}
|
.handler = {[&](std::string s) {
|
||||||
|
searchPath.elements.emplace_back(SearchPath::Elem::parse(s));
|
||||||
|
}}
|
||||||
});
|
});
|
||||||
|
|
||||||
addFlag({
|
addFlag({
|
||||||
|
@ -165,7 +167,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s)
|
||||||
{
|
{
|
||||||
if (EvalSettings::isPseudoUrl(s)) {
|
if (EvalSettings::isPseudoUrl(s)) {
|
||||||
auto storePath = fetchers::downloadTarball(
|
auto storePath = fetchers::downloadTarball(
|
||||||
state.store, EvalSettings::resolvePseudoUrl(s), "source", false).first.storePath;
|
state.store, EvalSettings::resolvePseudoUrl(s), "source", false).tree.storePath;
|
||||||
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
|
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "args.hh"
|
#include "args.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
|
#include "search-path.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ struct MixEvalArgs : virtual Args, virtual MixRepair
|
||||||
|
|
||||||
Bindings * getAutoArgs(EvalState & state);
|
Bindings * getAutoArgs(EvalState & state);
|
||||||
|
|
||||||
Strings searchPath;
|
SearchPath searchPath;
|
||||||
|
|
||||||
std::optional<std::string> evalStoreUrl;
|
std::optional<std::string> evalStoreUrl;
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||||
},
|
},
|
||||||
ExtraPathInfoFlake::Flake {
|
ExtraPathInfoFlake::Flake {
|
||||||
.originalRef = flakeRef,
|
.originalRef = flakeRef,
|
||||||
.resolvedRef = getLockedFlake()->flake.lockedRef,
|
.lockedRef = getLockedFlake()->flake.lockedRef,
|
||||||
}),
|
}),
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue
|
||||||
*/
|
*/
|
||||||
struct Flake {
|
struct Flake {
|
||||||
FlakeRef originalRef;
|
FlakeRef originalRef;
|
||||||
FlakeRef resolvedRef;
|
FlakeRef lockedRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
Flake flake;
|
Flake flake;
|
||||||
|
|
|
@ -701,7 +701,7 @@ RawInstallablesCommand::RawInstallablesCommand()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "stdin",
|
.longName = "stdin",
|
||||||
.description = "Read installables from the standard input.",
|
.description = "Read installables from the standard input. No default installable applied.",
|
||||||
.handler = {&readFromStdIn, true}
|
.handler = {&readFromStdIn, true}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -730,9 +730,9 @@ void RawInstallablesCommand::run(ref<Store> store)
|
||||||
while (std::cin >> word) {
|
while (std::cin >> word) {
|
||||||
rawInstallables.emplace_back(std::move(word));
|
rawInstallables.emplace_back(std::move(word));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
applyDefaultInstallables(rawInstallables);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyDefaultInstallables(rawInstallables);
|
|
||||||
run(store, std::move(rawInstallables));
|
run(store, std::move(rawInstallables));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct NixRepl
|
||||||
|
|
||||||
const Path historyFile;
|
const Path historyFile;
|
||||||
|
|
||||||
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
NixRepl(const SearchPath & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
||||||
std::function<AnnotatedValues()> getValues);
|
std::function<AnnotatedValues()> getValues);
|
||||||
virtual ~NixRepl();
|
virtual ~NixRepl();
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ std::string removeWhitespace(std::string s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
NixRepl::NixRepl(const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
std::function<NixRepl::AnnotatedValues()> getValues)
|
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||||
: AbstractNixRepl(state)
|
: AbstractNixRepl(state)
|
||||||
, debugTraceIndex(0)
|
, debugTraceIndex(0)
|
||||||
|
@ -1024,7 +1024,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
||||||
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
std::function<AnnotatedValues()> getValues)
|
std::function<AnnotatedValues()> getValues)
|
||||||
{
|
{
|
||||||
return std::make_unique<NixRepl>(
|
return std::make_unique<NixRepl>(
|
||||||
|
@ -1044,7 +1044,7 @@ void AbstractNixRepl::runSimple(
|
||||||
NixRepl::AnnotatedValues values;
|
NixRepl::AnnotatedValues values;
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
const Strings & searchPath = {};
|
SearchPath searchPath = {};
|
||||||
auto repl = std::make_unique<NixRepl>(
|
auto repl = std::make_unique<NixRepl>(
|
||||||
searchPath,
|
searchPath,
|
||||||
openStore(),
|
openStore(),
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct AbstractNixRepl
|
||||||
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||||
|
|
||||||
static std::unique_ptr<AbstractNixRepl> create(
|
static std::unique_ptr<AbstractNixRepl> create(
|
||||||
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
std::function<AnnotatedValues()> getValues);
|
std::function<AnnotatedValues()> getValues);
|
||||||
|
|
||||||
static void runSimple(
|
static void runSimple(
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "filetransfer.hh"
|
#include "filetransfer.hh"
|
||||||
|
@ -94,11 +95,16 @@ RootValue allocRootValue(Value * v)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::print(const SymbolTable & symbols, std::ostream & str,
|
void Value::print(const SymbolTable &symbols, std::ostream &str,
|
||||||
std::set<const void *> * seen) const
|
std::set<const void *> *seen, int depth) const
|
||||||
|
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
|
if (depth <= 0) {
|
||||||
|
str << "«too deep»";
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (internalType) {
|
switch (internalType) {
|
||||||
case tInt:
|
case tInt:
|
||||||
str << integer;
|
str << integer;
|
||||||
|
@ -122,7 +128,7 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
for (auto & i : attrs->lexicographicOrder(symbols)) {
|
for (auto & i : attrs->lexicographicOrder(symbols)) {
|
||||||
str << symbols[i->name] << " = ";
|
str << symbols[i->name] << " = ";
|
||||||
i->value->print(symbols, str, seen);
|
i->value->print(symbols, str, seen, depth - 1);
|
||||||
str << "; ";
|
str << "; ";
|
||||||
}
|
}
|
||||||
str << "}";
|
str << "}";
|
||||||
|
@ -138,7 +144,7 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
str << "[ ";
|
str << "[ ";
|
||||||
for (auto v2 : listItems()) {
|
for (auto v2 : listItems()) {
|
||||||
if (v2)
|
if (v2)
|
||||||
v2->print(symbols, str, seen);
|
v2->print(symbols, str, seen, depth - 1);
|
||||||
else
|
else
|
||||||
str << "(nullptr)";
|
str << "(nullptr)";
|
||||||
str << " ";
|
str << " ";
|
||||||
|
@ -180,11 +186,10 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Value::print(const SymbolTable &symbols, std::ostream &str,
|
||||||
void Value::print(const SymbolTable & symbols, std::ostream & str, bool showRepeated) const
|
bool showRepeated, int depth) const {
|
||||||
{
|
|
||||||
std::set<const void *> seen;
|
std::set<const void *> seen;
|
||||||
print(symbols, str, showRepeated ? nullptr : &seen);
|
print(symbols, str, showRepeated ? nullptr : &seen, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretty print types for assertion errors
|
// Pretty print types for assertion errors
|
||||||
|
@ -210,20 +215,21 @@ const Value * getPrimOp(const Value &v) {
|
||||||
return primOp;
|
return primOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view showType(ValueType type)
|
std::string_view showType(ValueType type, bool withArticle)
|
||||||
{
|
{
|
||||||
|
#define WA(a, w) withArticle ? a " " w : w
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case nInt: return "an integer";
|
case nInt: return WA("an", "integer");
|
||||||
case nBool: return "a Boolean";
|
case nBool: return WA("a", "Boolean");
|
||||||
case nString: return "a string";
|
case nString: return WA("a", "string");
|
||||||
case nPath: return "a path";
|
case nPath: return WA("a", "path");
|
||||||
case nNull: return "null";
|
case nNull: return "null";
|
||||||
case nAttrs: return "a set";
|
case nAttrs: return WA("a", "set");
|
||||||
case nList: return "a list";
|
case nList: return WA("a", "list");
|
||||||
case nFunction: return "a function";
|
case nFunction: return WA("a", "function");
|
||||||
case nExternal: return "an external value";
|
case nExternal: return WA("an", "external value");
|
||||||
case nFloat: return "a float";
|
case nFloat: return WA("a", "float");
|
||||||
case nThunk: return "a thunk";
|
case nThunk: return WA("a", "thunk");
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -492,7 +498,7 @@ ErrorBuilder & ErrorBuilder::withFrame(const Env & env, const Expr & expr)
|
||||||
|
|
||||||
|
|
||||||
EvalState::EvalState(
|
EvalState::EvalState(
|
||||||
const Strings & _searchPath,
|
const SearchPath & _searchPath,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
std::shared_ptr<Store> buildStore)
|
std::shared_ptr<Store> buildStore)
|
||||||
: sWith(symbols.create("<with>"))
|
: sWith(symbols.create("<with>"))
|
||||||
|
@ -557,30 +563,32 @@ EvalState::EvalState(
|
||||||
|
|
||||||
/* Initialise the Nix expression search path. */
|
/* Initialise the Nix expression search path. */
|
||||||
if (!evalSettings.pureEval) {
|
if (!evalSettings.pureEval) {
|
||||||
for (auto & i : _searchPath) addToSearchPath(i);
|
for (auto & i : _searchPath.elements)
|
||||||
for (auto & i : evalSettings.nixPath.get()) addToSearchPath(i);
|
addToSearchPath(SearchPath::Elem {i});
|
||||||
|
for (auto & i : evalSettings.nixPath.get())
|
||||||
|
addToSearchPath(SearchPath::Elem::parse(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
||||||
allowedPaths = PathSet();
|
allowedPaths = PathSet();
|
||||||
|
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath.elements) {
|
||||||
auto r = resolveSearchPathElem(i);
|
auto r = resolveSearchPathPath(i.path);
|
||||||
if (!r.first) continue;
|
if (!r) continue;
|
||||||
|
|
||||||
auto path = r.second;
|
auto path = *std::move(r);
|
||||||
|
|
||||||
if (store->isInStore(r.second)) {
|
if (store->isInStore(path)) {
|
||||||
try {
|
try {
|
||||||
StorePathSet closure;
|
StorePathSet closure;
|
||||||
store->computeFSClosure(store->toStorePath(r.second).first, closure);
|
store->computeFSClosure(store->toStorePath(path).first, closure);
|
||||||
for (auto & path : closure)
|
for (auto & path : closure)
|
||||||
allowPath(path);
|
allowPath(path);
|
||||||
} catch (InvalidPath &) {
|
} catch (InvalidPath &) {
|
||||||
allowPath(r.second);
|
allowPath(path);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
allowPath(r.second);
|
allowPath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,28 +709,34 @@ Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * EvalState::addConstant(const std::string & name, Value & v)
|
Value * EvalState::addConstant(const std::string & name, Value & v, Constant info)
|
||||||
{
|
{
|
||||||
Value * v2 = allocValue();
|
Value * v2 = allocValue();
|
||||||
*v2 = v;
|
*v2 = v;
|
||||||
addConstant(name, v2);
|
addConstant(name, v2, info);
|
||||||
return v2;
|
return v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::addConstant(const std::string & name, Value * v)
|
void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
||||||
{
|
{
|
||||||
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
|
||||||
auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
|
auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
constantInfos.push_back({name2, info});
|
||||||
|
|
||||||
Value * EvalState::addPrimOp(const std::string & name,
|
if (!(evalSettings.pureEval && info.impureOnly)) {
|
||||||
size_t arity, PrimOpFun primOp)
|
/* Check the type, if possible.
|
||||||
{
|
|
||||||
return addPrimOp(PrimOp { .fun = primOp, .arity = arity, .name = name });
|
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);
|
||||||
|
|
||||||
|
/* Install value the base environment. */
|
||||||
|
staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||||
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
|
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -736,7 +750,10 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||||
vPrimOp->mkPrimOp(new PrimOp(primOp));
|
vPrimOp->mkPrimOp(new PrimOp(primOp));
|
||||||
Value v;
|
Value v;
|
||||||
v.mkApp(vPrimOp, vPrimOp);
|
v.mkApp(vPrimOp, vPrimOp);
|
||||||
return addConstant(primOp.name, v);
|
return addConstant(primOp.name, v, {
|
||||||
|
.type = nThunk, // FIXME
|
||||||
|
.doc = primOp.doc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto envName = symbols.create(primOp.name);
|
auto envName = symbols.create(primOp.name);
|
||||||
|
@ -762,13 +779,13 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
|
||||||
{
|
{
|
||||||
if (v.isPrimOp()) {
|
if (v.isPrimOp()) {
|
||||||
auto v2 = &v;
|
auto v2 = &v;
|
||||||
if (v2->primOp->doc)
|
if (auto * doc = v2->primOp->doc)
|
||||||
return Doc {
|
return Doc {
|
||||||
.pos = {},
|
.pos = {},
|
||||||
.name = v2->primOp->name,
|
.name = v2->primOp->name,
|
||||||
.arity = v2->primOp->arity,
|
.arity = v2->primOp->arity,
|
||||||
.args = v2->primOp->args,
|
.args = v2->primOp->args,
|
||||||
.doc = v2->primOp->doc,
|
.doc = doc,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -1058,7 +1075,7 @@ void EvalState::mkOutputString(
|
||||||
? store->printStorePath(*std::move(optOutputPath))
|
? store->printStorePath(*std::move(optOutputPath))
|
||||||
/* Downstream we would substitute this for an actual path once
|
/* Downstream we would substitute this for an actual path once
|
||||||
we build the floating CA derivation */
|
we build the floating CA derivation */
|
||||||
: downstreamPlaceholder(*store, drvPath, outputName),
|
: DownstreamPlaceholder::unknownCaOutput(drvPath, outputName).render(),
|
||||||
NixStringContext {
|
NixStringContext {
|
||||||
NixStringContextElem::Built {
|
NixStringContextElem::Built {
|
||||||
.drvPath = drvPath,
|
.drvPath = drvPath,
|
||||||
|
@ -2380,7 +2397,7 @@ DerivedPath EvalState::coerceToDerivedPath(const PosIdx pos, Value & v, std::str
|
||||||
// This is testing for the case of CA derivations
|
// This is testing for the case of CA derivations
|
||||||
auto sExpected = optOutputPath
|
auto sExpected = optOutputPath
|
||||||
? store->printStorePath(*optOutputPath)
|
? store->printStorePath(*optOutputPath)
|
||||||
: downstreamPlaceholder(*store, b.drvPath, output);
|
: DownstreamPlaceholder::unknownCaOutput(b.drvPath, output).render();
|
||||||
if (s != sExpected)
|
if (s != sExpected)
|
||||||
error(
|
error(
|
||||||
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
|
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
|
||||||
|
@ -2619,7 +2636,7 @@ Strings EvalSettings::getDefaultNixPath()
|
||||||
{
|
{
|
||||||
Strings res;
|
Strings res;
|
||||||
auto add = [&](const Path & p, const std::string & s = std::string()) {
|
auto add = [&](const Path & p, const std::string & s = std::string()) {
|
||||||
if (pathExists(p)) {
|
if (pathAccessible(p)) {
|
||||||
if (s.empty()) {
|
if (s.empty()) {
|
||||||
res.push_back(p);
|
res.push_back(p);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
#include "experimental-features.hh"
|
#include "experimental-features.hh"
|
||||||
#include "input-accessor.hh"
|
#include "input-accessor.hh"
|
||||||
|
#include "search-path.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -25,15 +26,72 @@ struct DerivedPath;
|
||||||
enum RepairFlag : bool;
|
enum RepairFlag : bool;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that implements a primop.
|
||||||
|
*/
|
||||||
typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v);
|
typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info about a primitive operation, and its implementation
|
||||||
|
*/
|
||||||
struct PrimOp
|
struct PrimOp
|
||||||
{
|
{
|
||||||
PrimOpFun fun;
|
/**
|
||||||
size_t arity;
|
* Name of the primop. `__` prefix is treated specially.
|
||||||
|
*/
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Names of the parameters of a primop, for primops that take a
|
||||||
|
* fixed number of arguments to be substituted for these parameters.
|
||||||
|
*/
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aritiy of the primop.
|
||||||
|
*
|
||||||
|
* If `args` is not empty, this field will be computed from that
|
||||||
|
* field instead, so it doesn't need to be manually set.
|
||||||
|
*/
|
||||||
|
size_t arity = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional free-form documentation about the primop.
|
||||||
|
*/
|
||||||
const char * doc = nullptr;
|
const char * doc = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the primop.
|
||||||
|
*/
|
||||||
|
PrimOpFun fun;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional experimental for this to be gated on.
|
||||||
|
*/
|
||||||
|
std::optional<ExperimentalFeature> experimentalFeature;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info about a constant
|
||||||
|
*/
|
||||||
|
struct Constant
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Optional type of the constant (known since it is a fixed value).
|
||||||
|
*
|
||||||
|
* @todo we should use an enum for this.
|
||||||
|
*/
|
||||||
|
ValueType type = nThunk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional free-form documentation about the constant.
|
||||||
|
*/
|
||||||
|
const char * doc = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the constant is impure, and not available in pure mode.
|
||||||
|
*/
|
||||||
|
bool impureOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
|
@ -65,11 +123,6 @@ std::string printValue(const EvalState & state, const Value & v);
|
||||||
std::ostream & operator << (std::ostream & os, const ValueType t);
|
std::ostream & operator << (std::ostream & os, const ValueType t);
|
||||||
|
|
||||||
|
|
||||||
// FIXME: maybe change this to an std::variant<SourcePath, URL>.
|
|
||||||
typedef std::pair<std::string, std::string> SearchPathElem;
|
|
||||||
typedef std::list<SearchPathElem> SearchPath;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the Boehm GC, if applicable.
|
* Initialise the Boehm GC, if applicable.
|
||||||
*/
|
*/
|
||||||
|
@ -256,7 +309,7 @@ private:
|
||||||
|
|
||||||
SearchPath searchPath;
|
SearchPath searchPath;
|
||||||
|
|
||||||
std::map<std::string, std::pair<bool, std::string>> searchPathResolved;
|
std::map<std::string, std::optional<std::string>> searchPathResolved;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache used by checkSourcePath().
|
* Cache used by checkSourcePath().
|
||||||
|
@ -283,12 +336,12 @@ private:
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalState(
|
EvalState(
|
||||||
const Strings & _searchPath,
|
const SearchPath & _searchPath,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
std::shared_ptr<Store> buildStore = nullptr);
|
std::shared_ptr<Store> buildStore = nullptr);
|
||||||
~EvalState();
|
~EvalState();
|
||||||
|
|
||||||
void addToSearchPath(const std::string & s);
|
void addToSearchPath(SearchPath::Elem && elem);
|
||||||
|
|
||||||
SearchPath getSearchPath() { return searchPath; }
|
SearchPath getSearchPath() { return searchPath; }
|
||||||
|
|
||||||
|
@ -370,12 +423,16 @@ public:
|
||||||
* Look up a file in the search path.
|
* Look up a file in the search path.
|
||||||
*/
|
*/
|
||||||
SourcePath findFile(const std::string_view path);
|
SourcePath findFile(const std::string_view path);
|
||||||
SourcePath findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
|
SourcePath findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Try to resolve a search path value (not the optinal key part)
|
||||||
|
*
|
||||||
* If the specified search path element is a URI, download it.
|
* If the specified search path element is a URI, download it.
|
||||||
|
*
|
||||||
|
* If it is not found, return `std::nullopt`
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem);
|
std::optional<std::string> resolveSearchPathPath(const SearchPath::Path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate an expression to normal form
|
* Evaluate an expression to normal form
|
||||||
|
@ -483,7 +540,7 @@ public:
|
||||||
* Coerce to `DerivedPath`.
|
* Coerce to `DerivedPath`.
|
||||||
*
|
*
|
||||||
* Must be a string which is either a literal store path or a
|
* Must be a string which is either a literal store path or a
|
||||||
* "placeholder (see `downstreamPlaceholder()`).
|
* "placeholder (see `DownstreamPlaceholder`).
|
||||||
*
|
*
|
||||||
* Even more importantly, the string context must be exactly one
|
* Even more importantly, the string context must be exactly one
|
||||||
* element, which is either a `NixStringContextElem::Opaque` or
|
* element, which is either a `NixStringContextElem::Opaque` or
|
||||||
|
@ -509,18 +566,23 @@ public:
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<StaticEnv> staticBaseEnv; // !!! should be private
|
std::shared_ptr<StaticEnv> staticBaseEnv; // !!! should be private
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name and documentation about every constant.
|
||||||
|
*
|
||||||
|
* Constants from primops are hard to crawl, and their docs will go
|
||||||
|
* here too.
|
||||||
|
*/
|
||||||
|
std::vector<std::pair<std::string, Constant>> constantInfos;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned int baseEnvDispl = 0;
|
unsigned int baseEnvDispl = 0;
|
||||||
|
|
||||||
void createBaseEnv();
|
void createBaseEnv();
|
||||||
|
|
||||||
Value * addConstant(const std::string & name, Value & v);
|
Value * addConstant(const std::string & name, Value & v, Constant info);
|
||||||
|
|
||||||
void addConstant(const std::string & name, Value * v);
|
void addConstant(const std::string & name, Value * v, Constant info);
|
||||||
|
|
||||||
Value * addPrimOp(const std::string & name,
|
|
||||||
size_t arity, PrimOpFun primOp);
|
|
||||||
|
|
||||||
Value * addPrimOp(PrimOp && primOp);
|
Value * addPrimOp(PrimOp && primOp);
|
||||||
|
|
||||||
|
@ -534,6 +596,10 @@ public:
|
||||||
std::optional<std::string> name;
|
std::optional<std::string> name;
|
||||||
size_t arity;
|
size_t arity;
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
/**
|
||||||
|
* Unlike the other `doc` fields in this file, this one should never be
|
||||||
|
* `null`.
|
||||||
|
*/
|
||||||
const char * doc;
|
const char * doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -622,7 +688,7 @@ public:
|
||||||
* @param optOutputPath Optional output path for that string. Must
|
* @param optOutputPath Optional output path for that string. Must
|
||||||
* be passed if and only if output store object is input-addressed.
|
* be passed if and only if output store object is input-addressed.
|
||||||
* Will be printed to form string if passed, otherwise a placeholder
|
* Will be printed to form string if passed, otherwise a placeholder
|
||||||
* will be used (see `downstreamPlaceholder()`).
|
* will be used (see `DownstreamPlaceholder`).
|
||||||
*/
|
*/
|
||||||
void mkOutputString(
|
void mkOutputString(
|
||||||
Value & value,
|
Value & value,
|
||||||
|
@ -700,8 +766,11 @@ struct DebugTraceStacker {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A string representing the type of the value `v`.
|
* @return A string representing the type of the value `v`.
|
||||||
|
*
|
||||||
|
* @param withArticle Whether to begin with an english article, e.g. "an
|
||||||
|
* integer" vs "integer".
|
||||||
*/
|
*/
|
||||||
std::string_view showType(ValueType type);
|
std::string_view showType(ValueType type, bool withArticle = true);
|
||||||
std::string showType(const Value & v);
|
std::string showType(const Value & v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -733,7 +802,12 @@ struct EvalSettings : Config
|
||||||
|
|
||||||
Setting<Strings> nixPath{
|
Setting<Strings> nixPath{
|
||||||
this, getDefaultNixPath(), "nix-path",
|
this, getDefaultNixPath(), "nix-path",
|
||||||
"List of directories to be searched for `<...>` file references."};
|
R"(
|
||||||
|
List of directories to be searched for `<...>` file references
|
||||||
|
|
||||||
|
In particular, outside of [pure evaluation mode](#conf-pure-evaluation), this determines the value of
|
||||||
|
[`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtin-constants-nixPath).
|
||||||
|
)"};
|
||||||
|
|
||||||
Setting<bool> restrictEval{
|
Setting<bool> restrictEval{
|
||||||
this, false, "restrict-eval",
|
this, false, "restrict-eval",
|
||||||
|
@ -741,11 +815,18 @@ struct EvalSettings : Config
|
||||||
If set to `true`, the Nix evaluator will not allow access to any
|
If set to `true`, the Nix evaluator will not allow access to any
|
||||||
files outside of the Nix search path (as set via the `NIX_PATH`
|
files outside of the Nix search path (as set via the `NIX_PATH`
|
||||||
environment variable or the `-I` option), or to URIs outside of
|
environment variable or the `-I` option), or to URIs outside of
|
||||||
`allowed-uri`. The default is `false`.
|
[`allowed-uris`](../command-ref/conf-file.md#conf-allowed-uris).
|
||||||
|
The default is `false`.
|
||||||
)"};
|
)"};
|
||||||
|
|
||||||
Setting<bool> pureEval{this, false, "pure-eval",
|
Setting<bool> pureEval{this, false, "pure-eval",
|
||||||
"Whether to restrict file system and network access to files specified by cryptographic hash."};
|
R"(
|
||||||
|
Pure evaluation mode ensures that the result of Nix expressions is fully determined by explicitly declared inputs, and not influenced by external state:
|
||||||
|
|
||||||
|
- Restrict file system and network access to files specified by cryptographic hash
|
||||||
|
- Disable [`bultins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem) and [`builtins.currentTime`](@docroot@/language/builtin-constants.md#builtins-currentTime)
|
||||||
|
)"
|
||||||
|
};
|
||||||
|
|
||||||
Setting<bool> enableImportFromDerivation{
|
Setting<bool> enableImportFromDerivation{
|
||||||
this, true, "allow-import-from-derivation",
|
this, true, "allow-import-from-derivation",
|
||||||
|
|
|
@ -788,9 +788,6 @@ static RegisterPrimOp r2({
|
||||||
```nix
|
```nix
|
||||||
(builtins.getFlake "github:edolstra/dwarffs").rev
|
(builtins.getFlake "github:edolstra/dwarffs").rev
|
||||||
```
|
```
|
||||||
|
|
||||||
This function is only available if you enable the experimental feature
|
|
||||||
`flakes`.
|
|
||||||
)",
|
)",
|
||||||
.fun = prim_getFlake,
|
.fun = prim_getFlake,
|
||||||
.experimentalFeature = Xp::Flakes,
|
.experimentalFeature = Xp::Flakes,
|
||||||
|
|
|
@ -36,7 +36,7 @@ static inline PosIdx makeCurPos(const YYLTYPE & loc, ParseData * data)
|
||||||
#define CUR_POS makeCurPos(*yylloc, data)
|
#define CUR_POS makeCurPos(*yylloc, data)
|
||||||
|
|
||||||
// backup to recover from yyless(0)
|
// backup to recover from yyless(0)
|
||||||
YYLTYPE prev_yylloc;
|
thread_local YYLTYPE prev_yylloc;
|
||||||
|
|
||||||
static void initLoc(YYLTYPE * loc)
|
static void initLoc(YYLTYPE * loc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -275,7 +275,12 @@ static Expr * stripIndentation(const PosIdx pos, SymbolTable & symbols,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a single string, then don't do a concatenation. */
|
/* If this is a single string, then don't do a concatenation. */
|
||||||
return es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second) ? (*es2)[0].second : new ExprConcatStrings(pos, true, es2);
|
if (es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second)) {
|
||||||
|
auto *const result = (*es2)[0].second;
|
||||||
|
delete es2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return new ExprConcatStrings(pos, true, es2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,7 +335,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||||
%type <ind_string_parts> ind_string_parts
|
%type <ind_string_parts> ind_string_parts
|
||||||
%type <e> path_start string_parts string_attr
|
%type <e> path_start string_parts string_attr
|
||||||
%type <id> attr
|
%type <id> attr
|
||||||
%token <id> ID ATTRPATH
|
%token <id> ID
|
||||||
%token <str> STR IND_STR
|
%token <str> STR IND_STR
|
||||||
%token <n> INT
|
%token <n> INT
|
||||||
%token <nf> FLOAT
|
%token <nf> FLOAT
|
||||||
|
@ -658,7 +663,7 @@ Expr * EvalState::parse(
|
||||||
ParseData data {
|
ParseData data {
|
||||||
.state = *this,
|
.state = *this,
|
||||||
.symbols = symbols,
|
.symbols = symbols,
|
||||||
.basePath = std::move(basePath),
|
.basePath = basePath,
|
||||||
.origin = {origin},
|
.origin = {origin},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -729,19 +734,9 @@ Expr * EvalState::parseStdin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::addToSearchPath(const std::string & s)
|
void EvalState::addToSearchPath(SearchPath::Elem && elem)
|
||||||
{
|
{
|
||||||
size_t pos = s.find('=');
|
searchPath.elements.emplace_back(std::move(elem));
|
||||||
std::string prefix;
|
|
||||||
Path path;
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
path = s;
|
|
||||||
} else {
|
|
||||||
prefix = std::string(s, 0, pos);
|
|
||||||
path = std::string(s, pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPath.emplace_back(prefix, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -751,22 +746,19 @@ SourcePath EvalState::findFile(const std::string_view path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SourcePath EvalState::findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos)
|
||||||
{
|
{
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath.elements) {
|
||||||
std::string suffix;
|
auto suffixOpt = i.prefix.suffixIfPotentialMatch(path);
|
||||||
if (i.first.empty())
|
|
||||||
suffix = concatStrings("/", path);
|
if (!suffixOpt) continue;
|
||||||
else {
|
auto suffix = *suffixOpt;
|
||||||
auto s = i.first.size();
|
|
||||||
if (path.compare(0, s, i.first) != 0 ||
|
auto rOpt = resolveSearchPathPath(i.path);
|
||||||
(path.size() > s && path[s] != '/'))
|
if (!rOpt) continue;
|
||||||
continue;
|
auto r = *rOpt;
|
||||||
suffix = path.size() == s ? "" : concatStrings("/", path.substr(s));
|
|
||||||
}
|
Path res = suffix == "" ? r : concatStrings(r, "/", suffix);
|
||||||
auto r = resolveSearchPathElem(i);
|
|
||||||
if (!r.first) continue;
|
|
||||||
Path res = r.second + suffix;
|
|
||||||
if (pathExists(res)) return CanonPath(canonPath(res));
|
if (pathExists(res)) return CanonPath(canonPath(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,49 +775,53 @@ SourcePath EvalState::findFile(SearchPath & searchPath, const std::string_view p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathElem & elem)
|
std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Path & value0)
|
||||||
{
|
{
|
||||||
auto i = searchPathResolved.find(elem.second);
|
auto & value = value0.s;
|
||||||
|
auto i = searchPathResolved.find(value);
|
||||||
if (i != searchPathResolved.end()) return i->second;
|
if (i != searchPathResolved.end()) return i->second;
|
||||||
|
|
||||||
std::pair<bool, std::string> res;
|
std::optional<std::string> res;
|
||||||
|
|
||||||
if (EvalSettings::isPseudoUrl(elem.second)) {
|
if (EvalSettings::isPseudoUrl(value)) {
|
||||||
try {
|
try {
|
||||||
auto storePath = fetchers::downloadTarball(
|
auto storePath = fetchers::downloadTarball(
|
||||||
store, EvalSettings::resolvePseudoUrl(elem.second), "source", false).first.storePath;
|
store, EvalSettings::resolvePseudoUrl(value), "source", false).tree.storePath;
|
||||||
res = { true, store->toRealPath(storePath) };
|
res = { store->toRealPath(storePath) };
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
logWarning({
|
logWarning({
|
||||||
.msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second)
|
.msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value)
|
||||||
});
|
});
|
||||||
res = { false, "" };
|
res = std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (hasPrefix(elem.second, "flake:")) {
|
else if (hasPrefix(value, "flake:")) {
|
||||||
experimentalFeatureSettings.require(Xp::Flakes);
|
experimentalFeatureSettings.require(Xp::Flakes);
|
||||||
auto flakeRef = parseFlakeRef(elem.second.substr(6), {}, true, false);
|
auto flakeRef = parseFlakeRef(value.substr(6), {}, true, false);
|
||||||
debug("fetching flake search path element '%s''", elem.second);
|
debug("fetching flake search path element '%s''", value);
|
||||||
auto storePath = flakeRef.resolve(store).fetchTree(store).first.storePath;
|
auto storePath = flakeRef.resolve(store).fetchTree(store).first.storePath;
|
||||||
res = { true, store->toRealPath(storePath) };
|
res = { store->toRealPath(storePath) };
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
auto path = absPath(elem.second);
|
auto path = absPath(value);
|
||||||
if (pathExists(path))
|
if (pathExists(path))
|
||||||
res = { true, path };
|
res = { path };
|
||||||
else {
|
else {
|
||||||
logWarning({
|
logWarning({
|
||||||
.msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", elem.second)
|
.msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", value)
|
||||||
});
|
});
|
||||||
res = { false, "" };
|
res = std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("resolved search path element '%s' to '%s'", elem.second, res.second);
|
if (res)
|
||||||
|
debug("resolved search path element '%s' to '%s'", value, *res);
|
||||||
|
else
|
||||||
|
debug("failed to resolve search path element '%s'", value);
|
||||||
|
|
||||||
searchPathResolved[elem.second] = res;
|
searchPathResolved[value] = res;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "json-to-value.hh"
|
#include "json-to-value.hh"
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
#include "references.hh"
|
#include "path-references.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "value-to-json.hh"
|
#include "value-to-json.hh"
|
||||||
|
@ -87,7 +88,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context)
|
||||||
auto outputs = resolveDerivedPath(*store, drv);
|
auto outputs = resolveDerivedPath(*store, drv);
|
||||||
for (auto & [outputName, outputPath] : outputs) {
|
for (auto & [outputName, outputPath] : outputs) {
|
||||||
res.insert_or_assign(
|
res.insert_or_assign(
|
||||||
downstreamPlaceholder(*store, drv.drvPath, outputName),
|
DownstreamPlaceholder::unknownCaOutput(drv.drvPath, outputName).render(),
|
||||||
store->printStorePath(outputPath)
|
store->printStorePath(outputPath)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +238,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_scopedImport(PrimOp {
|
||||||
.name = "scopedImport",
|
.name = "scopedImport",
|
||||||
.arity = 2,
|
.arity = 2,
|
||||||
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
@ -691,7 +692,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a
|
||||||
v.listElems()[n++] = i;
|
v.listElems()[n++] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_genericClosure(PrimOp {
|
||||||
.name = "__genericClosure",
|
.name = "__genericClosure",
|
||||||
.args = {"attrset"},
|
.args = {"attrset"},
|
||||||
.arity = 1,
|
.arity = 1,
|
||||||
|
@ -808,7 +809,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_addErrorContext(PrimOp {
|
||||||
.name = "__addErrorContext",
|
.name = "__addErrorContext",
|
||||||
.arity = 2,
|
.arity = 2,
|
||||||
.fun = prim_addErrorContext,
|
.fun = prim_addErrorContext,
|
||||||
|
@ -1151,16 +1152,14 @@ drvName, Bindings * attrs, Value & v)
|
||||||
if (i->value->type() == nNull) continue;
|
if (i->value->type() == nNull) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->name == state.sContentAddressed) {
|
if (i->name == state.sContentAddressed && state.forceBool(*i->value, noPos, context_below)) {
|
||||||
contentAddressed = state.forceBool(*i->value, noPos, context_below);
|
contentAddressed = true;
|
||||||
if (contentAddressed)
|
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (i->name == state.sImpure) {
|
else if (i->name == state.sImpure && state.forceBool(*i->value, noPos, context_below)) {
|
||||||
isImpure = state.forceBool(*i->value, noPos, context_below);
|
isImpure = true;
|
||||||
if (isImpure)
|
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
||||||
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The `args' attribute is special: it supplies the
|
/* The `args' attribute is special: it supplies the
|
||||||
|
@ -1401,7 +1400,7 @@ drvName, Bindings * attrs, Value & v)
|
||||||
v.mkAttrs(result);
|
v.mkAttrs(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_derivationStrict(PrimOp {
|
||||||
.name = "derivationStrict",
|
.name = "derivationStrict",
|
||||||
.arity = 1,
|
.arity = 1,
|
||||||
.fun = prim_derivationStrict,
|
.fun = prim_derivationStrict,
|
||||||
|
@ -1502,7 +1501,9 @@ static RegisterPrimOp primop_storePath({
|
||||||
causes the path to be *copied* again to the Nix store, resulting
|
causes the path to be *copied* again to the Nix store, resulting
|
||||||
in a new path (e.g. `/nix/store/ld01dnzc…-source-source`).
|
in a new path (e.g. `/nix/store/ld01dnzc…-source-source`).
|
||||||
|
|
||||||
This function is not available in pure evaluation mode.
|
Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
|
||||||
|
See also [`builtins.fetchClosure`](#builtins-fetchClosure).
|
||||||
)",
|
)",
|
||||||
.fun = prim_storePath,
|
.fun = prim_storePath,
|
||||||
});
|
});
|
||||||
|
@ -1657,7 +1658,10 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPath.emplace_back(prefix, path);
|
searchPath.elements.emplace_back(SearchPath::Elem {
|
||||||
|
.prefix = SearchPath::Prefix { .s = prefix },
|
||||||
|
.path = SearchPath::Path { .s = path },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto path = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");
|
auto path = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile");
|
||||||
|
@ -1665,9 +1669,52 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_findFile(PrimOp {
|
||||||
.name = "__findFile",
|
.name = "__findFile",
|
||||||
.arity = 2,
|
.args = {"search path", "lookup path"},
|
||||||
|
.doc = R"(
|
||||||
|
Look up the given path with the given search path.
|
||||||
|
|
||||||
|
A search path is represented list of [attribute sets](./values.md#attribute-set) with two attributes, `prefix`, and `path`.
|
||||||
|
`prefix` is a relative path.
|
||||||
|
`path` denotes a file system location; the exact syntax depends on the command line interface.
|
||||||
|
|
||||||
|
Examples of search path attribute sets:
|
||||||
|
|
||||||
|
- ```
|
||||||
|
{
|
||||||
|
prefix = "nixos-config";
|
||||||
|
path = "/etc/nixos/configuration.nix";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- ```
|
||||||
|
{
|
||||||
|
prefix = "";
|
||||||
|
path = "/nix/var/nix/profiles/per-user/root/channels";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The lookup algorithm checks each entry until a match is found, returning a [path value](@docroot@/language/values.html#type-path) of the match.
|
||||||
|
|
||||||
|
This is the process for each entry:
|
||||||
|
If the lookup path matches `prefix`, then the remainder of the lookup path (the "suffix") is searched for within the directory denoted by `patch`.
|
||||||
|
Note that the `path` may need to be downloaded at this point to look inside.
|
||||||
|
If the suffix is found inside that directory, then the entry is a match;
|
||||||
|
the combined absolute path of the directory (now downloaded if need be) and the suffix is returned.
|
||||||
|
|
||||||
|
The syntax
|
||||||
|
|
||||||
|
```nix
|
||||||
|
<nixpkgs>
|
||||||
|
```
|
||||||
|
|
||||||
|
is equivalent to:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.findFile builtins.nixPath "nixpkgs"
|
||||||
|
```
|
||||||
|
)",
|
||||||
.fun = prim_findFile,
|
.fun = prim_findFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2386,7 +2433,7 @@ static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * *
|
||||||
state.mkPos(v, i->pos);
|
state.mkPos(v, i->pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_unsafeGetAttrPos(PrimOp {
|
||||||
.name = "__unsafeGetAttrPos",
|
.name = "__unsafeGetAttrPos",
|
||||||
.arity = 2,
|
.arity = 2,
|
||||||
.fun = prim_unsafeGetAttrPos,
|
.fun = prim_unsafeGetAttrPos,
|
||||||
|
@ -3909,13 +3956,8 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
for (auto elem : args[0]->listItems())
|
for (auto elem : args[0]->listItems())
|
||||||
from.emplace_back(state.forceString(*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
from.emplace_back(state.forceString(*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
||||||
|
|
||||||
std::vector<std::pair<std::string, NixStringContext>> to;
|
std::unordered_map<size_t, std::string> cache;
|
||||||
to.reserve(args[1]->listSize());
|
auto to = args[1]->listItems();
|
||||||
for (auto elem : args[1]->listItems()) {
|
|
||||||
NixStringContext ctx;
|
|
||||||
auto s = state.forceString(*elem, ctx, pos, "while evaluating one of the replacement strings passed to builtins.replaceStrings");
|
|
||||||
to.emplace_back(s, std::move(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
||||||
|
@ -3926,10 +3968,19 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
bool found = false;
|
bool found = false;
|
||||||
auto i = from.begin();
|
auto i = from.begin();
|
||||||
auto j = to.begin();
|
auto j = to.begin();
|
||||||
for (; i != from.end(); ++i, ++j)
|
size_t j_index = 0;
|
||||||
|
for (; i != from.end(); ++i, ++j, ++j_index)
|
||||||
if (s.compare(p, i->size(), *i) == 0) {
|
if (s.compare(p, i->size(), *i) == 0) {
|
||||||
found = true;
|
found = true;
|
||||||
res += j->first;
|
auto v = cache.find(j_index);
|
||||||
|
if (v == cache.end()) {
|
||||||
|
NixStringContext ctx;
|
||||||
|
auto ts = state.forceString(**j, ctx, pos, "while evaluating one of the replacement strings passed to builtins.replaceStrings");
|
||||||
|
v = (cache.emplace(j_index, ts)).first;
|
||||||
|
for (auto& path : ctx)
|
||||||
|
context.insert(path);
|
||||||
|
}
|
||||||
|
res += v->second;
|
||||||
if (i->empty()) {
|
if (i->empty()) {
|
||||||
if (p < s.size())
|
if (p < s.size())
|
||||||
res += s[p];
|
res += s[p];
|
||||||
|
@ -3937,9 +3988,6 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
} else {
|
} else {
|
||||||
p += i->size();
|
p += i->size();
|
||||||
}
|
}
|
||||||
for (auto& path : j->second)
|
|
||||||
context.insert(path);
|
|
||||||
j->second.clear();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -3957,7 +4005,11 @@ static RegisterPrimOp primop_replaceStrings({
|
||||||
.args = {"from", "to", "s"},
|
.args = {"from", "to", "s"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Given string *s*, replace every occurrence of the strings in *from*
|
Given string *s*, replace every occurrence of the strings in *from*
|
||||||
with the corresponding string in *to*. For example,
|
with the corresponding string in *to*.
|
||||||
|
|
||||||
|
The argument *to* is lazy, that is, it is only evaluated when its corresponding pattern in *from* is matched in the string *s*
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
|
builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
|
||||||
|
@ -4054,22 +4106,10 @@ static RegisterPrimOp primop_splitVersion({
|
||||||
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
|
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
|
||||||
|
|
||||||
|
|
||||||
RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun)
|
RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
|
||||||
{
|
{
|
||||||
if (!primOps) primOps = new PrimOps;
|
if (!primOps) primOps = new PrimOps;
|
||||||
primOps->push_back({
|
primOps->push_back(std::move(primOp));
|
||||||
.name = name,
|
|
||||||
.args = {},
|
|
||||||
.arity = arity,
|
|
||||||
.fun = fun,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RegisterPrimOp::RegisterPrimOp(Info && info)
|
|
||||||
{
|
|
||||||
if (!primOps) primOps = new PrimOps;
|
|
||||||
primOps->push_back(std::move(info));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4082,85 +4122,253 @@ void EvalState::createBaseEnv()
|
||||||
|
|
||||||
/* `builtins' must be first! */
|
/* `builtins' must be first! */
|
||||||
v.mkAttrs(buildBindings(128).finish());
|
v.mkAttrs(buildBindings(128).finish());
|
||||||
addConstant("builtins", v);
|
addConstant("builtins", v, {
|
||||||
|
.type = nAttrs,
|
||||||
|
.doc = R"(
|
||||||
|
Contains all the [built-in functions](@docroot@/language/builtins.md) and values.
|
||||||
|
|
||||||
|
Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# if hasContext is not available, we assume `s` has a context
|
||||||
|
if builtins ? hasContext then builtins.hasContext s else true
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
v.mkBool(true);
|
v.mkBool(true);
|
||||||
addConstant("true", v);
|
addConstant("true", v, {
|
||||||
|
.type = nBool,
|
||||||
|
.doc = R"(
|
||||||
|
Primitive value.
|
||||||
|
|
||||||
|
It can be returned by
|
||||||
|
[comparison operators](@docroot@/language/operators.md#Comparison)
|
||||||
|
and used in
|
||||||
|
[conditional expressions](@docroot@/language/constructs.md#Conditionals).
|
||||||
|
|
||||||
|
The name `true` is not special, and can be shadowed:
|
||||||
|
|
||||||
|
```nix-repl
|
||||||
|
nix-repl> let true = 1; in true
|
||||||
|
1
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
v.mkBool(false);
|
v.mkBool(false);
|
||||||
addConstant("false", v);
|
addConstant("false", v, {
|
||||||
|
.type = nBool,
|
||||||
|
.doc = R"(
|
||||||
|
Primitive value.
|
||||||
|
|
||||||
|
It can be returned by
|
||||||
|
[comparison operators](@docroot@/language/operators.md#Comparison)
|
||||||
|
and used in
|
||||||
|
[conditional expressions](@docroot@/language/constructs.md#Conditionals).
|
||||||
|
|
||||||
|
The name `false` is not special, and can be shadowed:
|
||||||
|
|
||||||
|
```nix-repl
|
||||||
|
nix-repl> let false = 1; in false
|
||||||
|
1
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
v.mkNull();
|
v.mkNull();
|
||||||
addConstant("null", v);
|
addConstant("null", v, {
|
||||||
|
.type = nNull,
|
||||||
|
.doc = R"(
|
||||||
|
Primitive value.
|
||||||
|
|
||||||
|
The name `null` is not special, and can be shadowed:
|
||||||
|
|
||||||
|
```nix-repl
|
||||||
|
nix-repl> let null = 1; in null
|
||||||
|
1
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
if (!evalSettings.pureEval) {
|
if (!evalSettings.pureEval) {
|
||||||
v.mkInt(time(0));
|
v.mkInt(time(0));
|
||||||
addConstant("__currentTime", v);
|
|
||||||
|
|
||||||
v.mkString(settings.thisSystem.get());
|
|
||||||
addConstant("__currentSystem", v);
|
|
||||||
}
|
}
|
||||||
|
addConstant("__currentTime", v, {
|
||||||
|
.type = nInt,
|
||||||
|
.doc = R"(
|
||||||
|
Return the [Unix time](https://en.wikipedia.org/wiki/Unix_time) at first evaluation.
|
||||||
|
Repeated references to that name will re-use the initially obtained value.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix repl
|
||||||
|
Welcome to Nix 2.15.1 Type :? for help.
|
||||||
|
|
||||||
|
nix-repl> builtins.currentTime
|
||||||
|
1683705525
|
||||||
|
|
||||||
|
nix-repl> builtins.currentTime
|
||||||
|
1683705525
|
||||||
|
```
|
||||||
|
|
||||||
|
The [store path](@docroot@/glossary.md#gloss-store-path) of a derivation depending on `currentTime` will differ for each evaluation, unless both evaluate `builtins.currentTime` in the same second.
|
||||||
|
)",
|
||||||
|
.impureOnly = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!evalSettings.pureEval) {
|
||||||
|
v.mkString(settings.thisSystem.get());
|
||||||
|
}
|
||||||
|
addConstant("__currentSystem", v, {
|
||||||
|
.type = nString,
|
||||||
|
.doc = R"(
|
||||||
|
The value of the [`system` configuration option](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
|
||||||
|
It can be used to set the `system` attribute for [`builtins.derivation`](@docroot@/language/derivations.md) such that the resulting derivation can be built on the same system that evaluates the Nix expression:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.derivation {
|
||||||
|
# ...
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It can be overridden in order to create derivations for different system than the current one:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-instantiate --system "mips64-linux" --eval --expr 'builtins.currentSystem'
|
||||||
|
"mips64-linux"
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
.impureOnly = true,
|
||||||
|
});
|
||||||
|
|
||||||
v.mkString(nixVersion);
|
v.mkString(nixVersion);
|
||||||
addConstant("__nixVersion", v);
|
addConstant("__nixVersion", v, {
|
||||||
|
.type = nString,
|
||||||
|
.doc = R"(
|
||||||
|
The version of Nix.
|
||||||
|
|
||||||
|
For example, where the command line returns the current Nix version,
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ nix --version
|
||||||
|
nix (Nix) 2.16.0
|
||||||
|
```
|
||||||
|
|
||||||
|
the Nix language evaluator returns the same value:
|
||||||
|
|
||||||
|
```nix-repl
|
||||||
|
nix-repl> builtins.nixVersion
|
||||||
|
"2.16.0"
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
v.mkString(store->storeDir);
|
v.mkString(store->storeDir);
|
||||||
addConstant("__storeDir", v);
|
addConstant("__storeDir", v, {
|
||||||
|
.type = nString,
|
||||||
|
.doc = R"(
|
||||||
|
Logical file system location of the [Nix store](@docroot@/glossary.md#gloss-store) currently in use.
|
||||||
|
|
||||||
|
This value is determined by the `store` parameter in [Store URLs](@docroot@/command-ref/new-cli/nix3-help-stores.md):
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ nix-instantiate --store 'dummy://?store=/blah' --eval --expr builtins.storeDir
|
||||||
|
"/blah"
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
/* Language version. This should be increased every time a new
|
/* Language version. This should be increased every time a new
|
||||||
language feature gets added. It's not necessary to increase it
|
language feature gets added. It's not necessary to increase it
|
||||||
when primops get added, because you can just use `builtins ?
|
when primops get added, because you can just use `builtins ?
|
||||||
primOp' to check. */
|
primOp' to check. */
|
||||||
v.mkInt(6);
|
v.mkInt(6);
|
||||||
addConstant("__langVersion", v);
|
addConstant("__langVersion", v, {
|
||||||
|
.type = nInt,
|
||||||
|
.doc = R"(
|
||||||
|
The current version of the Nix language.
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
if (evalSettings.enableNativeCode) {
|
if (evalSettings.enableNativeCode) {
|
||||||
addPrimOp("__importNative", 2, prim_importNative);
|
addPrimOp({
|
||||||
addPrimOp("__exec", 1, prim_exec);
|
.name = "__importNative",
|
||||||
|
.arity = 2,
|
||||||
|
.fun = prim_importNative,
|
||||||
|
});
|
||||||
|
addPrimOp({
|
||||||
|
.name = "__exec",
|
||||||
|
.arity = 1,
|
||||||
|
.fun = prim_exec,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addPrimOp({
|
addPrimOp({
|
||||||
.fun = evalSettings.traceVerbose ? prim_trace : prim_second,
|
|
||||||
.arity = 2,
|
|
||||||
.name = "__traceVerbose",
|
.name = "__traceVerbose",
|
||||||
.args = { "e1", "e2" },
|
.args = { "e1", "e2" },
|
||||||
|
.arity = 2,
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Evaluate *e1* and print its abstract syntax representation on standard
|
Evaluate *e1* and print its abstract syntax representation on standard
|
||||||
error if `--trace-verbose` is enabled. Then return *e2*. This function
|
error if `--trace-verbose` is enabled. Then return *e2*. This function
|
||||||
is useful for debugging.
|
is useful for debugging.
|
||||||
)",
|
)",
|
||||||
|
.fun = evalSettings.traceVerbose ? prim_trace : prim_second,
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Add a value containing the current Nix expression search path. */
|
/* Add a value containing the current Nix expression search path. */
|
||||||
mkList(v, searchPath.size());
|
mkList(v, searchPath.elements.size());
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath.elements) {
|
||||||
auto attrs = buildBindings(2);
|
auto attrs = buildBindings(2);
|
||||||
attrs.alloc("path").mkString(i.second);
|
attrs.alloc("path").mkString(i.path.s);
|
||||||
attrs.alloc("prefix").mkString(i.first);
|
attrs.alloc("prefix").mkString(i.prefix.s);
|
||||||
(v.listElems()[n++] = allocValue())->mkAttrs(attrs);
|
(v.listElems()[n++] = allocValue())->mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
addConstant("__nixPath", v);
|
addConstant("__nixPath", v, {
|
||||||
|
.type = nList,
|
||||||
|
.doc = R"(
|
||||||
|
The search path used to resolve angle bracket path lookups.
|
||||||
|
|
||||||
|
Angle bracket expressions can be
|
||||||
|
[desugared](https://en.wikipedia.org/wiki/Syntactic_sugar)
|
||||||
|
using this and
|
||||||
|
[`builtins.findFile`](./builtins.html#builtins-findFile):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
<nixpkgs>
|
||||||
|
```
|
||||||
|
|
||||||
|
is equivalent to:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.findFile builtins.nixPath "nixpkgs"
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
});
|
||||||
|
|
||||||
if (RegisterPrimOp::primOps)
|
if (RegisterPrimOp::primOps)
|
||||||
for (auto & primOp : *RegisterPrimOp::primOps)
|
for (auto & primOp : *RegisterPrimOp::primOps)
|
||||||
if (!primOp.experimentalFeature
|
if (experimentalFeatureSettings.isEnabled(primOp.experimentalFeature))
|
||||||
|| experimentalFeatureSettings.isEnabled(*primOp.experimentalFeature))
|
|
||||||
{
|
{
|
||||||
addPrimOp({
|
auto primOpAdjusted = primOp;
|
||||||
.fun = primOp.fun,
|
primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity);
|
||||||
.arity = std::max(primOp.args.size(), primOp.arity),
|
addPrimOp(std::move(primOpAdjusted));
|
||||||
.name = primOp.name,
|
|
||||||
.args = primOp.args,
|
|
||||||
.doc = primOp.doc,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a wrapper around the derivation primop that computes the
|
/* Add a wrapper around the derivation primop that computes the
|
||||||
`drvPath' and `outPath' attributes lazily. */
|
`drvPath' and `outPath' attributes lazily.
|
||||||
|
|
||||||
|
Null docs because it is documented separately.
|
||||||
|
*/
|
||||||
auto vDerivation = allocValue();
|
auto vDerivation = allocValue();
|
||||||
addConstant("derivation", vDerivation);
|
addConstant("derivation", vDerivation, {
|
||||||
|
.type = nFunction,
|
||||||
|
});
|
||||||
|
|
||||||
/* Now that we've added all primops, sort the `builtins' set,
|
/* Now that we've added all primops, sort the `builtins' set,
|
||||||
because attribute lookups expect it to be sorted. */
|
because attribute lookups expect it to be sorted. */
|
||||||
|
|
|
@ -10,17 +10,7 @@ namespace nix {
|
||||||
|
|
||||||
struct RegisterPrimOp
|
struct RegisterPrimOp
|
||||||
{
|
{
|
||||||
struct Info
|
typedef std::vector<PrimOp> PrimOps;
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::vector<std::string> args;
|
|
||||||
size_t arity = 0;
|
|
||||||
const char * doc;
|
|
||||||
PrimOpFun fun;
|
|
||||||
std::optional<ExperimentalFeature> experimentalFeature;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<Info> PrimOps;
|
|
||||||
static PrimOps * primOps;
|
static PrimOps * primOps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,12 +18,7 @@ struct RegisterPrimOp
|
||||||
* will get called during EvalState initialization, so there
|
* will get called during EvalState initialization, so there
|
||||||
* may be primops not yet added and builtins is not yet sorted.
|
* may be primops not yet added and builtins is not yet sorted.
|
||||||
*/
|
*/
|
||||||
RegisterPrimOp(
|
RegisterPrimOp(PrimOp && primOp);
|
||||||
std::string name,
|
|
||||||
size_t arity,
|
|
||||||
PrimOpFun fun);
|
|
||||||
|
|
||||||
RegisterPrimOp(Info && info);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These primops are disabled without enableNativeCode, but plugins
|
/* These primops are disabled without enableNativeCode, but plugins
|
||||||
|
|
|
@ -12,7 +12,11 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos,
|
||||||
v.mkString(*s);
|
v.mkString(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
static RegisterPrimOp primop_unsafeDiscardStringContext({
|
||||||
|
.name = "__unsafeDiscardStringContext",
|
||||||
|
.arity = 1,
|
||||||
|
.fun = prim_unsafeDiscardStringContext
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
|
@ -22,7 +26,16 @@ static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
v.mkBool(!context.empty());
|
v.mkBool(!context.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
|
static RegisterPrimOp primop_hasContext({
|
||||||
|
.name = "__hasContext",
|
||||||
|
.args = {"s"},
|
||||||
|
.doc = R"(
|
||||||
|
Return `true` if string *s* has a non-empty context. The
|
||||||
|
context can be obtained with
|
||||||
|
[`getContext`](#builtins-getContext).
|
||||||
|
)",
|
||||||
|
.fun = prim_hasContext
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
|
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
|
||||||
|
@ -51,7 +64,11 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx p
|
||||||
v.mkString(*s, context2);
|
v.mkString(*s, context2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
static RegisterPrimOp primop_unsafeDiscardOutputDependency({
|
||||||
|
.name = "__unsafeDiscardOutputDependency",
|
||||||
|
.arity = 1,
|
||||||
|
.fun = prim_unsafeDiscardOutputDependency
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* Extract the context of a string as a structured Nix value.
|
/* Extract the context of a string as a structured Nix value.
|
||||||
|
@ -119,7 +136,30 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
|
static RegisterPrimOp primop_getContext({
|
||||||
|
.name = "__getContext",
|
||||||
|
.args = {"s"},
|
||||||
|
.doc = R"(
|
||||||
|
Return the string context of *s*.
|
||||||
|
|
||||||
|
The string context tracks references to derivations within a string.
|
||||||
|
It is represented as an attribute set of [store derivation](@docroot@/glossary.md#gloss-store-derivation) paths mapping to output names.
|
||||||
|
|
||||||
|
Using [string interpolation](@docroot@/language/string-interpolation.md) on a derivation will add that derivation to the string context.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.getContext "${derivation { name = "a"; builder = "b"; system = "c"; }}"
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to
|
||||||
|
|
||||||
|
```
|
||||||
|
{ "/nix/store/arhvjaf6zmlyn8vh8fgn55rpwnxq0n7l-a.drv" = { outputs = [ "out" ]; }; }
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
.fun = prim_getContext
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* Append the given context to a given string.
|
/* Append the given context to a given string.
|
||||||
|
@ -192,6 +232,10 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar
|
||||||
v.mkString(orig, context);
|
v.mkString(orig, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_appendContext("__appendContext", 2, prim_appendContext);
|
static RegisterPrimOp primop_appendContext({
|
||||||
|
.name = "__appendContext",
|
||||||
|
.arity = 2,
|
||||||
|
.fun = prim_appendContext
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,37 +5,150 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the content addressed case.
|
||||||
|
*
|
||||||
|
* @param state Evaluator state and store to write to.
|
||||||
|
* @param fromStore Store containing the path to rewrite.
|
||||||
|
* @param fromPath Source path to be rewritten.
|
||||||
|
* @param toPathMaybe Path to write the rewritten path to. If empty, the error shows the actual path.
|
||||||
|
* @param v Return `Value`
|
||||||
|
*/
|
||||||
|
static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Store & fromStore, const StorePath & fromPath, const std::optional<StorePath> & toPathMaybe, Value &v) {
|
||||||
|
|
||||||
|
// establish toPath or throw
|
||||||
|
|
||||||
|
if (!toPathMaybe || !state.store->isValidPath(*toPathMaybe)) {
|
||||||
|
auto rewrittenPath = makeContentAddressed(fromStore, *state.store, fromPath);
|
||||||
|
if (toPathMaybe && *toPathMaybe != rewrittenPath)
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt("rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected",
|
||||||
|
state.store->printStorePath(fromPath),
|
||||||
|
state.store->printStorePath(rewrittenPath),
|
||||||
|
state.store->printStorePath(*toPathMaybe)),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
if (!toPathMaybe)
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt(
|
||||||
|
"rewriting '%s' to content-addressed form yielded '%s'\n"
|
||||||
|
"Use this value for the 'toPath' attribute passed to 'fetchClosure'",
|
||||||
|
state.store->printStorePath(fromPath),
|
||||||
|
state.store->printStorePath(rewrittenPath)),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto toPath = *toPathMaybe;
|
||||||
|
|
||||||
|
// check and return
|
||||||
|
|
||||||
|
auto resultInfo = state.store->queryPathInfo(toPath);
|
||||||
|
|
||||||
|
if (!resultInfo->isContentAddressed(*state.store)) {
|
||||||
|
// We don't perform the rewriting when outPath already exists, as an optimisation.
|
||||||
|
// However, we can quickly detect a mistake if the toPath is input addressed.
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt(
|
||||||
|
"The 'toPath' value '%s' is input-addressed, so it can't possibly be the result of rewriting to a content-addressed path.\n\n"
|
||||||
|
"Set 'toPath' to an empty string to make Nix report the correct content-addressed path.",
|
||||||
|
state.store->printStorePath(toPath)),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mkStorePathString(toPath, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the closure and make sure it's content addressed.
|
||||||
|
*/
|
||||||
|
static void runFetchClosureWithContentAddressedPath(EvalState & state, const PosIdx pos, Store & fromStore, const StorePath & fromPath, Value & v) {
|
||||||
|
|
||||||
|
if (!state.store->isValidPath(fromPath))
|
||||||
|
copyClosure(fromStore, *state.store, RealisedPath::Set { fromPath });
|
||||||
|
|
||||||
|
auto info = state.store->queryPathInfo(fromPath);
|
||||||
|
|
||||||
|
if (!info->isContentAddressed(*state.store)) {
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt(
|
||||||
|
"The 'fromPath' value '%s' is input-addressed, but 'inputAddressed' is set to 'false' (default).\n\n"
|
||||||
|
"If you do intend to fetch an input-addressed store path, add\n\n"
|
||||||
|
" inputAddressed = true;\n\n"
|
||||||
|
"to the 'fetchClosure' arguments.\n\n"
|
||||||
|
"Note that to ensure authenticity input-addressed store paths, users must configure a trusted binary cache public key on their systems. This is not needed for content-addressed paths.",
|
||||||
|
state.store->printStorePath(fromPath)),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mkStorePathString(fromPath, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the closure and make sure it's input addressed.
|
||||||
|
*/
|
||||||
|
static void runFetchClosureWithInputAddressedPath(EvalState & state, const PosIdx pos, Store & fromStore, const StorePath & fromPath, Value & v) {
|
||||||
|
|
||||||
|
if (!state.store->isValidPath(fromPath))
|
||||||
|
copyClosure(fromStore, *state.store, RealisedPath::Set { fromPath });
|
||||||
|
|
||||||
|
auto info = state.store->queryPathInfo(fromPath);
|
||||||
|
|
||||||
|
if (info->isContentAddressed(*state.store)) {
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt(
|
||||||
|
"The store object referred to by 'fromPath' at '%s' is not input-addressed, but 'inputAddressed' is set to 'true'.\n\n"
|
||||||
|
"Remove the 'inputAddressed' attribute (it defaults to 'false') to expect 'fromPath' to be content-addressed",
|
||||||
|
state.store->printStorePath(fromPath)),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mkStorePathString(fromPath, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::optional<StorePath> StorePathOrGap;
|
||||||
|
|
||||||
static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.fetchClosure");
|
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.fetchClosure");
|
||||||
|
|
||||||
std::optional<std::string> fromStoreUrl;
|
std::optional<std::string> fromStoreUrl;
|
||||||
std::optional<StorePath> fromPath;
|
std::optional<StorePath> fromPath;
|
||||||
bool toCA = false;
|
std::optional<StorePathOrGap> toPath;
|
||||||
std::optional<StorePath> toPath;
|
std::optional<bool> inputAddressedMaybe;
|
||||||
|
|
||||||
for (auto & attr : *args[0]->attrs) {
|
for (auto & attr : *args[0]->attrs) {
|
||||||
const auto & attrName = state.symbols[attr.name];
|
const auto & attrName = state.symbols[attr.name];
|
||||||
|
auto attrHint = [&]() -> std::string {
|
||||||
|
return "while evaluating the '" + attrName + "' attribute passed to builtins.fetchClosure";
|
||||||
|
};
|
||||||
|
|
||||||
if (attrName == "fromPath") {
|
if (attrName == "fromPath") {
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
fromPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint());
|
||||||
"while evaluating the 'fromPath' attribute passed to builtins.fetchClosure");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (attrName == "toPath") {
|
else if (attrName == "toPath") {
|
||||||
state.forceValue(*attr.value, attr.pos);
|
state.forceValue(*attr.value, attr.pos);
|
||||||
toCA = true;
|
bool isEmptyString = attr.value->type() == nString && attr.value->string.s == std::string("");
|
||||||
if (attr.value->type() != nString || attr.value->string.s != std::string("")) {
|
if (isEmptyString) {
|
||||||
|
toPath = StorePathOrGap {};
|
||||||
|
}
|
||||||
|
else {
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
toPath = state.coerceToStorePath(attr.pos, *attr.value, context,
|
toPath = state.coerceToStorePath(attr.pos, *attr.value, context, attrHint());
|
||||||
"while evaluating the 'toPath' attribute passed to builtins.fetchClosure");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (attrName == "fromStore")
|
else if (attrName == "fromStore")
|
||||||
fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos,
|
fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos,
|
||||||
"while evaluating the 'fromStore' attribute passed to builtins.fetchClosure");
|
attrHint());
|
||||||
|
|
||||||
|
else if (attrName == "inputAddressed")
|
||||||
|
inputAddressedMaybe = state.forceBool(*attr.value, attr.pos, attrHint());
|
||||||
|
|
||||||
else
|
else
|
||||||
throw Error({
|
throw Error({
|
||||||
|
@ -50,6 +163,18 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
.errPos = state.positions[pos]
|
.errPos = state.positions[pos]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool inputAddressed = inputAddressedMaybe.value_or(false);
|
||||||
|
|
||||||
|
if (inputAddressed) {
|
||||||
|
if (toPath)
|
||||||
|
throw Error({
|
||||||
|
.msg = hintfmt("attribute '%s' is set to true, but '%s' is also set. Please remove one of them",
|
||||||
|
"inputAddressed",
|
||||||
|
"toPath"),
|
||||||
|
.errPos = state.positions[pos]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!fromStoreUrl)
|
if (!fromStoreUrl)
|
||||||
throw Error({
|
throw Error({
|
||||||
.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"),
|
.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"),
|
||||||
|
@ -74,55 +199,40 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
|
|
||||||
auto fromStore = openStore(parsedURL.to_string());
|
auto fromStore = openStore(parsedURL.to_string());
|
||||||
|
|
||||||
if (toCA) {
|
if (toPath)
|
||||||
if (!toPath || !state.store->isValidPath(*toPath)) {
|
runFetchClosureWithRewrite(state, pos, *fromStore, *fromPath, *toPath, v);
|
||||||
auto remappings = makeContentAddressed(*fromStore, *state.store, { *fromPath });
|
else if (inputAddressed)
|
||||||
auto i = remappings.find(*fromPath);
|
runFetchClosureWithInputAddressedPath(state, pos, *fromStore, *fromPath, v);
|
||||||
assert(i != remappings.end());
|
else
|
||||||
if (toPath && *toPath != i->second)
|
runFetchClosureWithContentAddressedPath(state, pos, *fromStore, *fromPath, v);
|
||||||
throw Error({
|
|
||||||
.msg = hintfmt("rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected",
|
|
||||||
state.store->printStorePath(*fromPath),
|
|
||||||
state.store->printStorePath(i->second),
|
|
||||||
state.store->printStorePath(*toPath)),
|
|
||||||
.errPos = state.positions[pos]
|
|
||||||
});
|
|
||||||
if (!toPath)
|
|
||||||
throw Error({
|
|
||||||
.msg = hintfmt(
|
|
||||||
"rewriting '%s' to content-addressed form yielded '%s'; "
|
|
||||||
"please set this in the 'toPath' attribute passed to 'fetchClosure'",
|
|
||||||
state.store->printStorePath(*fromPath),
|
|
||||||
state.store->printStorePath(i->second)),
|
|
||||||
.errPos = state.positions[pos]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!state.store->isValidPath(*fromPath))
|
|
||||||
copyClosure(*fromStore, *state.store, RealisedPath::Set { *fromPath });
|
|
||||||
toPath = fromPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In pure mode, require a CA path. */
|
|
||||||
if (evalSettings.pureEval) {
|
|
||||||
auto info = state.store->queryPathInfo(*toPath);
|
|
||||||
if (!info->isContentAddressed(*state.store))
|
|
||||||
throw Error({
|
|
||||||
.msg = hintfmt("in pure mode, 'fetchClosure' requires a content-addressed path, which '%s' isn't",
|
|
||||||
state.store->printStorePath(*toPath)),
|
|
||||||
.errPos = state.positions[pos]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.mkStorePathString(*toPath, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_fetchClosure({
|
static RegisterPrimOp primop_fetchClosure({
|
||||||
.name = "__fetchClosure",
|
.name = "__fetchClosure",
|
||||||
.args = {"args"},
|
.args = {"args"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Fetch a Nix store closure from a binary cache, rewriting it into
|
Fetch a store path [closure](@docroot@/glossary.md#gloss-closure) from a binary cache, and return the store path as a string with context.
|
||||||
content-addressed form. For example,
|
|
||||||
|
This function can be invoked in three ways, that we will discuss in order of preference.
|
||||||
|
|
||||||
|
**Fetch a content-addressed store path**
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.fetchClosure {
|
||||||
|
fromStore = "https://cache.nixos.org";
|
||||||
|
fromPath = /nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the simplest invocation, and it does not require the user of the expression to configure [`trusted-public-keys`](@docroot@/command-ref/conf-file.md#conf-trusted-public-keys) to ensure their authenticity.
|
||||||
|
|
||||||
|
If your store path is [input addressed](@docroot@/glossary.md#gloss-input-addressed-store-object) instead of content addressed, consider the other two invocations.
|
||||||
|
|
||||||
|
**Fetch any store path and rewrite it to a fully content-addressed store path**
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
builtins.fetchClosure {
|
builtins.fetchClosure {
|
||||||
|
@ -132,31 +242,42 @@ static RegisterPrimOp primop_fetchClosure({
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
fetches `/nix/store/r2jd...` from the specified binary cache,
|
This example fetches `/nix/store/r2jd...` from the specified binary cache,
|
||||||
and rewrites it into the content-addressed store path
|
and rewrites it into the content-addressed store path
|
||||||
`/nix/store/ldbh...`.
|
`/nix/store/ldbh...`.
|
||||||
|
|
||||||
If `fromPath` is already content-addressed, or if you are
|
Like the previous example, no extra configuration or privileges are required.
|
||||||
allowing impure evaluation (`--impure`), then `toPath` may be
|
|
||||||
omitted.
|
|
||||||
|
|
||||||
To find out the correct value for `toPath` given a `fromPath`,
|
To find out the correct value for `toPath` given a `fromPath`,
|
||||||
you can use `nix store make-content-addressed`:
|
use [`nix store make-content-addressed`](@docroot@/command-ref/new-cli/nix3-store-make-content-addressed.md):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix store make-content-addressed --from https://cache.nixos.org /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1
|
# nix store make-content-addressed --from https://cache.nixos.org /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1
|
||||||
rewrote '/nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1' to '/nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1'
|
rewrote '/nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1' to '/nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1'
|
||||||
```
|
```
|
||||||
|
|
||||||
This function is similar to `builtins.storePath` in that it
|
Alternatively, set `toPath = ""` and find the correct `toPath` in the error message.
|
||||||
allows you to use a previously built store path in a Nix
|
|
||||||
expression. However, it is more reproducible because it requires
|
|
||||||
specifying a binary cache from which the path can be fetched.
|
|
||||||
Also, requiring a content-addressed final store path avoids the
|
|
||||||
need for users to configure binary cache public keys.
|
|
||||||
|
|
||||||
This function is only available if you enable the experimental
|
**Fetch an input-addressed store path as is**
|
||||||
feature `fetch-closure`.
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.fetchClosure {
|
||||||
|
fromStore = "https://cache.nixos.org";
|
||||||
|
fromPath = /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1;
|
||||||
|
inputAddressed = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is possible to fetch an [input-addressed store path](@docroot@/glossary.md#gloss-input-addressed-store-object) and return it as is.
|
||||||
|
However, this is the least preferred way of invoking `fetchClosure`, because it requires that the input-addressed paths are trusted by the Nix configuration.
|
||||||
|
|
||||||
|
**`builtins.storePath`**
|
||||||
|
|
||||||
|
`fetchClosure` is similar to [`builtins.storePath`](#builtins-storePath) in that it allows you to use a previously built store path in a Nix expression.
|
||||||
|
However, `fetchClosure` is more reproducible because it specifies a binary cache from which the path can be fetched.
|
||||||
|
Also, using content-addressed store paths does not require users to configure [`trusted-public-keys`](@docroot@/command-ref/conf-file.md#conf-trusted-public-keys) to ensure their authenticity.
|
||||||
)",
|
)",
|
||||||
.fun = prim_fetchClosure,
|
.fun = prim_fetchClosure,
|
||||||
.experimentalFeature = Xp::FetchClosure,
|
.experimentalFeature = Xp::FetchClosure,
|
||||||
|
|
|
@ -88,6 +88,10 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a
|
||||||
state.allowPath(tree.storePath);
|
state.allowPath(tree.storePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r_fetchMercurial("fetchMercurial", 1, prim_fetchMercurial);
|
static RegisterPrimOp r_fetchMercurial({
|
||||||
|
.name = "fetchMercurial",
|
||||||
|
.arity = 1,
|
||||||
|
.fun = prim_fetchMercurial
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ void emitTreeAttrs(
|
||||||
{
|
{
|
||||||
assert(input.isLocked());
|
assert(input.isLocked());
|
||||||
|
|
||||||
auto attrs = state.buildBindings(8);
|
auto attrs = state.buildBindings(10);
|
||||||
|
|
||||||
|
|
||||||
state.mkStorePathString(tree.storePath, attrs.alloc(state.sOutPath));
|
state.mkStorePathString(tree.storePath, attrs.alloc(state.sOutPath));
|
||||||
|
@ -56,6 +56,11 @@ void emitTreeAttrs(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto dirtyRev = fetchers::maybeGetStrAttr(input.attrs, "dirtyRev")) {
|
||||||
|
attrs.alloc("dirtyRev").mkString(*dirtyRev);
|
||||||
|
attrs.alloc("dirtyShortRev").mkString(*fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev"));
|
||||||
|
}
|
||||||
|
|
||||||
if (auto lastModified = input.getLastModified()) {
|
if (auto lastModified = input.getLastModified()) {
|
||||||
attrs.alloc("lastModified").mkInt(*lastModified);
|
attrs.alloc("lastModified").mkInt(*lastModified);
|
||||||
attrs.alloc("lastModifiedDate").mkString(
|
attrs.alloc("lastModifiedDate").mkString(
|
||||||
|
@ -194,7 +199,11 @@ static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: document
|
// FIXME: document
|
||||||
static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree);
|
static RegisterPrimOp primop_fetchTree({
|
||||||
|
.name = "fetchTree",
|
||||||
|
.arity = 1,
|
||||||
|
.fun = prim_fetchTree
|
||||||
|
});
|
||||||
|
|
||||||
static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v,
|
static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v,
|
||||||
const std::string & who, bool unpack, std::string name)
|
const std::string & who, bool unpack, std::string name)
|
||||||
|
@ -262,7 +271,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
||||||
// https://github.com/NixOS/nix/issues/4313
|
// https://github.com/NixOS/nix/issues/4313
|
||||||
auto storePath =
|
auto storePath =
|
||||||
unpack
|
unpack
|
||||||
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath
|
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).tree.storePath
|
||||||
: fetchers::downloadFile(state.store, *url, name, (bool) expectedHash).storePath;
|
: fetchers::downloadFile(state.store, *url, name, (bool) expectedHash).storePath;
|
||||||
|
|
||||||
if (expectedHash) {
|
if (expectedHash) {
|
||||||
|
@ -286,9 +295,9 @@ static RegisterPrimOp primop_fetchurl({
|
||||||
.name = "__fetchurl",
|
.name = "__fetchurl",
|
||||||
.args = {"url"},
|
.args = {"url"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Download the specified URL and return the path of the downloaded
|
Download the specified URL and return the path of the downloaded file.
|
||||||
file. This function is not available if [restricted evaluation
|
|
||||||
mode](../command-ref/conf-file.md) is enabled.
|
Not available in [restricted evaluation mode](@docroot@/command-ref/conf-file.md#conf-restrict-eval).
|
||||||
)",
|
)",
|
||||||
.fun = prim_fetchurl,
|
.fun = prim_fetchurl,
|
||||||
});
|
});
|
||||||
|
@ -338,8 +347,7 @@ static RegisterPrimOp primop_fetchTarball({
|
||||||
stdenv.mkDerivation { … }
|
stdenv.mkDerivation { … }
|
||||||
```
|
```
|
||||||
|
|
||||||
This function is not available if [restricted evaluation
|
Not available in [restricted evaluation mode](@docroot@/command-ref/conf-file.md#conf-restrict-eval).
|
||||||
mode](../command-ref/conf-file.md) is enabled.
|
|
||||||
)",
|
)",
|
||||||
.fun = prim_fetchTarball,
|
.fun = prim_fetchTarball,
|
||||||
});
|
});
|
||||||
|
@ -470,14 +478,9 @@ static RegisterPrimOp primop_fetchGit({
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
Nix will refetch the branch according to the [`tarball-ttl`](@docroot@/command-ref/conf-file.md#conf-tarball-ttl) setting.
|
||||||
>
|
|
||||||
> Nix will refetch the branch in accordance with
|
|
||||||
> the option `tarball-ttl`.
|
|
||||||
|
|
||||||
> **Note**
|
This behavior is disabled in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
>
|
|
||||||
> This behavior is disabled in *Pure evaluation mode*.
|
|
||||||
|
|
||||||
- To fetch the content of a checked-out work directory:
|
- To fetch the content of a checked-out work directory:
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../../toml11/toml.hpp"
|
#include "../../toml11/toml.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, Value & val)
|
static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, Value & val)
|
||||||
|
@ -58,8 +60,18 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
case toml::value_t::offset_datetime:
|
case toml::value_t::offset_datetime:
|
||||||
case toml::value_t::local_date:
|
case toml::value_t::local_date:
|
||||||
case toml::value_t::local_time:
|
case toml::value_t::local_time:
|
||||||
// We fail since Nix doesn't have date and time types
|
{
|
||||||
throw std::runtime_error("Dates and times are not supported");
|
if (experimentalFeatureSettings.isEnabled(Xp::ParseTomlTimestamps)) {
|
||||||
|
auto attrs = state.buildBindings(2);
|
||||||
|
attrs.alloc("_type").mkString("timestamp");
|
||||||
|
std::ostringstream s;
|
||||||
|
s << t;
|
||||||
|
attrs.alloc("value").mkString(s.str());
|
||||||
|
v.mkAttrs(attrs);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Dates and times are not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
break;;
|
break;;
|
||||||
case toml::value_t::empty:
|
case toml::value_t::empty:
|
||||||
v.mkNull();
|
v.mkNull();
|
||||||
|
@ -78,6 +90,24 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);
|
static RegisterPrimOp primop_fromTOML({
|
||||||
|
.name = "fromTOML",
|
||||||
|
.args = {"e"},
|
||||||
|
.doc = R"(
|
||||||
|
Convert a TOML string to a Nix value. For example,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.fromTOML ''
|
||||||
|
x=1
|
||||||
|
s="a"
|
||||||
|
[table]
|
||||||
|
y=2
|
||||||
|
''
|
||||||
|
```
|
||||||
|
|
||||||
|
returns the value `{ s = "a"; table = { y = 2; }; x = 1; }`.
|
||||||
|
)",
|
||||||
|
.fun = prim_fromTOML
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
56
src/libexpr/search-path.cc
Normal file
56
src/libexpr/search-path.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "search-path.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::optional<std::string_view> SearchPath::Prefix::suffixIfPotentialMatch(
|
||||||
|
std::string_view path) const
|
||||||
|
{
|
||||||
|
auto n = s.size();
|
||||||
|
|
||||||
|
/* Non-empty prefix and suffix must be separated by a /, or the
|
||||||
|
prefix is not a valid path prefix. */
|
||||||
|
bool needSeparator = n > 0 && (path.size() - n) > 0;
|
||||||
|
|
||||||
|
if (needSeparator && path[n] != '/') {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prefix must be prefix of this path. */
|
||||||
|
if (path.compare(0, n, s) != 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip next path separator. */
|
||||||
|
return {
|
||||||
|
path.substr(needSeparator ? n + 1 : n)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SearchPath::Elem SearchPath::Elem::parse(std::string_view rawElem)
|
||||||
|
{
|
||||||
|
size_t pos = rawElem.find('=');
|
||||||
|
|
||||||
|
return SearchPath::Elem {
|
||||||
|
.prefix = Prefix {
|
||||||
|
.s = pos == std::string::npos
|
||||||
|
? std::string { "" }
|
||||||
|
: std::string { rawElem.substr(0, pos) },
|
||||||
|
},
|
||||||
|
.path = Path {
|
||||||
|
.s = std::string { rawElem.substr(pos + 1) },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SearchPath parseSearchPath(const Strings & rawElems)
|
||||||
|
{
|
||||||
|
SearchPath res;
|
||||||
|
for (auto & rawElem : rawElems)
|
||||||
|
res.elements.emplace_back(SearchPath::Elem::parse(rawElem));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue