diff --git a/.github/assign-by-files.yml b/.github/assign-by-files.yml new file mode 100644 index 000000000..f13b71776 --- /dev/null +++ b/.github/assign-by-files.yml @@ -0,0 +1,5 @@ +--- +# This files is used by https://github.com/marketplace/actions/auto-assign-reviewer-by-files +# to assign maintainers +"doc/**/*": + - fricklerhandwerk diff --git a/.github/workflows/assign-reviewer.yml b/.github/workflows/assign-reviewer.yml new file mode 100644 index 000000000..4371cbff4 --- /dev/null +++ b/.github/workflows/assign-reviewer.yml @@ -0,0 +1,12 @@ +name: "Auto Assign" +on: + - pull_request + +jobs: + assign_reviewer: + runs-on: ubuntu-latest + steps: + - uses: shufo/auto-assign-reviewer-by-files@v1.1.4 + with: + config: ".github/assign-by-files.yml" + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 628d1d192..dafba6d85 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,9 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: cachix/install-nix-action@v17 + - uses: cachix/install-nix-action@v18 - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - - uses: cachix/cachix-action@v10 + - uses: cachix/cachix-action@v12 if: needs.check_secrets.outputs.cachix == 'true' with: name: '${{ env.CACHIX_NAME }}' @@ -58,8 +58,8 @@ jobs: with: fetch-depth: 0 - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - - uses: cachix/install-nix-action@v17 - - uses: cachix/cachix-action@v10 + - uses: cachix/install-nix-action@v18 + - uses: cachix/cachix-action@v12 with: name: '${{ env.CACHIX_NAME }}' signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' @@ -77,7 +77,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - - uses: cachix/install-nix-action@v17 + - uses: cachix/install-nix-action@v18 with: install_url: '${{needs.installer.outputs.installerURL}}' install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve" @@ -102,10 +102,10 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: cachix/install-nix-action@v17 + - uses: cachix/install-nix-action@v18 - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV - - uses: cachix/cachix-action@v10 + - uses: cachix/cachix-action@v12 if: needs.check_secrets.outputs.cachix == 'true' with: name: '${{ env.CACHIX_NAME }}' diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix index 18a1a8bfe..057719e34 100644 --- a/doc/manual/generate-manpage.nix +++ b/doc/manual/generate-manpage.nix @@ -1,11 +1,11 @@ -{ command }: +{ toplevel }: with builtins; with import ./utils.nix; let - showCommand = { command, details, filename }: + showCommand = { command, details, filename, toplevel }: let result = '' > **Warning** \ @@ -57,14 +57,15 @@ let maybeOptions = if details.flags == {} then "" else '' # Options - ${showOptions details.flags} + ${showOptions details.flags toplevel.flags} ''; - showOptions = options: + showOptions = options: commonOptions: let + allOptions = options // commonOptions; showCategory = cat: '' ${if cat != "" then "**${cat}:**" else ""} - ${listOptions (filterAttrs (n: v: v.category == cat) options)} + ${listOptions (filterAttrs (n: v: v.category == cat) allOptions)} ''; listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts)); showOption = name: option: @@ -76,30 +77,33 @@ let ${option.description} ''; - categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues options))); + categories = sort builtins.lessThan (unique (map (cmd: cmd.category) (attrValues allOptions))); in concatStrings (map showCategory categories); in squash result; appendName = filename: name: (if filename == "nix" then "nix3" else filename) + "-" + name; - processCommand = { command, details, filename }: + processCommand = { command, details, filename, toplevel }: let cmd = { inherit command; name = filename + ".md"; - value = showCommand { inherit command details filename; }; + value = showCommand { inherit command details filename toplevel; }; }; subcommand = subCmd: processCommand { command = command + " " + subCmd; details = details.commands.${subCmd}; filename = appendName filename subCmd; + inherit toplevel; }; in [ cmd ] ++ concatMap subcommand (attrNames details.commands or {}); + parsedToplevel = builtins.fromJSON toplevel; manpages = processCommand { command = "nix"; - details = builtins.fromJSON command; + details = parsedToplevel; filename = "nix"; + toplevel = parsedToplevel; }; tableOfContents = let diff --git a/doc/manual/generate-options.nix b/doc/manual/generate-options.nix index 2d586fa1b..680b709c8 100644 --- a/doc/manual/generate-options.nix +++ b/doc/manual/generate-options.nix @@ -11,16 +11,16 @@ concatStrings (map + concatStrings (map (s: " ${s}\n") (splitLines option.description)) + "\n\n" + (if option.documentDefault then " **Default:** " + ( - if option.value == "" || option.value == [] + if option.defaultValue == "" || option.defaultValue == [] then "*empty*" - else if isBool option.value - then (if option.value then "`true`" else "`false`") + else if isBool option.defaultValue + then (if option.defaultValue then "`true`" else "`false`") else # n.b. a StringMap value type is specified as a string, but # this shows the value type. The empty stringmap is "null" in # JSON, but that converts to "{ }" here. - (if isAttrs option.value then "`\"\"`" - else "`" + toString option.value + "`")) + "\n\n" + (if isAttrs option.defaultValue then "`\"\"`" + else "`" + toString option.defaultValue + "`")) + "\n\n" else " **Default:** *machine-specific*\n") + (if option.aliases != [] then " **Deprecated alias:** " + (concatStringsSep ", " (map (s: "`${s}`") option.aliases)) + "\n\n" diff --git a/doc/manual/local.mk b/doc/manual/local.mk index 364e02967..486dbd7a2 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -50,7 +50,7 @@ $(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix @rm -rf $@ - $(trace-gen) $(nix-eval) --write-to $@ --expr 'import doc/manual/generate-manpage.nix { command = builtins.readFile $<; }' + $(trace-gen) $(nix-eval) --write-to $@ --expr 'import doc/manual/generate-manpage.nix { toplevel = builtins.readFile $<; }' $(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix @cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js index 167e221b8..2e77edd0f 100644 --- a/doc/manual/redirects.js +++ b/doc/manual/redirects.js @@ -1,330 +1,424 @@ -// Redirects from old DocBook manual. -var redirects = { - "#part-advanced-topics": "advanced-topics/advanced-topics.html", - "#chap-tuning-cores-and-jobs": "advanced-topics/cores-vs-jobs.html", - "#chap-diff-hook": "advanced-topics/diff-hook.html", - "#check-dirs-are-unregistered": "advanced-topics/diff-hook.html#check-dirs-are-unregistered", - "#chap-distributed-builds": "advanced-topics/distributed-builds.html", - "#chap-post-build-hook": "advanced-topics/post-build-hook.html", - "#chap-post-build-hook-caveats": "advanced-topics/post-build-hook.html#implementation-caveats", - "#part-command-ref": "command-ref/command-ref.html", - "#conf-allow-import-from-derivation": "command-ref/conf-file.html#conf-allow-import-from-derivation", - "#conf-allow-new-privileges": "command-ref/conf-file.html#conf-allow-new-privileges", - "#conf-allowed-uris": "command-ref/conf-file.html#conf-allowed-uris", - "#conf-allowed-users": "command-ref/conf-file.html#conf-allowed-users", - "#conf-auto-optimise-store": "command-ref/conf-file.html#conf-auto-optimise-store", - "#conf-binary-cache-public-keys": "command-ref/conf-file.html#conf-binary-cache-public-keys", - "#conf-binary-caches": "command-ref/conf-file.html#conf-binary-caches", - "#conf-build-compress-log": "command-ref/conf-file.html#conf-build-compress-log", - "#conf-build-cores": "command-ref/conf-file.html#conf-build-cores", - "#conf-build-extra-chroot-dirs": "command-ref/conf-file.html#conf-build-extra-chroot-dirs", - "#conf-build-extra-sandbox-paths": "command-ref/conf-file.html#conf-build-extra-sandbox-paths", - "#conf-build-fallback": "command-ref/conf-file.html#conf-build-fallback", - "#conf-build-max-jobs": "command-ref/conf-file.html#conf-build-max-jobs", - "#conf-build-max-log-size": "command-ref/conf-file.html#conf-build-max-log-size", - "#conf-build-max-silent-time": "command-ref/conf-file.html#conf-build-max-silent-time", - "#conf-build-repeat": "command-ref/conf-file.html#conf-build-repeat", - "#conf-build-timeout": "command-ref/conf-file.html#conf-build-timeout", - "#conf-build-use-chroot": "command-ref/conf-file.html#conf-build-use-chroot", - "#conf-build-use-sandbox": "command-ref/conf-file.html#conf-build-use-sandbox", - "#conf-build-use-substitutes": "command-ref/conf-file.html#conf-build-use-substitutes", - "#conf-build-users-group": "command-ref/conf-file.html#conf-build-users-group", - "#conf-builders": "command-ref/conf-file.html#conf-builders", - "#conf-builders-use-substitutes": "command-ref/conf-file.html#conf-builders-use-substitutes", - "#conf-compress-build-log": "command-ref/conf-file.html#conf-compress-build-log", - "#conf-connect-timeout": "command-ref/conf-file.html#conf-connect-timeout", - "#conf-cores": "command-ref/conf-file.html#conf-cores", - "#conf-diff-hook": "command-ref/conf-file.html#conf-diff-hook", - "#conf-enforce-determinism": "command-ref/conf-file.html#conf-enforce-determinism", - "#conf-env-keep-derivations": "command-ref/conf-file.html#conf-env-keep-derivations", - "#conf-extra-binary-caches": "command-ref/conf-file.html#conf-extra-binary-caches", - "#conf-extra-platforms": "command-ref/conf-file.html#conf-extra-platforms", - "#conf-extra-sandbox-paths": "command-ref/conf-file.html#conf-extra-sandbox-paths", - "#conf-extra-substituters": "command-ref/conf-file.html#conf-extra-substituters", - "#conf-fallback": "command-ref/conf-file.html#conf-fallback", - "#conf-fsync-metadata": "command-ref/conf-file.html#conf-fsync-metadata", - "#conf-gc-keep-derivations": "command-ref/conf-file.html#conf-gc-keep-derivations", - "#conf-gc-keep-outputs": "command-ref/conf-file.html#conf-gc-keep-outputs", - "#conf-hashed-mirrors": "command-ref/conf-file.html#conf-hashed-mirrors", - "#conf-http-connections": "command-ref/conf-file.html#conf-http-connections", - "#conf-keep-build-log": "command-ref/conf-file.html#conf-keep-build-log", - "#conf-keep-derivations": "command-ref/conf-file.html#conf-keep-derivations", - "#conf-keep-env-derivations": "command-ref/conf-file.html#conf-keep-env-derivations", - "#conf-keep-outputs": "command-ref/conf-file.html#conf-keep-outputs", - "#conf-max-build-log-size": "command-ref/conf-file.html#conf-max-build-log-size", - "#conf-max-free": "command-ref/conf-file.html#conf-max-free", - "#conf-max-jobs": "command-ref/conf-file.html#conf-max-jobs", - "#conf-max-silent-time": "command-ref/conf-file.html#conf-max-silent-time", - "#conf-min-free": "command-ref/conf-file.html#conf-min-free", - "#conf-narinfo-cache-negative-ttl": "command-ref/conf-file.html#conf-narinfo-cache-negative-ttl", - "#conf-narinfo-cache-positive-ttl": "command-ref/conf-file.html#conf-narinfo-cache-positive-ttl", - "#conf-netrc-file": "command-ref/conf-file.html#conf-netrc-file", - "#conf-plugin-files": "command-ref/conf-file.html#conf-plugin-files", - "#conf-post-build-hook": "command-ref/conf-file.html#conf-post-build-hook", - "#conf-pre-build-hook": "command-ref/conf-file.html#conf-pre-build-hook", - "#conf-repeat": "command-ref/conf-file.html#conf-repeat", - "#conf-require-sigs": "command-ref/conf-file.html#conf-require-sigs", - "#conf-restrict-eval": "command-ref/conf-file.html#conf-restrict-eval", - "#conf-run-diff-hook": "command-ref/conf-file.html#conf-run-diff-hook", - "#conf-sandbox": "command-ref/conf-file.html#conf-sandbox", - "#conf-sandbox-dev-shm-size": "command-ref/conf-file.html#conf-sandbox-dev-shm-size", - "#conf-sandbox-paths": "command-ref/conf-file.html#conf-sandbox-paths", - "#conf-secret-key-files": "command-ref/conf-file.html#conf-secret-key-files", - "#conf-show-trace": "command-ref/conf-file.html#conf-show-trace", - "#conf-stalled-download-timeout": "command-ref/conf-file.html#conf-stalled-download-timeout", - "#conf-substitute": "command-ref/conf-file.html#conf-substitute", - "#conf-substituters": "command-ref/conf-file.html#conf-substituters", - "#conf-system": "command-ref/conf-file.html#conf-system", - "#conf-system-features": "command-ref/conf-file.html#conf-system-features", - "#conf-tarball-ttl": "command-ref/conf-file.html#conf-tarball-ttl", - "#conf-timeout": "command-ref/conf-file.html#conf-timeout", - "#conf-trace-function-calls": "command-ref/conf-file.html#conf-trace-function-calls", - "#conf-trusted-binary-caches": "command-ref/conf-file.html#conf-trusted-binary-caches", - "#conf-trusted-public-keys": "command-ref/conf-file.html#conf-trusted-public-keys", - "#conf-trusted-substituters": "command-ref/conf-file.html#conf-trusted-substituters", - "#conf-trusted-users": "command-ref/conf-file.html#conf-trusted-users", - "#extra-sandbox-paths": "command-ref/conf-file.html#extra-sandbox-paths", - "#sec-conf-file": "command-ref/conf-file.html", - "#env-NIX_PATH": "command-ref/env-common.html#env-NIX_PATH", - "#env-common": "command-ref/env-common.html", - "#envar-remote": "command-ref/env-common.html#env-NIX_REMOTE", - "#sec-common-env": "command-ref/env-common.html", - "#ch-files": "command-ref/files.html", - "#ch-main-commands": "command-ref/main-commands.html", - "#opt-out-link": "command-ref/nix-build.html#opt-out-link", - "#sec-nix-build": "command-ref/nix-build.html", - "#sec-nix-channel": "command-ref/nix-channel.html", - "#sec-nix-collect-garbage": "command-ref/nix-collect-garbage.html", - "#sec-nix-copy-closure": "command-ref/nix-copy-closure.html", - "#sec-nix-daemon": "command-ref/nix-daemon.html", - "#refsec-nix-env-install-examples": "command-ref/nix-env.html#examples", - "#rsec-nix-env-install": "command-ref/nix-env.html#operation---install", - "#rsec-nix-env-set": "command-ref/nix-env.html#operation---set", - "#rsec-nix-env-set-flag": "command-ref/nix-env.html#operation---set-flag", - "#rsec-nix-env-upgrade": "command-ref/nix-env.html#operation---upgrade", - "#sec-nix-env": "command-ref/nix-env.html", - "#ssec-version-comparisons": "command-ref/nix-env.html#versions", - "#sec-nix-hash": "command-ref/nix-hash.html", - "#sec-nix-instantiate": "command-ref/nix-instantiate.html", - "#sec-nix-prefetch-url": "command-ref/nix-prefetch-url.html", - "#sec-nix-shell": "command-ref/nix-shell.html", - "#ssec-nix-shell-shebang": "command-ref/nix-shell.html#use-as-a--interpreter", - "#nixref-queries": "command-ref/nix-store.html#queries", - "#opt-add-root": "command-ref/nix-store.html#opt-add-root", - "#refsec-nix-store-dump": "command-ref/nix-store.html#operation---dump", - "#refsec-nix-store-export": "command-ref/nix-store.html#operation---export", - "#refsec-nix-store-import": "command-ref/nix-store.html#operation---import", - "#refsec-nix-store-query": "command-ref/nix-store.html#operation---query", - "#refsec-nix-store-verify": "command-ref/nix-store.html#operation---verify", - "#rsec-nix-store-gc": "command-ref/nix-store.html#operation---gc", - "#rsec-nix-store-generate-binary-cache-key": "command-ref/nix-store.html#operation---generate-binary-cache-key", - "#rsec-nix-store-realise": "command-ref/nix-store.html#operation---realise", - "#rsec-nix-store-serve": "command-ref/nix-store.html#operation---serve", - "#sec-nix-store": "command-ref/nix-store.html", - "#opt-I": "command-ref/opt-common.html#opt-I", - "#opt-attr": "command-ref/opt-common.html#opt-attr", - "#opt-common": "command-ref/opt-common.html", - "#opt-cores": "command-ref/opt-common.html#opt-cores", - "#opt-log-format": "command-ref/opt-common.html#opt-log-format", - "#opt-max-jobs": "command-ref/opt-common.html#opt-max-jobs", - "#opt-max-silent-time": "command-ref/opt-common.html#opt-max-silent-time", - "#opt-timeout": "command-ref/opt-common.html#opt-timeout", - "#sec-common-options": "command-ref/opt-common.html", - "#ch-utilities": "command-ref/utilities.html", - "#chap-hacking": "contributing/hacking.html", - "#adv-attr-allowSubstitutes": "language/advanced-attributes.html#adv-attr-allowSubstitutes", - "#adv-attr-allowedReferences": "language/advanced-attributes.html#adv-attr-allowedReferences", - "#adv-attr-allowedRequisites": "language/advanced-attributes.html#adv-attr-allowedRequisites", - "#adv-attr-disallowedReferences": "language/advanced-attributes.html#adv-attr-disallowedReferences", - "#adv-attr-disallowedRequisites": "language/advanced-attributes.html#adv-attr-disallowedRequisites", - "#adv-attr-exportReferencesGraph": "language/advanced-attributes.html#adv-attr-exportReferencesGraph", - "#adv-attr-impureEnvVars": "language/advanced-attributes.html#adv-attr-impureEnvVars", - "#adv-attr-outputHash": "language/advanced-attributes.html#adv-attr-outputHash", - "#adv-attr-outputHashAlgo": "language/advanced-attributes.html#adv-attr-outputHashAlgo", - "#adv-attr-outputHashMode": "language/advanced-attributes.html#adv-attr-outputHashMode", - "#adv-attr-passAsFile": "language/advanced-attributes.html#adv-attr-passAsFile", - "#adv-attr-preferLocalBuild": "language/advanced-attributes.html#adv-attr-preferLocalBuild", - "#fixed-output-drvs": "language/advanced-attributes.html#adv-attr-outputHash", - "#sec-advanced-attributes": "language/advanced-attributes.html", - "#builtin-abort": "language/builtins.html#builtins-abort", - "#builtin-add": "language/builtins.html#builtins-add", - "#builtin-all": "language/builtins.html#builtins-all", - "#builtin-any": "language/builtins.html#builtins-any", - "#builtin-attrNames": "language/builtins.html#builtins-attrNames", - "#builtin-attrValues": "language/builtins.html#builtins-attrValues", - "#builtin-baseNameOf": "language/builtins.html#builtins-baseNameOf", - "#builtin-bitAnd": "language/builtins.html#builtins-bitAnd", - "#builtin-bitOr": "language/builtins.html#builtins-bitOr", - "#builtin-bitXor": "language/builtins.html#builtins-bitXor", - "#builtin-builtins": "language/builtins.html#builtins-builtins", - "#builtin-compareVersions": "language/builtins.html#builtins-compareVersions", - "#builtin-concatLists": "language/builtins.html#builtins-concatLists", - "#builtin-concatStringsSep": "language/builtins.html#builtins-concatStringsSep", - "#builtin-currentSystem": "language/builtins.html#builtins-currentSystem", - "#builtin-deepSeq": "language/builtins.html#builtins-deepSeq", - "#builtin-derivation": "language/builtins.html#builtins-derivation", - "#builtin-dirOf": "language/builtins.html#builtins-dirOf", - "#builtin-div": "language/builtins.html#builtins-div", - "#builtin-elem": "language/builtins.html#builtins-elem", - "#builtin-elemAt": "language/builtins.html#builtins-elemAt", - "#builtin-fetchGit": "language/builtins.html#builtins-fetchGit", - "#builtin-fetchTarball": "language/builtins.html#builtins-fetchTarball", - "#builtin-fetchurl": "language/builtins.html#builtins-fetchurl", - "#builtin-filterSource": "language/builtins.html#builtins-filterSource", - "#builtin-foldl-prime": "language/builtins.html#builtins-foldl-prime", - "#builtin-fromJSON": "language/builtins.html#builtins-fromJSON", - "#builtin-functionArgs": "language/builtins.html#builtins-functionArgs", - "#builtin-genList": "language/builtins.html#builtins-genList", - "#builtin-getAttr": "language/builtins.html#builtins-getAttr", - "#builtin-getEnv": "language/builtins.html#builtins-getEnv", - "#builtin-hasAttr": "language/builtins.html#builtins-hasAttr", - "#builtin-hashFile": "language/builtins.html#builtins-hashFile", - "#builtin-hashString": "language/builtins.html#builtins-hashString", - "#builtin-head": "language/builtins.html#builtins-head", - "#builtin-import": "language/builtins.html#builtins-import", - "#builtin-intersectAttrs": "language/builtins.html#builtins-intersectAttrs", - "#builtin-isAttrs": "language/builtins.html#builtins-isAttrs", - "#builtin-isBool": "language/builtins.html#builtins-isBool", - "#builtin-isFloat": "language/builtins.html#builtins-isFloat", - "#builtin-isFunction": "language/builtins.html#builtins-isFunction", - "#builtin-isInt": "language/builtins.html#builtins-isInt", - "#builtin-isList": "language/builtins.html#builtins-isList", - "#builtin-isNull": "language/builtins.html#builtins-isNull", - "#builtin-isString": "language/builtins.html#builtins-isString", - "#builtin-length": "language/builtins.html#builtins-length", - "#builtin-lessThan": "language/builtins.html#builtins-lessThan", - "#builtin-listToAttrs": "language/builtins.html#builtins-listToAttrs", - "#builtin-map": "language/builtins.html#builtins-map", - "#builtin-match": "language/builtins.html#builtins-match", - "#builtin-mul": "language/builtins.html#builtins-mul", - "#builtin-parseDrvName": "language/builtins.html#builtins-parseDrvName", - "#builtin-path": "language/builtins.html#builtins-path", - "#builtin-pathExists": "language/builtins.html#builtins-pathExists", - "#builtin-placeholder": "language/builtins.html#builtins-placeholder", - "#builtin-readDir": "language/builtins.html#builtins-readDir", - "#builtin-readFile": "language/builtins.html#builtins-readFile", - "#builtin-removeAttrs": "language/builtins.html#builtins-removeAttrs", - "#builtin-replaceStrings": "language/builtins.html#builtins-replaceStrings", - "#builtin-seq": "language/builtins.html#builtins-seq", - "#builtin-sort": "language/builtins.html#builtins-sort", - "#builtin-split": "language/builtins.html#builtins-split", - "#builtin-splitVersion": "language/builtins.html#builtins-splitVersion", - "#builtin-stringLength": "language/builtins.html#builtins-stringLength", - "#builtin-sub": "language/builtins.html#builtins-sub", - "#builtin-substring": "language/builtins.html#builtins-substring", - "#builtin-tail": "language/builtins.html#builtins-tail", - "#builtin-throw": "language/builtins.html#builtins-throw", - "#builtin-toFile": "language/builtins.html#builtins-toFile", - "#builtin-toJSON": "language/builtins.html#builtins-toJSON", - "#builtin-toPath": "language/builtins.html#builtins-toPath", - "#builtin-toString": "language/builtins.html#builtins-toString", - "#builtin-toXML": "language/builtins.html#builtins-toXML", - "#builtin-trace": "language/builtins.html#builtins-trace", - "#builtin-tryEval": "language/builtins.html#builtins-tryEval", - "#builtin-typeOf": "language/builtins.html#builtins-typeOf", - "#ssec-builtins": "language/builtins.html", - "#attr-system": "language/derivations.html#attr-system", - "#ssec-derivation": "language/derivations.html", - "#ch-expression-language": "language/index.html", - "#sec-constructs": "language/constructs.html", - "#sect-let-language": "language/constructs.html#let-language", - "#ss-functions": "language/constructs.html#functions", - "#sec-language-operators": "language/operators.html", - "#table-operators": "language/operators.html", - "#ssec-values": "language/values.html", - "#gloss-closure": "glossary.html#gloss-closure", - "#gloss-derivation": "glossary.html#gloss-derivation", - "#gloss-deriver": "glossary.html#gloss-deriver", - "#gloss-nar": "glossary.html#gloss-nar", - "#gloss-output-path": "glossary.html#gloss-output-path", - "#gloss-profile": "glossary.html#gloss-profile", - "#gloss-reachable": "glossary.html#gloss-reachable", - "#gloss-reference": "glossary.html#gloss-reference", - "#gloss-substitute": "glossary.html#gloss-substitute", - "#gloss-user-env": "glossary.html#gloss-user-env", - "#gloss-validity": "glossary.html#gloss-validity", - "#part-glossary": "glossary.html", - "#sec-building-source": "installation/building-source.html", - "#ch-env-variables": "installation/env-variables.html", - "#sec-installer-proxy-settings": "installation/env-variables.html#proxy-environment-variables", - "#sec-nix-ssl-cert-file": "installation/env-variables.html#nix_ssl_cert_file", - "#sec-nix-ssl-cert-file-with-nix-daemon-and-macos": "installation/env-variables.html#nix_ssl_cert_file-with-macos-and-the-nix-daemon", - "#chap-installation": "installation/installation.html", - "#ch-installing-binary": "installation/installing-binary.html", - "#sect-macos-installation": "installation/installing-binary.html#macos-installation", - "#sect-macos-installation-change-store-prefix": "installation/installing-binary.html#macos-installation", - "#sect-macos-installation-encrypted-volume": "installation/installing-binary.html#macos-installation", - "#sect-macos-installation-recommended-notes": "installation/installing-binary.html#macos-installation", - "#sect-macos-installation-symlink": "installation/installing-binary.html#macos-installation", - "#sect-multi-user-installation": "installation/installing-binary.html#multi-user-installation", - "#sect-nix-install-binary-tarball": "installation/installing-binary.html#installing-from-a-binary-tarball", - "#sect-nix-install-pinned-version-url": "installation/installing-binary.html#installing-a-pinned-nix-version-from-a-url", - "#sect-single-user-installation": "installation/installing-binary.html#single-user-installation", - "#ch-installing-source": "installation/installing-source.html", - "#ssec-multi-user": "installation/multi-user.html", - "#ch-nix-security": "installation/nix-security.html", - "#sec-obtaining-source": "installation/obtaining-source.html", - "#sec-prerequisites-source": "installation/prerequisites-source.html", - "#sec-single-user": "installation/single-user.html", - "#ch-supported-platforms": "installation/supported-platforms.html", - "#ch-upgrading-nix": "installation/upgrading.html", - "#ch-about-nix": "introduction.html", - "#chap-introduction": "introduction.html", - "#ch-basic-package-mgmt": "package-management/basic-package-mgmt.html", - "#ssec-binary-cache-substituter": "package-management/binary-cache-substituter.html", - "#sec-channels": "package-management/channels.html", - "#ssec-copy-closure": "package-management/copy-closure.html", - "#sec-garbage-collection": "package-management/garbage-collection.html", - "#ssec-gc-roots": "package-management/garbage-collector-roots.html", - "#chap-package-management": "package-management/package-management.html", - "#sec-profiles": "package-management/profiles.html", - "#ssec-s3-substituter": "package-management/s3-substituter.html", - "#ssec-s3-substituter-anonymous-reads": "package-management/s3-substituter.html#anonymous-reads-to-your-s3-compatible-binary-cache", - "#ssec-s3-substituter-authenticated-reads": "package-management/s3-substituter.html#authenticated-reads-to-your-s3-binary-cache", - "#ssec-s3-substituter-authenticated-writes": "package-management/s3-substituter.html#authenticated-writes-to-your-s3-compatible-binary-cache", - "#sec-sharing-packages": "package-management/sharing-packages.html", - "#ssec-ssh-substituter": "package-management/ssh-substituter.html", - "#chap-quick-start": "quick-start.html", - "#sec-relnotes": "release-notes/release-notes.html", - "#ch-relnotes-0.10.1": "release-notes/rl-0.10.1.html", - "#ch-relnotes-0.10": "release-notes/rl-0.10.html", - "#ssec-relnotes-0.11": "release-notes/rl-0.11.html", - "#ssec-relnotes-0.12": "release-notes/rl-0.12.html", - "#ssec-relnotes-0.13": "release-notes/rl-0.13.html", - "#ssec-relnotes-0.14": "release-notes/rl-0.14.html", - "#ssec-relnotes-0.15": "release-notes/rl-0.15.html", - "#ssec-relnotes-0.16": "release-notes/rl-0.16.html", - "#ch-relnotes-0.5": "release-notes/rl-0.5.html", - "#ch-relnotes-0.6": "release-notes/rl-0.6.html", - "#ch-relnotes-0.7": "release-notes/rl-0.7.html", - "#ch-relnotes-0.8.1": "release-notes/rl-0.8.1.html", - "#ch-relnotes-0.8": "release-notes/rl-0.8.html", - "#ch-relnotes-0.9.1": "release-notes/rl-0.9.1.html", - "#ch-relnotes-0.9.2": "release-notes/rl-0.9.2.html", - "#ch-relnotes-0.9": "release-notes/rl-0.9.html", - "#ssec-relnotes-1.0": "release-notes/rl-1.0.html", - "#ssec-relnotes-1.1": "release-notes/rl-1.1.html", - "#ssec-relnotes-1.10": "release-notes/rl-1.10.html", - "#ssec-relnotes-1.11.10": "release-notes/rl-1.11.10.html", - "#ssec-relnotes-1.11": "release-notes/rl-1.11.html", - "#ssec-relnotes-1.2": "release-notes/rl-1.2.html", - "#ssec-relnotes-1.3": "release-notes/rl-1.3.html", - "#ssec-relnotes-1.4": "release-notes/rl-1.4.html", - "#ssec-relnotes-1.5.1": "release-notes/rl-1.5.1.html", - "#ssec-relnotes-1.5.2": "release-notes/rl-1.5.2.html", - "#ssec-relnotes-1.5": "release-notes/rl-1.5.html", - "#ssec-relnotes-1.6.1": "release-notes/rl-1.6.1.html", - "#ssec-relnotes-1.6.0": "release-notes/rl-1.6.html", - "#ssec-relnotes-1.7": "release-notes/rl-1.7.html", - "#ssec-relnotes-1.8": "release-notes/rl-1.8.html", - "#ssec-relnotes-1.9": "release-notes/rl-1.9.html", - "#ssec-relnotes-2.0": "release-notes/rl-2.0.html", - "#ssec-relnotes-2.1": "release-notes/rl-2.1.html", - "#ssec-relnotes-2.2": "release-notes/rl-2.2.html", - "#ssec-relnotes-2.3": "release-notes/rl-2.3.html" +// redirect rules for anchors ensure backwards compatibility of URLs. +// this must be done on the client side, as web servers do not see the anchor part of the URL. + +// redirections are declared as follows: +// each entry has as its key a path matching the requested URL path, relative to the mdBook document root. +// +// IMPORTANT: it must specify the full path with file name and suffix +// +// each entry is itself a set of key-value pairs, where +// - keys are anchors on the matched path. +// - values are redirection targets relative to the current path. + +const redirects = { + "index.html": { + "part-advanced-topics": "advanced-topics/advanced-topics.html", + "chap-tuning-cores-and-jobs": "advanced-topics/cores-vs-jobs.html", + "chap-diff-hook": "advanced-topics/diff-hook.html", + "check-dirs-are-unregistered": "advanced-topics/diff-hook.html#check-dirs-are-unregistered", + "chap-distributed-builds": "advanced-topics/distributed-builds.html", + "chap-post-build-hook": "advanced-topics/post-build-hook.html", + "chap-post-build-hook-caveats": "advanced-topics/post-build-hook.html#implementation-caveats", + "part-command-ref": "command-ref/command-ref.html", + "conf-allow-import-from-derivation": "command-ref/conf-file.html#conf-allow-import-from-derivation", + "conf-allow-new-privileges": "command-ref/conf-file.html#conf-allow-new-privileges", + "conf-allowed-uris": "command-ref/conf-file.html#conf-allowed-uris", + "conf-allowed-users": "command-ref/conf-file.html#conf-allowed-users", + "conf-auto-optimise-store": "command-ref/conf-file.html#conf-auto-optimise-store", + "conf-binary-cache-public-keys": "command-ref/conf-file.html#conf-binary-cache-public-keys", + "conf-binary-caches": "command-ref/conf-file.html#conf-binary-caches", + "conf-build-compress-log": "command-ref/conf-file.html#conf-build-compress-log", + "conf-build-cores": "command-ref/conf-file.html#conf-build-cores", + "conf-build-extra-chroot-dirs": "command-ref/conf-file.html#conf-build-extra-chroot-dirs", + "conf-build-extra-sandbox-paths": "command-ref/conf-file.html#conf-build-extra-sandbox-paths", + "conf-build-fallback": "command-ref/conf-file.html#conf-build-fallback", + "conf-build-max-jobs": "command-ref/conf-file.html#conf-build-max-jobs", + "conf-build-max-log-size": "command-ref/conf-file.html#conf-build-max-log-size", + "conf-build-max-silent-time": "command-ref/conf-file.html#conf-build-max-silent-time", + "conf-build-repeat": "command-ref/conf-file.html#conf-build-repeat", + "conf-build-timeout": "command-ref/conf-file.html#conf-build-timeout", + "conf-build-use-chroot": "command-ref/conf-file.html#conf-build-use-chroot", + "conf-build-use-sandbox": "command-ref/conf-file.html#conf-build-use-sandbox", + "conf-build-use-substitutes": "command-ref/conf-file.html#conf-build-use-substitutes", + "conf-build-users-group": "command-ref/conf-file.html#conf-build-users-group", + "conf-builders": "command-ref/conf-file.html#conf-builders", + "conf-builders-use-substitutes": "command-ref/conf-file.html#conf-builders-use-substitutes", + "conf-compress-build-log": "command-ref/conf-file.html#conf-compress-build-log", + "conf-connect-timeout": "command-ref/conf-file.html#conf-connect-timeout", + "conf-cores": "command-ref/conf-file.html#conf-cores", + "conf-diff-hook": "command-ref/conf-file.html#conf-diff-hook", + "conf-enforce-determinism": "command-ref/conf-file.html#conf-enforce-determinism", + "conf-env-keep-derivations": "command-ref/conf-file.html#conf-env-keep-derivations", + "conf-extra-binary-caches": "command-ref/conf-file.html#conf-extra-binary-caches", + "conf-extra-platforms": "command-ref/conf-file.html#conf-extra-platforms", + "conf-extra-sandbox-paths": "command-ref/conf-file.html#conf-extra-sandbox-paths", + "conf-extra-substituters": "command-ref/conf-file.html#conf-extra-substituters", + "conf-fallback": "command-ref/conf-file.html#conf-fallback", + "conf-fsync-metadata": "command-ref/conf-file.html#conf-fsync-metadata", + "conf-gc-keep-derivations": "command-ref/conf-file.html#conf-gc-keep-derivations", + "conf-gc-keep-outputs": "command-ref/conf-file.html#conf-gc-keep-outputs", + "conf-hashed-mirrors": "command-ref/conf-file.html#conf-hashed-mirrors", + "conf-http-connections": "command-ref/conf-file.html#conf-http-connections", + "conf-keep-build-log": "command-ref/conf-file.html#conf-keep-build-log", + "conf-keep-derivations": "command-ref/conf-file.html#conf-keep-derivations", + "conf-keep-env-derivations": "command-ref/conf-file.html#conf-keep-env-derivations", + "conf-keep-outputs": "command-ref/conf-file.html#conf-keep-outputs", + "conf-max-build-log-size": "command-ref/conf-file.html#conf-max-build-log-size", + "conf-max-free": "command-ref/conf-file.html#conf-max-free", + "conf-max-jobs": "command-ref/conf-file.html#conf-max-jobs", + "conf-max-silent-time": "command-ref/conf-file.html#conf-max-silent-time", + "conf-min-free": "command-ref/conf-file.html#conf-min-free", + "conf-narinfo-cache-negative-ttl": "command-ref/conf-file.html#conf-narinfo-cache-negative-ttl", + "conf-narinfo-cache-positive-ttl": "command-ref/conf-file.html#conf-narinfo-cache-positive-ttl", + "conf-netrc-file": "command-ref/conf-file.html#conf-netrc-file", + "conf-plugin-files": "command-ref/conf-file.html#conf-plugin-files", + "conf-post-build-hook": "command-ref/conf-file.html#conf-post-build-hook", + "conf-pre-build-hook": "command-ref/conf-file.html#conf-pre-build-hook", + "conf-repeat": "command-ref/conf-file.html#conf-repeat", + "conf-require-sigs": "command-ref/conf-file.html#conf-require-sigs", + "conf-restrict-eval": "command-ref/conf-file.html#conf-restrict-eval", + "conf-run-diff-hook": "command-ref/conf-file.html#conf-run-diff-hook", + "conf-sandbox": "command-ref/conf-file.html#conf-sandbox", + "conf-sandbox-dev-shm-size": "command-ref/conf-file.html#conf-sandbox-dev-shm-size", + "conf-sandbox-paths": "command-ref/conf-file.html#conf-sandbox-paths", + "conf-secret-key-files": "command-ref/conf-file.html#conf-secret-key-files", + "conf-show-trace": "command-ref/conf-file.html#conf-show-trace", + "conf-stalled-download-timeout": "command-ref/conf-file.html#conf-stalled-download-timeout", + "conf-substitute": "command-ref/conf-file.html#conf-substitute", + "conf-substituters": "command-ref/conf-file.html#conf-substituters", + "conf-system": "command-ref/conf-file.html#conf-system", + "conf-system-features": "command-ref/conf-file.html#conf-system-features", + "conf-tarball-ttl": "command-ref/conf-file.html#conf-tarball-ttl", + "conf-timeout": "command-ref/conf-file.html#conf-timeout", + "conf-trace-function-calls": "command-ref/conf-file.html#conf-trace-function-calls", + "conf-trusted-binary-caches": "command-ref/conf-file.html#conf-trusted-binary-caches", + "conf-trusted-public-keys": "command-ref/conf-file.html#conf-trusted-public-keys", + "conf-trusted-substituters": "command-ref/conf-file.html#conf-trusted-substituters", + "conf-trusted-users": "command-ref/conf-file.html#conf-trusted-users", + "extra-sandbox-paths": "command-ref/conf-file.html#extra-sandbox-paths", + "sec-conf-file": "command-ref/conf-file.html", + "env-NIX_PATH": "command-ref/env-common.html#env-NIX_PATH", + "env-common": "command-ref/env-common.html", + "envar-remote": "command-ref/env-common.html#env-NIX_REMOTE", + "sec-common-env": "command-ref/env-common.html", + "ch-files": "command-ref/files.html", + "ch-main-commands": "command-ref/main-commands.html", + "opt-out-link": "command-ref/nix-build.html#opt-out-link", + "sec-nix-build": "command-ref/nix-build.html", + "sec-nix-channel": "command-ref/nix-channel.html", + "sec-nix-collect-garbage": "command-ref/nix-collect-garbage.html", + "sec-nix-copy-closure": "command-ref/nix-copy-closure.html", + "sec-nix-daemon": "command-ref/nix-daemon.html", + "refsec-nix-env-install-examples": "command-ref/nix-env.html#examples", + "rsec-nix-env-install": "command-ref/nix-env.html#operation---install", + "rsec-nix-env-set": "command-ref/nix-env.html#operation---set", + "rsec-nix-env-set-flag": "command-ref/nix-env.html#operation---set-flag", + "rsec-nix-env-upgrade": "command-ref/nix-env.html#operation---upgrade", + "sec-nix-env": "command-ref/nix-env.html", + "ssec-version-comparisons": "command-ref/nix-env.html#versions", + "sec-nix-hash": "command-ref/nix-hash.html", + "sec-nix-instantiate": "command-ref/nix-instantiate.html", + "sec-nix-prefetch-url": "command-ref/nix-prefetch-url.html", + "sec-nix-shell": "command-ref/nix-shell.html", + "ssec-nix-shell-shebang": "command-ref/nix-shell.html#use-as-a--interpreter", + "nixref-queries": "command-ref/nix-store.html#queries", + "opt-add-root": "command-ref/nix-store.html#opt-add-root", + "refsec-nix-store-dump": "command-ref/nix-store.html#operation---dump", + "refsec-nix-store-export": "command-ref/nix-store.html#operation---export", + "refsec-nix-store-import": "command-ref/nix-store.html#operation---import", + "refsec-nix-store-query": "command-ref/nix-store.html#operation---query", + "refsec-nix-store-verify": "command-ref/nix-store.html#operation---verify", + "rsec-nix-store-gc": "command-ref/nix-store.html#operation---gc", + "rsec-nix-store-generate-binary-cache-key": "command-ref/nix-store.html#operation---generate-binary-cache-key", + "rsec-nix-store-realise": "command-ref/nix-store.html#operation---realise", + "rsec-nix-store-serve": "command-ref/nix-store.html#operation---serve", + "sec-nix-store": "command-ref/nix-store.html", + "opt-I": "command-ref/opt-common.html#opt-I", + "opt-attr": "command-ref/opt-common.html#opt-attr", + "opt-common": "command-ref/opt-common.html", + "opt-cores": "command-ref/opt-common.html#opt-cores", + "opt-log-format": "command-ref/opt-common.html#opt-log-format", + "opt-max-jobs": "command-ref/opt-common.html#opt-max-jobs", + "opt-max-silent-time": "command-ref/opt-common.html#opt-max-silent-time", + "opt-timeout": "command-ref/opt-common.html#opt-timeout", + "sec-common-options": "command-ref/opt-common.html", + "ch-utilities": "command-ref/utilities.html", + "chap-hacking": "contributing/hacking.html", + "adv-attr-allowSubstitutes": "language/advanced-attributes.html#adv-attr-allowSubstitutes", + "adv-attr-allowedReferences": "language/advanced-attributes.html#adv-attr-allowedReferences", + "adv-attr-allowedRequisites": "language/advanced-attributes.html#adv-attr-allowedRequisites", + "adv-attr-disallowedReferences": "language/advanced-attributes.html#adv-attr-disallowedReferences", + "adv-attr-disallowedRequisites": "language/advanced-attributes.html#adv-attr-disallowedRequisites", + "adv-attr-exportReferencesGraph": "language/advanced-attributes.html#adv-attr-exportReferencesGraph", + "adv-attr-impureEnvVars": "language/advanced-attributes.html#adv-attr-impureEnvVars", + "adv-attr-outputHash": "language/advanced-attributes.html#adv-attr-outputHash", + "adv-attr-outputHashAlgo": "language/advanced-attributes.html#adv-attr-outputHashAlgo", + "adv-attr-outputHashMode": "language/advanced-attributes.html#adv-attr-outputHashMode", + "adv-attr-passAsFile": "language/advanced-attributes.html#adv-attr-passAsFile", + "adv-attr-preferLocalBuild": "language/advanced-attributes.html#adv-attr-preferLocalBuild", + "fixed-output-drvs": "language/advanced-attributes.html#adv-attr-outputHash", + "sec-advanced-attributes": "language/advanced-attributes.html", + "builtin-abort": "language/builtins.html#builtins-abort", + "builtin-add": "language/builtins.html#builtins-add", + "builtin-all": "language/builtins.html#builtins-all", + "builtin-any": "language/builtins.html#builtins-any", + "builtin-attrNames": "language/builtins.html#builtins-attrNames", + "builtin-attrValues": "language/builtins.html#builtins-attrValues", + "builtin-baseNameOf": "language/builtins.html#builtins-baseNameOf", + "builtin-bitAnd": "language/builtins.html#builtins-bitAnd", + "builtin-bitOr": "language/builtins.html#builtins-bitOr", + "builtin-bitXor": "language/builtins.html#builtins-bitXor", + "builtin-builtins": "language/builtins.html#builtins-builtins", + "builtin-compareVersions": "language/builtins.html#builtins-compareVersions", + "builtin-concatLists": "language/builtins.html#builtins-concatLists", + "builtin-concatStringsSep": "language/builtins.html#builtins-concatStringsSep", + "builtin-currentSystem": "language/builtins.html#builtins-currentSystem", + "builtin-deepSeq": "language/builtins.html#builtins-deepSeq", + "builtin-derivation": "language/builtins.html#builtins-derivation", + "builtin-dirOf": "language/builtins.html#builtins-dirOf", + "builtin-div": "language/builtins.html#builtins-div", + "builtin-elem": "language/builtins.html#builtins-elem", + "builtin-elemAt": "language/builtins.html#builtins-elemAt", + "builtin-fetchGit": "language/builtins.html#builtins-fetchGit", + "builtin-fetchTarball": "language/builtins.html#builtins-fetchTarball", + "builtin-fetchurl": "language/builtins.html#builtins-fetchurl", + "builtin-filterSource": "language/builtins.html#builtins-filterSource", + "builtin-foldl-prime": "language/builtins.html#builtins-foldl-prime", + "builtin-fromJSON": "language/builtins.html#builtins-fromJSON", + "builtin-functionArgs": "language/builtins.html#builtins-functionArgs", + "builtin-genList": "language/builtins.html#builtins-genList", + "builtin-getAttr": "language/builtins.html#builtins-getAttr", + "builtin-getEnv": "language/builtins.html#builtins-getEnv", + "builtin-hasAttr": "language/builtins.html#builtins-hasAttr", + "builtin-hashFile": "language/builtins.html#builtins-hashFile", + "builtin-hashString": "language/builtins.html#builtins-hashString", + "builtin-head": "language/builtins.html#builtins-head", + "builtin-import": "language/builtins.html#builtins-import", + "builtin-intersectAttrs": "language/builtins.html#builtins-intersectAttrs", + "builtin-isAttrs": "language/builtins.html#builtins-isAttrs", + "builtin-isBool": "language/builtins.html#builtins-isBool", + "builtin-isFloat": "language/builtins.html#builtins-isFloat", + "builtin-isFunction": "language/builtins.html#builtins-isFunction", + "builtin-isInt": "language/builtins.html#builtins-isInt", + "builtin-isList": "language/builtins.html#builtins-isList", + "builtin-isNull": "language/builtins.html#builtins-isNull", + "builtin-isString": "language/builtins.html#builtins-isString", + "builtin-length": "language/builtins.html#builtins-length", + "builtin-lessThan": "language/builtins.html#builtins-lessThan", + "builtin-listToAttrs": "language/builtins.html#builtins-listToAttrs", + "builtin-map": "language/builtins.html#builtins-map", + "builtin-match": "language/builtins.html#builtins-match", + "builtin-mul": "language/builtins.html#builtins-mul", + "builtin-parseDrvName": "language/builtins.html#builtins-parseDrvName", + "builtin-path": "language/builtins.html#builtins-path", + "builtin-pathExists": "language/builtins.html#builtins-pathExists", + "builtin-placeholder": "language/builtins.html#builtins-placeholder", + "builtin-readDir": "language/builtins.html#builtins-readDir", + "builtin-readFile": "language/builtins.html#builtins-readFile", + "builtin-removeAttrs": "language/builtins.html#builtins-removeAttrs", + "builtin-replaceStrings": "language/builtins.html#builtins-replaceStrings", + "builtin-seq": "language/builtins.html#builtins-seq", + "builtin-sort": "language/builtins.html#builtins-sort", + "builtin-split": "language/builtins.html#builtins-split", + "builtin-splitVersion": "language/builtins.html#builtins-splitVersion", + "builtin-stringLength": "language/builtins.html#builtins-stringLength", + "builtin-sub": "language/builtins.html#builtins-sub", + "builtin-substring": "language/builtins.html#builtins-substring", + "builtin-tail": "language/builtins.html#builtins-tail", + "builtin-throw": "language/builtins.html#builtins-throw", + "builtin-toFile": "language/builtins.html#builtins-toFile", + "builtin-toJSON": "language/builtins.html#builtins-toJSON", + "builtin-toPath": "language/builtins.html#builtins-toPath", + "builtin-toString": "language/builtins.html#builtins-toString", + "builtin-toXML": "language/builtins.html#builtins-toXML", + "builtin-trace": "language/builtins.html#builtins-trace", + "builtin-tryEval": "language/builtins.html#builtins-tryEval", + "builtin-typeOf": "language/builtins.html#builtins-typeOf", + "ssec-builtins": "language/builtins.html", + "attr-system": "language/derivations.html#attr-system", + "ssec-derivation": "language/derivations.html", + "ch-expression-language": "language/index.html", + "sec-constructs": "language/constructs.html", + "sect-let-language": "language/constructs.html#let-language", + "ss-functions": "language/constructs.html#functions", + "sec-language-operators": "language/operators.html", + "table-operators": "language/operators.html", + "ssec-values": "language/values.html", + "gloss-closure": "glossary.html#gloss-closure", + "gloss-derivation": "glossary.html#gloss-derivation", + "gloss-deriver": "glossary.html#gloss-deriver", + "gloss-nar": "glossary.html#gloss-nar", + "gloss-output-path": "glossary.html#gloss-output-path", + "gloss-profile": "glossary.html#gloss-profile", + "gloss-reachable": "glossary.html#gloss-reachable", + "gloss-reference": "glossary.html#gloss-reference", + "gloss-substitute": "glossary.html#gloss-substitute", + "gloss-user-env": "glossary.html#gloss-user-env", + "gloss-validity": "glossary.html#gloss-validity", + "part-glossary": "glossary.html", + "sec-building-source": "installation/building-source.html", + "ch-env-variables": "installation/env-variables.html", + "sec-installer-proxy-settings": "installation/env-variables.html#proxy-environment-variables", + "sec-nix-ssl-cert-file": "installation/env-variables.html#nix_ssl_cert_file", + "sec-nix-ssl-cert-file-with-nix-daemon-and-macos": "installation/env-variables.html#nix_ssl_cert_file-with-macos-and-the-nix-daemon", + "chap-installation": "installation/installation.html", + "ch-installing-binary": "installation/installing-binary.html", + "sect-macos-installation": "installation/installing-binary.html#macos-installation", + "sect-macos-installation-change-store-prefix": "installation/installing-binary.html#macos-installation", + "sect-macos-installation-encrypted-volume": "installation/installing-binary.html#macos-installation", + "sect-macos-installation-recommended-notes": "installation/installing-binary.html#macos-installation", + "sect-macos-installation-symlink": "installation/installing-binary.html#macos-installation", + "sect-multi-user-installation": "installation/installing-binary.html#multi-user-installation", + "sect-nix-install-binary-tarball": "installation/installing-binary.html#installing-from-a-binary-tarball", + "sect-nix-install-pinned-version-url": "installation/installing-binary.html#installing-a-pinned-nix-version-from-a-url", + "sect-single-user-installation": "installation/installing-binary.html#single-user-installation", + "ch-installing-source": "installation/installing-source.html", + "ssec-multi-user": "installation/multi-user.html", + "ch-nix-security": "installation/nix-security.html", + "sec-obtaining-source": "installation/obtaining-source.html", + "sec-prerequisites-source": "installation/prerequisites-source.html", + "sec-single-user": "installation/single-user.html", + "ch-supported-platforms": "installation/supported-platforms.html", + "ch-upgrading-nix": "installation/upgrading.html", + "ch-about-nix": "introduction.html", + "chap-introduction": "introduction.html", + "ch-basic-package-mgmt": "package-management/basic-package-mgmt.html", + "ssec-binary-cache-substituter": "package-management/binary-cache-substituter.html", + "sec-channels": "package-management/channels.html", + "ssec-copy-closure": "package-management/copy-closure.html", + "sec-garbage-collection": "package-management/garbage-collection.html", + "ssec-gc-roots": "package-management/garbage-collector-roots.html", + "chap-package-management": "package-management/package-management.html", + "sec-profiles": "package-management/profiles.html", + "ssec-s3-substituter": "package-management/s3-substituter.html", + "ssec-s3-substituter-anonymous-reads": "package-management/s3-substituter.html#anonymous-reads-to-your-s3-compatible-binary-cache", + "ssec-s3-substituter-authenticated-reads": "package-management/s3-substituter.html#authenticated-reads-to-your-s3-binary-cache", + "ssec-s3-substituter-authenticated-writes": "package-management/s3-substituter.html#authenticated-writes-to-your-s3-compatible-binary-cache", + "sec-sharing-packages": "package-management/sharing-packages.html", + "ssec-ssh-substituter": "package-management/ssh-substituter.html", + "chap-quick-start": "quick-start.html", + "sec-relnotes": "release-notes/release-notes.html", + "ch-relnotes-0.10.1": "release-notes/rl-0.10.1.html", + "ch-relnotes-0.10": "release-notes/rl-0.10.html", + "ssec-relnotes-0.11": "release-notes/rl-0.11.html", + "ssec-relnotes-0.12": "release-notes/rl-0.12.html", + "ssec-relnotes-0.13": "release-notes/rl-0.13.html", + "ssec-relnotes-0.14": "release-notes/rl-0.14.html", + "ssec-relnotes-0.15": "release-notes/rl-0.15.html", + "ssec-relnotes-0.16": "release-notes/rl-0.16.html", + "ch-relnotes-0.5": "release-notes/rl-0.5.html", + "ch-relnotes-0.6": "release-notes/rl-0.6.html", + "ch-relnotes-0.7": "release-notes/rl-0.7.html", + "ch-relnotes-0.8.1": "release-notes/rl-0.8.1.html", + "ch-relnotes-0.8": "release-notes/rl-0.8.html", + "ch-relnotes-0.9.1": "release-notes/rl-0.9.1.html", + "ch-relnotes-0.9.2": "release-notes/rl-0.9.2.html", + "ch-relnotes-0.9": "release-notes/rl-0.9.html", + "ssec-relnotes-1.0": "release-notes/rl-1.0.html", + "ssec-relnotes-1.1": "release-notes/rl-1.1.html", + "ssec-relnotes-1.10": "release-notes/rl-1.10.html", + "ssec-relnotes-1.11.10": "release-notes/rl-1.11.10.html", + "ssec-relnotes-1.11": "release-notes/rl-1.11.html", + "ssec-relnotes-1.2": "release-notes/rl-1.2.html", + "ssec-relnotes-1.3": "release-notes/rl-1.3.html", + "ssec-relnotes-1.4": "release-notes/rl-1.4.html", + "ssec-relnotes-1.5.1": "release-notes/rl-1.5.1.html", + "ssec-relnotes-1.5.2": "release-notes/rl-1.5.2.html", + "ssec-relnotes-1.5": "release-notes/rl-1.5.html", + "ssec-relnotes-1.6.1": "release-notes/rl-1.6.1.html", + "ssec-relnotes-1.6.0": "release-notes/rl-1.6.html", + "ssec-relnotes-1.7": "release-notes/rl-1.7.html", + "ssec-relnotes-1.8": "release-notes/rl-1.8.html", + "ssec-relnotes-1.9": "release-notes/rl-1.9.html", + "ssec-relnotes-2.0": "release-notes/rl-2.0.html", + "ssec-relnotes-2.1": "release-notes/rl-2.1.html", + "ssec-relnotes-2.2": "release-notes/rl-2.2.html", + "ssec-relnotes-2.3": "release-notes/rl-2.3.html" + }, + "language/values.html": { + "simple-values": "#primitives", + "lists": "#list", + "strings": "#string", + "lists": "#list", + "attribute-sets": "#attribute-set" + } }; -var isRoot = (document.location.pathname.endsWith('/') || document.location.pathname.endsWith('/index.html')) && path_to_root === ''; -if (isRoot && redirects[document.location.hash]) { - document.location.href = path_to_root + redirects[document.location.hash]; +// the following code matches the current page's URL against the set of redirects. +// +// it is written to minimize the latency between page load and redirect. +// therefore we avoid function calls, copying data, and unnecessary loops. +// IMPORTANT: we use stateful array operations and their order matters! +// +// matching URLs is more involved than it should be: +// +// 1. `document.location.pathname` can have an arbitrary prefix. +// +// 2. `path_to_root` is set by mdBook. it consists only of `../`s and +// determines the depth of `` relative to the prefix: +// +// `document.location.pathname` +// |------------------------------| +// ///[[.html]][#] +// |----| +// `path_to_root` has same number of path segments +// +// source: https://phaiax.github.io/mdBook/format/theme/index-hbs.html#data +// +// 3. the following paths are equivalent: +// +// /foo/bar/ +// /foo/bar/index.html +// /foo/bar/index +// +// 4. the following paths are also equivalent: +// +// /foo/bar/baz +// /foo/bar/baz.html +// + +let segments = document.location.pathname.split('/'); + +let file = segments.pop(); + +// normalize file name +if (file === '') { file = "index.html"; } +else if (!file.endsWith('.html')) { file = file + '.html'; } + +segments.push(file); + +// use `path_to_root` to discern prefix from path. +const depth = path_to_root.split('/').length; + +// remove segments containing prefix. the following works because +// 1. the original `document.location.pathname` is absolute, +// hence first element of `segments` is always empty. +// 2. last element of splitting `path_to_root` is also always empty. +// 3. last element of `segments` is the file name. +// +// visual example: +// +// '/foo/bar/baz.html'.split('/') -> [ '', 'foo', 'bar', 'baz.html' ] +// '../'.split('/') -> [ '..', '' ] +// +// the following operations will then result in +// +// path = 'bar/baz.html' +// +segments.splice(0, segments.length - depth); +const path = segments.join('/'); + +// anchor starts with the hash character (`#`), +// but our redirect declarations don't, so we strip it. +// example: +// document.location.hash -> '#foo' +// document.location.hash.substring(1) -> 'foo' +const anchor = document.location.hash.substring(1); + +const redirect = redirects[path]; +if (redirect) { + const target = redirect[anchor]; + if (target) { + document.location.href = target; + } } diff --git a/doc/manual/src/command-ref/nix-daemon.md b/doc/manual/src/command-ref/nix-daemon.md index e91cb01dd..04b483be3 100644 --- a/doc/manual/src/command-ref/nix-daemon.md +++ b/doc/manual/src/command-ref/nix-daemon.md @@ -8,6 +8,6 @@ # Description -The Nix daemon is necessary in multi-user Nix installations. It performs -build actions and other operations on the Nix store on behalf of +The Nix daemon is necessary in multi-user Nix installations. It runs +build tasks and other operations on the Nix store on behalf of unprivileged users. diff --git a/doc/manual/src/command-ref/nix-store.md b/doc/manual/src/command-ref/nix-store.md index ecd838e8d..1251888e9 100644 --- a/doc/manual/src/command-ref/nix-store.md +++ b/doc/manual/src/command-ref/nix-store.md @@ -71,7 +71,7 @@ paths. Realisation is a somewhat overloaded term: outputs are already valid, in which case we are done immediately. Otherwise, there may be [substitutes](../glossary.md) that produce the outputs (e.g., by downloading them). Finally, the - outputs can be produced by performing the build action described + outputs can be produced by running the build task described by the derivation. - If the store path is not a derivation, realisation ensures that the diff --git a/doc/manual/src/glossary.md b/doc/manual/src/glossary.md index 70a0eb994..b13709f8a 100644 --- a/doc/manual/src/glossary.md +++ b/doc/manual/src/glossary.md @@ -1,7 +1,7 @@ # Glossary - [derivation]{#gloss-derivation}\ - A description of a build action. The result of a derivation is a + A description of a build task. The result of a derivation is a store object. Derivations are typically specified in Nix expressions using the [`derivation` primitive](language/derivations.md). These are translated into low-level *store derivations* (implicitly by @@ -53,8 +53,8 @@ A file that is an immediate child of the Nix store directory. These can be regular files, but also entire directory trees. Store objects can be sources (objects copied from outside of the store), - derivation outputs (objects produced by running a build action), or - derivations (files describing a build action). + derivation outputs (objects produced by running a build task), or + derivations (files describing a build task). - [input-addressed store object]{#gloss-input-addressed-store-object}\ A store object produced by building a diff --git a/doc/manual/src/installation/installing-binary.md b/doc/manual/src/installation/installing-binary.md index 2d007ca1b..31faeadc2 100644 --- a/doc/manual/src/installation/installing-binary.md +++ b/doc/manual/src/installation/installing-binary.md @@ -88,10 +88,24 @@ extension. The installer will also create `/etc/profile.d/nix.sh`. ### Linux -```console -sudo rm -rf /etc/profile/nix.sh /etc/nix /nix ~root/.nix-profile ~root/.nix-defexpr ~root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels +Remove files created by Nix: -# If you are on Linux with systemd, you will need to run: +```console +sudo rm -rf /nix /etc/nix /etc/profile/nix.sh ~root/.nix-profile ~root/.nix-defexpr ~root/.nix-channels ~/.nix-profile ~/.nix-defexpr ~/.nix-channels +``` + +Remove build users and their group: + +```console +for i in $(seq 30001 30032); do + sudo userdel $i +done +sudo groupdel 30000 +``` + +If you are on Linux with systemd, remove the Nix daemon service: + +```console sudo systemctl stop nix-daemon.socket sudo systemctl stop nix-daemon.service sudo systemctl disable nix-daemon.socket @@ -99,8 +113,13 @@ sudo systemctl disable nix-daemon.service sudo systemctl daemon-reload ``` -There may also be references to Nix in `/etc/profile`, `/etc/bashrc`, -and `/etc/zshrc` which you may remove. +There may also be references to Nix in + +- `/etc/profile` +- `/etc/bashrc` +- `/etc/zshrc` + +which you may remove. ### macOS diff --git a/doc/manual/src/introduction.md b/doc/manual/src/introduction.md index d87487a07..b54346db8 100644 --- a/doc/manual/src/introduction.md +++ b/doc/manual/src/introduction.md @@ -104,7 +104,7 @@ a currently running program. Packages are built from _Nix expressions_, which is a simple functional language. A Nix expression describes everything that goes -into a package build action (a “derivation”): other packages, sources, +into a package build task (a “derivation”): other packages, sources, the build script, environment variables for the build script, etc. Nix tries very hard to ensure that Nix expressions are _deterministic_: building a Nix expression twice should yield the same diff --git a/doc/manual/src/language/derivations.md b/doc/manual/src/language/derivations.md index 3391ec0d8..043a38191 100644 --- a/doc/manual/src/language/derivations.md +++ b/doc/manual/src/language/derivations.md @@ -1,7 +1,7 @@ # Derivations The most important built-in function is `derivation`, which is used to -describe a single derivation (a build action). It takes as input a set, +describe a single derivation (a build task). It takes as input a set, the attributes of which specify the inputs of the build. - There must be an attribute named [`system`]{#attr-system} whose value must be a diff --git a/doc/manual/src/language/index.md b/doc/manual/src/language/index.md index a4b402f8b..f9e9b9781 100644 --- a/doc/manual/src/language/index.md +++ b/doc/manual/src/language/index.md @@ -31,3 +31,551 @@ The Nix language is Type errors are only detected when expressions are evaluated. +# Overview + +This is an incomplete overview of language features, by example. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Example + + Description +
+ + + *Basic values* + + + + + + +
+ + `"hello world"` + + + + A string + +
+ + ``` + '' + multi + line + string + '' + ``` + + + + A multi-line string. Strips common prefixed whitespace. Evaluates to `"multi\n line\n string"`. + +
+ + `"hello ${ { a = "world" }.a }"` + + `"1 2 ${3}"` + + `"${pkgs.bash}/bin/sh"` + + + + String interpolation (expands to `"hello world"`, `"1 2 3"`, `"/nix/store/-bash-/bin/sh"`) + +
+ + `true`, `false` + + + + Booleans + +
+ + `null` + + + + Null value + +
+ + `123` + + + + An integer + +
+ + `3.141` + + + + A floating point number + +
+ + `/etc` + + + + An absolute path + +
+ + `./foo.png` + + + + A path relative to the file containing this Nix expression + +
+ + `~/.config` + + + + A home path. Evaluates to the `"/.config"`. + +
+ + + + + + Search path. Value determined by [`$NIX_PATH` environment variable](../command-ref/env-common.md#env-NIX_PATH). + +
+ + *Compound values* + + + + + +
+ + `{ x = 1; y = 2; }` + + + + A set with attributes named `x` and `y` + +
+ + `{ foo.bar = 1; }` + + + + A nested set, equivalent to `{ foo = { bar = 1; }; }` + +
+ + `rec { x = "foo"; y = x + "bar"; }` + + + + A recursive set, equivalent to `{ x = "foo"; y = "foobar"; }` + +
+ + `[ "foo" "bar" "baz" ]` + + `[ 1 2 3 ]` + + `[ (f 1) { a = 1; b = 2; } [ "c" ] ]` + + + + Lists with three elements. + +
+ + *Operators* + + + + + +
+ + `"foo" + "bar"` + + + + String concatenation + +
+ + `1 + 2` + + + + Integer addition + +
+ + `"foo" == "f" + "oo"` + + + + Equality test (evaluates to `true`) + +
+ + `"foo" != "bar"` + + + + Inequality test (evaluates to `true`) + +
+ + `!true` + + + + Boolean negation + +
+ + `{ x = 1; y = 2; }.x` + + + + Attribute selection (evaluates to `1`) + +
+ + `{ x = 1; y = 2; }.z or 3` + + + + Attribute selection with default (evaluates to `3`) + +
+ + `{ x = 1; y = 2; } // { z = 3; }` + + + + Merge two sets (attributes in the right-hand set taking precedence) + +
+ + *Control structures* + + + + + +
+ + `if 1 + 1 == 2 then "yes!" else "no!"` + + + + Conditional expression + +
+ + `assert 1 + 1 == 2; "yes!"` + + + + Assertion check (evaluates to `"yes!"`). + +
+ + `let x = "foo"; y = "bar"; in x + y` + + + + Variable definition + +
+ + `with builtins; head [ 1 2 3 ]` + + + + Add all attributes from the given set to the scope (evaluates to `1`) + +
+ + *Functions (lambdas)* + + + + + +
+ + `x: x + 1` + + + + A function that expects an integer and returns it increased by 1 + +
+ + `x: y: x + y` + + + + Curried function, equivalent to `x: (y: x + y)`. Can be used like a function that takes two arguments and returns their sum. + +
+ + `(x: x + 1) 100` + + + + A function call (evaluates to 101) + +
+ + `let inc = x: x + 1; in inc (inc (inc 100))` + + + + A function bound to a variable and subsequently called by name (evaluates to 103) + +
+ + `{ x, y }: x + y` + + + + A function that expects a set with required attributes `x` and `y` and concatenates them + +
+ + `{ x, y ? "bar" }: x + y` + + + + A function that expects a set with required attribute `x` and optional `y`, using `"bar"` as default value for `y` + +
+ + `{ x, y, ... }: x + y` + + + + A function that expects a set with required attributes `x` and `y` and ignores any other attributes + +
+ + `{ x, y } @ args: x + y` + + `args @ { x, y }: x + y` + + + + A function that expects a set with required attributes `x` and `y`, and binds the whole set to `args` + +
+ + *Built-in functions* + + + + + +
+ + `import ./foo.nix` + + + + Load and return Nix expression in given file + +
+ + `map (x: x + x) [ 1 2 3 ]` + + + + Apply a function to every element of a list (evaluates to `[ 2 4 6 ]`) + +
diff --git a/doc/manual/src/language/values.md b/doc/manual/src/language/values.md index f09400d02..6fc8c0369 100644 --- a/doc/manual/src/language/values.md +++ b/doc/manual/src/language/values.md @@ -150,6 +150,20 @@ recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division operation. `./a.${foo}/b.${bar}` is a path. + When a path appears in an antiquotation, and is thus coerced into a string, + the path is first copied into the Nix store and the resulting string is + the Nix store path. For instance `"${./foo.txt}" will cause `foo.txt` in + the current directory to be copied into the Nix store and result in the + string `"/nix/store/-foo.txt"`. + + Note that the Nix language assumes that all input files will remain + _unchanged_ during the course of the Nix expression evaluation. + If you for example antiquote a file path during a `nix repl` session, and + then later in the same session, after having changed the file contents, + evaluate the antiquotation with the file path again, then Nix will still + return the first store path. It will _not_ reread the file contents to + produce a different Nix store path. + - Boolean *Booleans* with values `true` and `false`. diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index a39339050..96c0f302b 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -58,7 +58,7 @@ readonly EXTRACTED_NIX_PATH="$(dirname "$0")" readonly ROOT_HOME=~root -if [ -t 0 ]; then +if [ -t 0 ] && [ -z "${NIX_INSTALLER_YES:-}" ]; then readonly IS_HEADLESS='no' else readonly IS_HEADLESS='yes' diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh index d4eed2efe..ccd19e1a8 100644 --- a/scripts/install-nix-from-closure.sh +++ b/scripts/install-nix-from-closure.sh @@ -71,6 +71,8 @@ while [ $# -gt 0 ]; do # # intentional tail space # ACTIONS="${ACTIONS}uninstall " # ;; + --yes) + export NIX_INSTALLER_YES=1;; --no-channel-add) export NIX_INSTALLER_NO_CHANNEL_ADD=1;; --daemon-user-count) @@ -90,7 +92,7 @@ while [ $# -gt 0 ]; do shift;; *) { - echo "Nix Installer [--daemon|--no-daemon] [--daemon-user-count INT] [--no-channel-add] [--no-modify-profile] [--nix-extra-conf-file FILE]" + echo "Nix Installer [--daemon|--no-daemon] [--daemon-user-count INT] [--yes] [--no-channel-add] [--no-modify-profile] [--nix-extra-conf-file FILE]" echo "Choose installation method." echo "" @@ -104,6 +106,8 @@ while [ $# -gt 0 ]; do echo " trivial to uninstall." echo " (default)" echo "" + echo " --yes: Run the script non-interactively, accepting all prompts." + echo "" echo " --no-channel-add: Don't add any channels. nixpkgs-unstable is installed by default." echo "" echo " --no-modify-profile: Don't modify the user profile to automatically load nix." diff --git a/scripts/nix-profile.fish.in b/scripts/nix-profile.fish.in index 59d247771..8d783d7c0 100644 --- a/scripts/nix-profile.fish.in +++ b/scripts/nix-profile.fish.in @@ -28,7 +28,9 @@ if test -n "$HOME" && test -n "$USER" # Only use MANPATH if it is already set. In general `man` will just simply # pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin` # which is in the $PATH. For more info, run `manpath -d`. - set --export --prepend --path MANPATH "$NIX_LINK/share/man" + if set --query MANPATH + set --export --prepend --path MANPATH "$NIX_LINK/share/man" + end fish_add_path --prepend --global "$NIX_LINK/bin" set --erase NIX_LINK diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index ff8ba2724..6b81ecc49 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -186,12 +186,12 @@ static int main_build_remote(int argc, char * * argv) // build the hint template. std::string errorText = "Failed to find a machine for remote build!\n" - "derivation: %s\nrequired (system, features): (%s, %s)"; + "derivation: %s\nrequired (system, features): (%s, [%s])"; errorText += "\n%s available machines:"; errorText += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)"; for (unsigned int i = 0; i < machines.size(); ++i) - errorText += "\n(%s, %s, %s, %s)"; + errorText += "\n([%s], %s, [%s], [%s])"; // add the template values. std::string drvstr; diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 14bb27936..0740ea960 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -88,7 +88,8 @@ EvalCommand::EvalCommand() { addFlag({ .longName = "debugger", - .description = "start an interactive environment if evaluation fails", + .description = "Start an interactive environment if evaluation fails.", + .category = MixEvalArgs::category, .handler = {&startReplOnEvalErrors, true}, }); } @@ -225,7 +226,7 @@ MixProfile::MixProfile() { addFlag({ .longName = "profile", - .description = "The profile to update.", + .description = "The profile to operate on.", .labels = {"path"}, .handler = {&profile}, .completer = completePath diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 5b6e82388..140ed3b88 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -13,8 +13,6 @@ namespace nix { MixEvalArgs::MixEvalArgs() { - auto category = "Common evaluation options"; - addFlag({ .longName = "arg", .description = "Pass the value *expr* as the argument *name* to Nix functions.", diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh index 03fa226aa..1ec800613 100644 --- a/src/libcmd/common-eval-args.hh +++ b/src/libcmd/common-eval-args.hh @@ -10,6 +10,8 @@ class Bindings; struct MixEvalArgs : virtual Args { + static constexpr auto category = "Common evaluation options"; + MixEvalArgs(); Bindings * getAutoArgs(EvalState & state); diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 61c05050f..df8932087 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -1050,7 +1050,7 @@ struct CmdRepl : InstallablesCommand evalSettings.pureEval = false; } - void prepare() + void prepare() override { if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) { warn("future versions of Nix will require using `--file` to load a file"); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e3716f217..563f24e48 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -904,7 +904,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2, const std::string & s3) { debugThrowLastTrace(EvalError({ - .msg = hintfmt(s, s2), + .msg = hintfmt(s, s2, s3), .errPos = positions[noPos] })); } @@ -913,7 +913,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri const std::string & s3) { debugThrowLastTrace(EvalError({ - .msg = hintfmt(s, s2), + .msg = hintfmt(s, s2, s3), .errPos = positions[pos] })); } @@ -922,7 +922,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri const std::string & s3, Env & env, Expr & expr) { debugThrow(EvalError({ - .msg = hintfmt(s, s2), + .msg = hintfmt(s, s2, s3), .errPos = positions[pos] }), env, expr); } diff --git a/src/libexpr/flake/call-flake.nix b/src/libexpr/flake/call-flake.nix index 932ac5e90..8061db3df 100644 --- a/src/libexpr/flake/call-flake.nix +++ b/src/libexpr/flake/call-flake.nix @@ -43,7 +43,7 @@ let outputs = flake.outputs (inputs // { self = result; }); - result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; }; + result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; _type = "flake"; }; in if node.flake or true then assert builtins.isFunction flake.outputs; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ff620ca63..22f6ad3cc 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -3826,8 +3826,8 @@ static RegisterPrimOp primop_parseDrvName({ .args = {"s"}, .doc = R"( Split the string *s* into a package name and version. The package - name is everything up to but not including the first dash followed - by a digit, and the version is everything following that dash. The + name is everything up to but not including the first dash not followed + by a letter, and the version is everything following that dash. The result is returned in a set `{ name, version }`. Thus, `builtins.parseDrvName "nix-0.12pre12876"` returns `{ name = "nix"; version = "0.12pre12876"; }`. diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index c1a21e764..7b7a1be35 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -485,6 +485,10 @@ struct GitInputScheme : InputScheme } input.attrs.insert_or_assign("ref", *head); unlockedAttrs.insert_or_assign("ref", *head); + } else { + if (!input.getRev()) { + unlockedAttrs.insert_or_assign("ref", input.getRef().value()); + } } if (auto res = getCache()->lookup(store, unlockedAttrs)) { diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index a491d82a6..2115ce2f5 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -262,17 +262,20 @@ struct GitHubInputScheme : GitArchiveInputScheme DownloadUrl getDownloadUrl(const Input & input) const override { - // FIXME: use regular /archive URLs instead? api.github.com - // might have stricter rate limits. auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com"); - auto url = fmt( - host == "github.com" - ? "https://api.%s/repos/%s/%s/tarball/%s" - : "https://%s/api/v3/repos/%s/%s/tarball/%s", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), + Headers headers = makeHeadersWithAuthTokens(host); + // If we have no auth headers then we default to the public archive + // urls so we do not run into rate limits. + const auto urlFmt = + host != "github.com" + ? "https://%s/api/v3/repos/%s/%s/tarball/%s" + : headers.empty() + ? "https://%s/%s/%s/archive/%s.tar.gz" + : "https://api.%s/repos/%s/%s/tarball/%s"; + + const auto url = fmt(urlFmt, host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), input.getRev()->to_string(Base16, false)); - Headers headers = makeHeadersWithAuthTokens(host); return DownloadUrl { url, headers }; } diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc index 12f5403ea..f92920d18 100644 --- a/src/libmain/common-args.cc +++ b/src/libmain/common-args.cc @@ -32,6 +32,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName) addFlag({ .longName = "option", .description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).", + .category = miscCategory, .labels = {"name", "value"}, .handler = {[](std::string name, std::string value) { try { diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh index 25453b8c6..f180d83ce 100644 --- a/src/libmain/common-args.hh +++ b/src/libmain/common-args.hh @@ -6,6 +6,7 @@ namespace nix { //static constexpr auto commonArgsCategory = "Miscellaneous common options"; static constexpr auto loggingCategory = "Logging-related options"; +static constexpr auto miscCategory = "Miscellaneous global options"; class MixCommonArgs : public virtual Args { diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index 0bbeaff8d..961f4e18a 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -503,7 +503,7 @@ public: return s[0]; } - virtual void setPrintBuildLogs(bool printBuildLogs) + void setPrintBuildLogs(bool printBuildLogs) override { this->printBuildLogs = printBuildLogs; } diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index c1cf38565..a58428762 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -33,6 +33,7 @@ namespace nix { +char * * savedArgv; static bool gcWarning = true; diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 0cc56d47d..3c37fd627 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -113,5 +113,25 @@ struct PrintFreed /* Install a SIGSEGV handler to detect stack overflows. */ void detectStackOverflow(); +/* Pluggable behavior to run in case of a stack overflow. + + Default value: defaultStackOverflowHandler. + + This is called by the handler installed by detectStackOverflow(). + + This gives Nix library consumers a limit opportunity to report the error + condition. The handler should exit the process. + See defaultStackOverflowHandler() for a reference implementation. + + NOTE: Use with diligence, because this runs in the signal handler, with very + limited stack space and a potentially a corrupted heap, all while the failed + thread is blocked indefinitely. All functions called must be reentrant. */ +extern std::function stackOverflowHandler; + +/* The default, robust implementation of stackOverflowHandler. + + Prints an error message directly to stderr using a syscall instead of the + logger. Exits the process immediately after. */ +void defaultStackOverflowHandler(siginfo_t * info, void * ctx); } diff --git a/src/libmain/stack.cc b/src/libmain/stack.cc index b0a4a4c5d..10f71c1dc 100644 --- a/src/libmain/stack.cc +++ b/src/libmain/stack.cc @@ -1,4 +1,5 @@ #include "error.hh" +#include "shared.hh" #include #include @@ -29,9 +30,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx) ptrdiff_t diff = (char *) info->si_addr - sp; if (diff < 0) diff = -diff; if (diff < 4096) { - char msg[] = "error: stack overflow (possible infinite recursion)\n"; - [[gnu::unused]] auto res = write(2, msg, strlen(msg)); - _exit(1); // maybe abort instead? + nix::stackOverflowHandler(info, ctx); } } @@ -67,5 +66,12 @@ void detectStackOverflow() #endif } +std::function stackOverflowHandler(defaultStackOverflowHandler); + +void defaultStackOverflowHandler(siginfo_t * info, void * ctx) { + char msg[] = "error: stack overflow (possible infinite recursion)\n"; + [[gnu::unused]] auto res = write(2, msg, strlen(msg)); + _exit(1); // maybe abort instead? +} } diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 9226c4e19..a26770c79 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -331,6 +331,17 @@ bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath) return fileExists(narInfoFileFor(storePath)); } +std::optional BinaryCacheStore::queryPathFromHashPart(const std::string & hashPart) +{ + auto pseudoPath = StorePath(hashPart + "-" + MissingName); + try { + auto info = queryPathInfo(pseudoPath); + return info->path; + } catch (InvalidPath &) { + return std::nullopt; + } +} + void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink) { auto info = queryPathInfo(storePath).cast(); diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index ca538b3cb..8c82e2387 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -95,8 +95,7 @@ public: void queryPathInfoUncached(const StorePath & path, Callback> callback) noexcept override; - std::optional queryPathFromHashPart(const std::string & hashPart) override - { unsupported("queryPathFromHashPart"); } + std::optional queryPathFromHashPart(const std::string & hashPart) override; void addToStore(const ValidPathInfo & info, Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs) override; diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc index 1f19ddccc..cb58a1f02 100644 --- a/src/libstore/build/hook-instance.cc +++ b/src/libstore/build/hook-instance.cc @@ -16,11 +16,11 @@ HookInstance::HookInstance() buildHookArgs.pop_front(); Strings args; + args.push_back(std::string(baseNameOf(buildHook))); for (auto & arg : buildHookArgs) args.push_back(arg); - args.push_back(std::string(baseNameOf(settings.buildHook.get()))); args.push_back(std::to_string(verbosity)); /* Create a pipe to get the output of the child. */ diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 18b682e13..5cea3b590 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -1594,6 +1594,8 @@ void LocalDerivationGoal::runChild() /* Warning: in the child we should absolutely not make any SQLite calls! */ + bool sendException = true; + try { /* child */ commonChildInit(builderOut); @@ -2050,6 +2052,8 @@ void LocalDerivationGoal::runChild() /* Indicate that we managed to set up the build environment. */ writeFull(STDERR_FILENO, std::string("\2\n")); + sendException = false; + /* Execute the program. This should not return. */ if (drv->isBuiltin()) { try { @@ -2103,10 +2107,13 @@ void LocalDerivationGoal::runChild() throw SysError("executing '%1%'", drv->builder); } catch (Error & e) { - writeFull(STDERR_FILENO, "\1\n"); - FdSink sink(STDERR_FILENO); - sink << e; - sink.flush(); + if (sendException) { + writeFull(STDERR_FILENO, "\1\n"); + FdSink sink(STDERR_FILENO); + sink << e; + sink.flush(); + } else + std::cerr << e.msg(); _exit(1); } } diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index d724897bb..ff658c428 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -154,13 +154,9 @@ StringSet Settings::getDefaultExtraPlatforms() // machines. Note that we can’t force processes from executing // x86_64 in aarch64 environments or vice versa since they can // always exec with their own binary preferences. - if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist") || - pathExists("/System/Library/LaunchDaemons/com.apple.oahd.plist")) { - if (std::string{SYSTEM} == "x86_64-darwin") - extraPlatforms.insert("aarch64-darwin"); - else if (std::string{SYSTEM} == "aarch64-darwin") - extraPlatforms.insert("x86_64-darwin"); - } + if (std::string{SYSTEM} == "aarch64-darwin" && + runProgram(RunOptions {.program = "arch", .args = {"-arch", "x86_64", "/usr/bin/true"}, .mergeStderrToStdout = true}).first == 0) + extraPlatforms.insert("x86_64-darwin"); #endif return extraPlatforms; diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 1bbad71f2..69bfe3418 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -67,7 +67,7 @@ std::unique_ptr SSHMaster::startCommand(const std::string if (fakeSSH) { args = { "bash", "-c" }; } else { - args = { "ssh", host.c_str(), "-x", "-a" }; + args = { "ssh", host.c_str(), "-x" }; addCommonSSHOpts(args); if (socketPath != "") args.insert(args.end(), {"-S", socketPath}); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 86b12257a..06a9758fc 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1363,9 +1363,9 @@ std::shared_ptr openFromNonUri(const std::string & uri, const Store::Para } catch (Error & e) { return std::make_shared(params); } - warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore); + warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore); } else - debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore); + debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore); Store::Params params2; params2["root"] = chrootStore; return std::make_shared(params2); diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index a7db58559..238d0a7a6 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -77,9 +77,7 @@ TarArchive::~TarArchive() static void extract_archive(TarArchive & archive, const Path & destDir) { - int flags = ARCHIVE_EXTRACT_FFLAGS - | ARCHIVE_EXTRACT_PERM - | ARCHIVE_EXTRACT_TIME + int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_SECURE_NODOTDOT; @@ -98,6 +96,10 @@ static void extract_archive(TarArchive & archive, const Path & destDir) archive_entry_copy_pathname(entry, (destDir + "/" + name).c_str()); + // sources can and do contain dirs with no rx bits + if (archive_entry_filetype(entry) == AE_IFDIR && (archive_entry_mode(entry) & 0500) != 0500) + archive_entry_set_mode(entry, archive_entry_mode(entry) | 0500); + // Patch hardlink path const char *original_hardlink = archive_entry_hardlink(entry); if (original_hardlink) { diff --git a/src/nix/app.cc b/src/nix/app.cc index 821964f86..48de8fb82 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -66,7 +66,9 @@ UnresolvedApp Installable::toApp(EvalState & state) auto type = cursor->getAttr("type")->getString(); - std::string expected = !attrPath.empty() && state.symbols[attrPath[0]] == "apps" ? "app" : "derivation"; + std::string expected = !attrPath.empty() && + (state.symbols[attrPath[0]] == "apps" || state.symbols[attrPath[0]] == "defaultApp") + ? "app" : "derivation"; if (type != expected) throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected); diff --git a/src/nix/daemon.md b/src/nix/daemon.md index e97016a94..d5cdadf08 100644 --- a/src/nix/daemon.md +++ b/src/nix/daemon.md @@ -11,7 +11,7 @@ R""( # Description This command runs the Nix daemon, which is a required component in -multi-user Nix installations. It performs build actions and other +multi-user Nix installations. It runs build tasks and other operations on the Nix store on behalf of non-root users. Usually you don't run the daemon directly; instead it's managed by a service management framework such as `systemd`. diff --git a/src/nix/main.cc b/src/nix/main.cc index e0155cd5d..2c6309c81 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -53,7 +53,6 @@ static bool haveInternet() } std::string programPath; -char * * savedArgv; struct HelpRequested { }; @@ -74,6 +73,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs addFlag({ .longName = "help", .description = "Show usage information.", + .category = miscCategory, .handler = {[&]() { throw HelpRequested(); }}, }); @@ -88,6 +88,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs addFlag({ .longName = "version", .description = "Show version information.", + .category = miscCategory, .handler = {[&]() { showVersion = true; }}, }); @@ -95,12 +96,14 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs .longName = "offline", .aliases = {"no-net"}, // FIXME: remove .description = "Disable substituters and consider all previously downloaded files up-to-date.", + .category = miscCategory, .handler = {[&]() { useNet = false; }}, }); addFlag({ .longName = "refresh", .description = "Consider all previously downloaded files out-of-date.", + .category = miscCategory, .handler = {[&]() { refresh = true; }}, }); } @@ -187,7 +190,7 @@ static void showHelp(std::vector subcommand, MultiCommand & topleve *vUtils); auto attrs = state.buildBindings(16); - attrs.alloc("command").mkString(toplevel.toJSON().dump()); + attrs.alloc("toplevel").mkString(toplevel.toJSON().dump()); auto vRes = state.allocValue(); state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos); @@ -266,7 +269,7 @@ void mainWrapped(int argc, char * * argv) programPath = argv[0]; auto programName = std::string(baseNameOf(programPath)); - if (argc > 0 && std::string_view(argv[0]) == "__build-remote") { + if (argc > 1 && std::string_view(argv[1]) == "__build-remote") { programName = "build-remote"; argv++; argc--; } diff --git a/src/nix/path-from-hash-part.cc b/src/nix/path-from-hash-part.cc new file mode 100644 index 000000000..7f7cda8d3 --- /dev/null +++ b/src/nix/path-from-hash-part.cc @@ -0,0 +1,39 @@ +#include "command.hh" +#include "store-api.hh" + +using namespace nix; + +struct CmdPathFromHashPart : StoreCommand +{ + std::string hashPart; + + CmdPathFromHashPart() + { + expectArgs({ + .label = "hash-part", + .handler = {&hashPart}, + }); + } + + std::string description() override + { + return "get a store path from its hash part"; + } + + std::string doc() override + { + return + #include "path-from-hash-part.md" + ; + } + + void run(ref store) override + { + if (auto storePath = store->queryPathFromHashPart(hashPart)) + logger->cout(store->printStorePath(*storePath)); + else + throw Error("there is no store path corresponding to '%s'", hashPart); + } +}; + +static auto rCmdPathFromHashPart = registerCommand2({"store", "path-from-hash-part"}); diff --git a/src/nix/path-from-hash-part.md b/src/nix/path-from-hash-part.md new file mode 100644 index 000000000..788e13ab6 --- /dev/null +++ b/src/nix/path-from-hash-part.md @@ -0,0 +1,20 @@ +R""( + +# Examples + +* Return the full store path with the given hash part: + + ```console + # nix store path-from-hash-part --store https://cache.nixos.org/ 0i2jd68mp5g6h2sa5k9c85rb80sn8hi9 + /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10 + ``` + +# Description + +Given the hash part of a store path (that is, the 32 characters +following `/nix/store/`), return the full store path. This is +primarily useful in the implementation of binary caches, where a +request for a `.narinfo` file only supplies the hash part +(e.g. `https://cache.nixos.org/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9.narinfo`). + +)"" diff --git a/src/nix/repl.md b/src/nix/repl.md index 23ef0f4e6..c5113be61 100644 --- a/src/nix/repl.md +++ b/src/nix/repl.md @@ -36,7 +36,7 @@ R""( Loading Installable ''... Added 1 variables. - # nix repl --extra_experimental_features 'flakes repl-flake' nixpkgs + # nix repl --extra-experimental-features 'flakes repl-flake' nixpkgs Loading Installable 'flake:nixpkgs#'... Added 5 variables. diff --git a/tests/fetchGit.sh b/tests/fetchGit.sh index 166bccfc7..4ceba0293 100644 --- a/tests/fetchGit.sh +++ b/tests/fetchGit.sh @@ -24,12 +24,14 @@ touch $repo/.gitignore git -C $repo add hello .gitignore git -C $repo commit -m 'Bla1' rev1=$(git -C $repo rev-parse HEAD) +git -C $repo tag -a tag1 -m tag1 echo world > $repo/hello git -C $repo commit -m 'Bla2' -a git -C $repo worktree add $TEST_ROOT/worktree echo hello >> $TEST_ROOT/worktree/hello rev2=$(git -C $repo rev-parse HEAD) +git -C $repo tag -a tag2 -m tag2 # Fetch a worktree unset _NIX_FORCE_HTTP @@ -217,6 +219,16 @@ rev4_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$ path9=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; name = \"foo\"; }).outPath") [[ $path9 =~ -foo$ ]] +# Specifying a ref without a rev shouldn't pick a cached rev for a different ref +export _NIX_FORCE_HTTP=1 +rev_tag1_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag1\"; }).rev") +rev_tag1=$(git -C $repo rev-parse refs/tags/tag1) +[[ $rev_tag1_nix = $rev_tag1 ]] +rev_tag2_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag2\"; }).rev") +rev_tag2=$(git -C $repo rev-parse refs/tags/tag2) +[[ $rev_tag2_nix = $rev_tag2 ]] +unset _NIX_FORCE_HTTP + # should fail if there is no repo rm -rf $repo/.git (! nix eval --impure --raw --expr "(builtins.fetchGit \"file://$repo\").outPath") diff --git a/tests/github-flakes.nix b/tests/github-flakes.nix index fc481c7e3..43a4f1432 100644 --- a/tests/github-flakes.nix +++ b/tests/github-flakes.nix @@ -7,7 +7,7 @@ with import (nixpkgs + "/nixos/lib/testing-python.nix") { let - # Generate a fake root CA and a fake api.github.com / channels.nixos.org certificate. + # Generate a fake root CA and a fake api.github.com / github.com / channels.nixos.org certificate. cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; } '' mkdir -p $out @@ -18,7 +18,7 @@ let openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \ -subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=github.com" -out server.csr - openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:channels.nixos.org") \ + openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:channels.nixos.org") \ -days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt ''; @@ -37,6 +37,17 @@ let "owner": "NixOS", "repo": "nixpkgs" } + }, + { + "from": { + "type": "indirect", + "id": "private-flake" + }, + "to": { + "type": "github", + "owner": "fancy-enterprise", + "repo": "private-flake" + } } ], "version": 2 @@ -45,20 +56,40 @@ let destination = "/flake-registry.json"; }; - api = pkgs.runCommand "nixpkgs-flake" {} + private-flake-rev = "9f1dd0df5b54a7dc75b618034482ed42ce34383d"; + + private-flake-api = pkgs.runCommand "private-flake" {} '' - mkdir -p $out/tarball + mkdir -p $out/{commits,tarball} + + # Setup https://docs.github.com/en/rest/commits/commits#get-a-commit + echo '{"sha": "${private-flake-rev}"}' > $out/commits/HEAD + + # Setup tarball download via API + dir=private-flake + mkdir $dir + echo '{ outputs = {...}: {}; }' > $dir/flake.nix + tar cfz $out/tarball/${private-flake-rev} $dir --hard-dereference + ''; + + nixpkgs-api = pkgs.runCommand "nixpkgs-flake" {} + '' + mkdir -p $out/commits + + # Setup https://docs.github.com/en/rest/commits/commits#get-a-commit + echo '{"sha": "${nixpkgs.rev}"}' > $out/commits/HEAD + ''; + + archive = pkgs.runCommand "nixpkgs-flake" {} + '' + mkdir -p $out/archive dir=NixOS-nixpkgs-${nixpkgs.shortRev} cp -prd ${nixpkgs} $dir # Set the correct timestamp in the tarball. find $dir -print0 | xargs -0 touch -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} -- - tar cfz $out/tarball/${nixpkgs.rev} $dir --hard-dereference - - mkdir -p $out/commits - echo '{"sha": "${nixpkgs.rev}"}' > $out/commits/HEAD + tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference ''; - in makeTest ( @@ -93,7 +124,20 @@ makeTest ( sslServerCert = "${cert}/server.crt"; servedDirs = [ { urlPath = "/repos/NixOS/nixpkgs"; - dir = api; + dir = nixpkgs-api; + } + { urlPath = "/repos/fancy-enterprise/private-flake"; + dir = private-flake-api; + } + ]; + }; + services.httpd.virtualHosts."github.com" = + { forceSSL = true; + sslServerKey = "${cert}/server.key"; + sslServerCert = "${cert}/server.crt"; + servedDirs = + [ { urlPath = "/NixOS/nixpkgs"; + dir = archive; } ]; }; @@ -107,9 +151,8 @@ makeTest ( virtualisation.memorySize = 4096; nix.binaryCaches = lib.mkForce [ ]; nix.extraOptions = "experimental-features = nix-command flakes"; - environment.systemPackages = [ pkgs.jq ]; networking.hosts.${(builtins.head nodes.github.config.networking.interfaces.eth1.ipv4.addresses).address} = - [ "channels.nixos.org" "api.github.com" ]; + [ "channels.nixos.org" "api.github.com" "github.com" ]; security.pki.certificateFiles = [ "${cert}/ca.crt" ]; }; }; @@ -121,22 +164,39 @@ makeTest ( start_all() + def cat_log(): + github.succeed("cat /var/log/httpd/*.log >&2") + github.wait_for_unit("httpd.service") - client.succeed("curl -v https://api.github.com/ >&2") - client.succeed("nix registry list | grep nixpkgs") + client.succeed("curl -v https://github.com/ >&2") + out = client.succeed("nix registry list") + print(out) + assert "github:NixOS/nixpkgs" in out, "nixpkgs flake not found" + assert "github:fancy-enterprise/private-flake" in out, "private flake not found" + cat_log() - rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision") - assert rev.strip() == "${nixpkgs.rev}", "revision mismatch" + # If no github access token is provided, nix should use the public archive url... + out = client.succeed("nix flake metadata nixpkgs --json") + print(out) + info = json.loads(out) + assert info["revision"] == "${nixpkgs.rev}", f"revision mismatch: {info['revision']} != ${nixpkgs.rev}" + cat_log() + + # ... otherwise it should use the API + out = client.succeed("nix flake metadata private-flake --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0") + print(out) + info = json.loads(out) + assert info["revision"] == "${private-flake-rev}", f"revision mismatch: {info['revision']} != ${private-flake-rev}" + cat_log() client.succeed("nix registry pin nixpkgs") - - client.succeed("nix flake info nixpkgs --tarball-ttl 0 >&2") + client.succeed("nix flake metadata nixpkgs --tarball-ttl 0 >&2") # Shut down the web server. The flake should be cached on the client. github.succeed("systemctl stop httpd.service") - info = json.loads(client.succeed("nix flake info nixpkgs --json")) + info = json.loads(client.succeed("nix flake metadata nixpkgs --json")) date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified'])) assert date == "${nixpkgs.lastModifiedDate}", "time mismatch" diff --git a/tests/impure-derivations.sh b/tests/impure-derivations.sh index 35ae3f5d3..7ca9ce742 100644 --- a/tests/impure-derivations.sh +++ b/tests/impure-derivations.sh @@ -2,7 +2,7 @@ source common.sh requireDaemonNewerThan "2.8pre20220311" -enableFeatures "ca-derivations ca-references impure-derivations" +enableFeatures "ca-derivations impure-derivations" restartDaemon set -o pipefail diff --git a/tests/lang/eval-okay-eq.exp b/tests/lang/eval-okay-eq.exp new file mode 100644 index 000000000..27ba77dda --- /dev/null +++ b/tests/lang/eval-okay-eq.exp @@ -0,0 +1 @@ +true diff --git a/tests/lang/eval-okay-eq.exp.disabled b/tests/lang/eval-okay-eq.exp.disabled deleted file mode 100644 index 2015847b6..000000000 --- a/tests/lang/eval-okay-eq.exp.disabled +++ /dev/null @@ -1 +0,0 @@ -Bool(True) diff --git a/tests/lang/eval-okay-versions.nix b/tests/lang/eval-okay-versions.nix index e63c36586..e9111f5f4 100644 --- a/tests/lang/eval-okay-versions.nix +++ b/tests/lang/eval-okay-versions.nix @@ -4,6 +4,7 @@ let name2 = "hello"; name3 = "915resolution-0.5.2"; name4 = "xf86-video-i810-1.7.4"; + name5 = "name-that-ends-with-dash--1.0"; eq = 0; lt = builtins.sub 0 1; @@ -23,6 +24,8 @@ let ((builtins.parseDrvName name3).version == "0.5.2") ((builtins.parseDrvName name4).name == "xf86-video-i810") ((builtins.parseDrvName name4).version == "1.7.4") + ((builtins.parseDrvName name5).name == "name-that-ends-with-dash") + ((builtins.parseDrvName name5).version == "-1.0") (versionTest "1.0" "2.3" lt) (versionTest "2.1" "2.3" lt) (versionTest "2.3" "2.3" eq) diff --git a/tests/local.mk b/tests/local.mk index 5e48ceae1..340817ec3 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -109,7 +109,8 @@ nix_tests = \ store-ping.sh \ fetchClosure.sh \ completions.sh \ - impure-derivations.sh + impure-derivations.sh \ + path-from-hash-part.sh ifeq ($(HAVE_LIBCPUID), 1) nix_tests += compute-levels.sh diff --git a/tests/path-from-hash-part.sh b/tests/path-from-hash-part.sh new file mode 100644 index 000000000..bdd104434 --- /dev/null +++ b/tests/path-from-hash-part.sh @@ -0,0 +1,10 @@ +source common.sh + +path=$(nix build --no-link --print-out-paths -f simple.nix) + +hash_part=$(basename $path) +hash_part=${hash_part:0:32} + +path2=$(nix store path-from-hash-part $hash_part) + +[[ $path = $path2 ]]