forked from lix-project/lix
Merge remote-tracking branch 'upstream/master' into fix-mv-in-different-filesystems
This commit is contained in:
commit
5192bb093a
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -22,7 +22,7 @@ perl/Makefile.config
|
||||||
/doc/manual/src/SUMMARY.md
|
/doc/manual/src/SUMMARY.md
|
||||||
/doc/manual/src/command-ref/new-cli
|
/doc/manual/src/command-ref/new-cli
|
||||||
/doc/manual/src/command-ref/conf-file.md
|
/doc/manual/src/command-ref/conf-file.md
|
||||||
/doc/manual/src/expressions/builtins.md
|
/doc/manual/src/language/builtins.md
|
||||||
|
|
||||||
# /scripts/
|
# /scripts/
|
||||||
/scripts/nix-profile.sh
|
/scripts/nix-profile.sh
|
||||||
|
|
|
@ -20,7 +20,7 @@ Information on additional installation methods is available on the [Nix download
|
||||||
|
|
||||||
## Building And Developing
|
## Building And Developing
|
||||||
|
|
||||||
See our [Hacking guide](https://hydra.nixos.org/job/nix/master/build.x86_64-linux/latest/download-by-type/doc/manual/contributing/hacking.html) in our manual for instruction on how to
|
See our [Hacking guide](https://nixos.org/manual/nix/stable/contributing/hacking.html) in our manual for instruction on how to
|
||||||
build nix from source with nix-build or how to get a development environment.
|
build nix from source with nix-build or how to get a development environment.
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
ifeq ($(doc_generate),yes)
|
ifeq ($(doc_generate),yes)
|
||||||
|
|
||||||
|
MANUAL_SRCS := \
|
||||||
|
$(call rwildcard, $(d)/src, *.md) \
|
||||||
|
$(call rwildcard, $(d)/src, */*.md)
|
||||||
|
|
||||||
# Generate man pages.
|
# Generate man pages.
|
||||||
man-pages := $(foreach n, \
|
man-pages := $(foreach n, \
|
||||||
nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
|
nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
|
||||||
|
@ -61,10 +65,10 @@ $(d)/conf-file.json: $(bindir)/nix
|
||||||
$(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp
|
$(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
$(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/expressions/builtins-prefix.md $(bindir)/nix
|
$(d)/src/language/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(bindir)/nix
|
||||||
@cat doc/manual/src/expressions/builtins-prefix.md > $@.tmp
|
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
||||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp
|
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp
|
||||||
@cat doc/manual/src/expressions/builtins-suffix.md >> $@.tmp
|
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
$(d)/builtins.json: $(bindir)/nix
|
$(d)/builtins.json: $(bindir)/nix
|
||||||
|
@ -97,7 +101,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli
|
||||||
done
|
done
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/command-ref/conf-file.md $(d)/src/expressions/builtins.md $(call rwildcard, $(d)/src, *.md)
|
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md
|
||||||
$(trace-gen) RUST_LOG=warn mdbook build doc/manual -d $(DESTDIR)$(docdir)/manual
|
$(trace-gen) RUST_LOG=warn mdbook build doc/manual -d $(DESTDIR)$(docdir)/manual
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -132,113 +132,106 @@ var redirects = {
|
||||||
"#sec-common-options": "command-ref/opt-common.html",
|
"#sec-common-options": "command-ref/opt-common.html",
|
||||||
"#ch-utilities": "command-ref/utilities.html",
|
"#ch-utilities": "command-ref/utilities.html",
|
||||||
"#chap-hacking": "contributing/hacking.html",
|
"#chap-hacking": "contributing/hacking.html",
|
||||||
"#adv-attr-allowSubstitutes": "expressions/advanced-attributes.html#adv-attr-allowSubstitutes",
|
"#adv-attr-allowSubstitutes": "language/advanced-attributes.html#adv-attr-allowSubstitutes",
|
||||||
"#adv-attr-allowedReferences": "expressions/advanced-attributes.html#adv-attr-allowedReferences",
|
"#adv-attr-allowedReferences": "language/advanced-attributes.html#adv-attr-allowedReferences",
|
||||||
"#adv-attr-allowedRequisites": "expressions/advanced-attributes.html#adv-attr-allowedRequisites",
|
"#adv-attr-allowedRequisites": "language/advanced-attributes.html#adv-attr-allowedRequisites",
|
||||||
"#adv-attr-disallowedReferences": "expressions/advanced-attributes.html#adv-attr-disallowedReferences",
|
"#adv-attr-disallowedReferences": "language/advanced-attributes.html#adv-attr-disallowedReferences",
|
||||||
"#adv-attr-disallowedRequisites": "expressions/advanced-attributes.html#adv-attr-disallowedRequisites",
|
"#adv-attr-disallowedRequisites": "language/advanced-attributes.html#adv-attr-disallowedRequisites",
|
||||||
"#adv-attr-exportReferencesGraph": "expressions/advanced-attributes.html#adv-attr-exportReferencesGraph",
|
"#adv-attr-exportReferencesGraph": "language/advanced-attributes.html#adv-attr-exportReferencesGraph",
|
||||||
"#adv-attr-impureEnvVars": "expressions/advanced-attributes.html#adv-attr-impureEnvVars",
|
"#adv-attr-impureEnvVars": "language/advanced-attributes.html#adv-attr-impureEnvVars",
|
||||||
"#adv-attr-outputHash": "expressions/advanced-attributes.html#adv-attr-outputHash",
|
"#adv-attr-outputHash": "language/advanced-attributes.html#adv-attr-outputHash",
|
||||||
"#adv-attr-outputHashAlgo": "expressions/advanced-attributes.html#adv-attr-outputHashAlgo",
|
"#adv-attr-outputHashAlgo": "language/advanced-attributes.html#adv-attr-outputHashAlgo",
|
||||||
"#adv-attr-outputHashMode": "expressions/advanced-attributes.html#adv-attr-outputHashMode",
|
"#adv-attr-outputHashMode": "language/advanced-attributes.html#adv-attr-outputHashMode",
|
||||||
"#adv-attr-passAsFile": "expressions/advanced-attributes.html#adv-attr-passAsFile",
|
"#adv-attr-passAsFile": "language/advanced-attributes.html#adv-attr-passAsFile",
|
||||||
"#adv-attr-preferLocalBuild": "expressions/advanced-attributes.html#adv-attr-preferLocalBuild",
|
"#adv-attr-preferLocalBuild": "language/advanced-attributes.html#adv-attr-preferLocalBuild",
|
||||||
"#fixed-output-drvs": "expressions/advanced-attributes.html#adv-attr-outputHash",
|
"#fixed-output-drvs": "language/advanced-attributes.html#adv-attr-outputHash",
|
||||||
"#sec-advanced-attributes": "expressions/advanced-attributes.html",
|
"#sec-advanced-attributes": "language/advanced-attributes.html",
|
||||||
"#sec-arguments": "expressions/arguments-variables.html",
|
"#builtin-abort": "language/builtins.html#builtins-abort",
|
||||||
"#sec-build-script": "expressions/build-script.html",
|
"#builtin-add": "language/builtins.html#builtins-add",
|
||||||
"#builtin-abort": "expressions/builtins.html#builtins-abort",
|
"#builtin-all": "language/builtins.html#builtins-all",
|
||||||
"#builtin-add": "expressions/builtins.html#builtins-add",
|
"#builtin-any": "language/builtins.html#builtins-any",
|
||||||
"#builtin-all": "expressions/builtins.html#builtins-all",
|
"#builtin-attrNames": "language/builtins.html#builtins-attrNames",
|
||||||
"#builtin-any": "expressions/builtins.html#builtins-any",
|
"#builtin-attrValues": "language/builtins.html#builtins-attrValues",
|
||||||
"#builtin-attrNames": "expressions/builtins.html#builtins-attrNames",
|
"#builtin-baseNameOf": "language/builtins.html#builtins-baseNameOf",
|
||||||
"#builtin-attrValues": "expressions/builtins.html#builtins-attrValues",
|
"#builtin-bitAnd": "language/builtins.html#builtins-bitAnd",
|
||||||
"#builtin-baseNameOf": "expressions/builtins.html#builtins-baseNameOf",
|
"#builtin-bitOr": "language/builtins.html#builtins-bitOr",
|
||||||
"#builtin-bitAnd": "expressions/builtins.html#builtins-bitAnd",
|
"#builtin-bitXor": "language/builtins.html#builtins-bitXor",
|
||||||
"#builtin-bitOr": "expressions/builtins.html#builtins-bitOr",
|
"#builtin-builtins": "language/builtins.html#builtins-builtins",
|
||||||
"#builtin-bitXor": "expressions/builtins.html#builtins-bitXor",
|
"#builtin-compareVersions": "language/builtins.html#builtins-compareVersions",
|
||||||
"#builtin-builtins": "expressions/builtins.html#builtins-builtins",
|
"#builtin-concatLists": "language/builtins.html#builtins-concatLists",
|
||||||
"#builtin-compareVersions": "expressions/builtins.html#builtins-compareVersions",
|
"#builtin-concatStringsSep": "language/builtins.html#builtins-concatStringsSep",
|
||||||
"#builtin-concatLists": "expressions/builtins.html#builtins-concatLists",
|
"#builtin-currentSystem": "language/builtins.html#builtins-currentSystem",
|
||||||
"#builtin-concatStringsSep": "expressions/builtins.html#builtins-concatStringsSep",
|
"#builtin-deepSeq": "language/builtins.html#builtins-deepSeq",
|
||||||
"#builtin-currentSystem": "expressions/builtins.html#builtins-currentSystem",
|
"#builtin-derivation": "language/builtins.html#builtins-derivation",
|
||||||
"#builtin-deepSeq": "expressions/builtins.html#builtins-deepSeq",
|
"#builtin-dirOf": "language/builtins.html#builtins-dirOf",
|
||||||
"#builtin-derivation": "expressions/builtins.html#builtins-derivation",
|
"#builtin-div": "language/builtins.html#builtins-div",
|
||||||
"#builtin-dirOf": "expressions/builtins.html#builtins-dirOf",
|
"#builtin-elem": "language/builtins.html#builtins-elem",
|
||||||
"#builtin-div": "expressions/builtins.html#builtins-div",
|
"#builtin-elemAt": "language/builtins.html#builtins-elemAt",
|
||||||
"#builtin-elem": "expressions/builtins.html#builtins-elem",
|
"#builtin-fetchGit": "language/builtins.html#builtins-fetchGit",
|
||||||
"#builtin-elemAt": "expressions/builtins.html#builtins-elemAt",
|
"#builtin-fetchTarball": "language/builtins.html#builtins-fetchTarball",
|
||||||
"#builtin-fetchGit": "expressions/builtins.html#builtins-fetchGit",
|
"#builtin-fetchurl": "language/builtins.html#builtins-fetchurl",
|
||||||
"#builtin-fetchTarball": "expressions/builtins.html#builtins-fetchTarball",
|
"#builtin-filterSource": "language/builtins.html#builtins-filterSource",
|
||||||
"#builtin-fetchurl": "expressions/builtins.html#builtins-fetchurl",
|
"#builtin-foldl-prime": "language/builtins.html#builtins-foldl-prime",
|
||||||
"#builtin-filterSource": "expressions/builtins.html#builtins-filterSource",
|
"#builtin-fromJSON": "language/builtins.html#builtins-fromJSON",
|
||||||
"#builtin-foldl-prime": "expressions/builtins.html#builtins-foldl-prime",
|
"#builtin-functionArgs": "language/builtins.html#builtins-functionArgs",
|
||||||
"#builtin-fromJSON": "expressions/builtins.html#builtins-fromJSON",
|
"#builtin-genList": "language/builtins.html#builtins-genList",
|
||||||
"#builtin-functionArgs": "expressions/builtins.html#builtins-functionArgs",
|
"#builtin-getAttr": "language/builtins.html#builtins-getAttr",
|
||||||
"#builtin-genList": "expressions/builtins.html#builtins-genList",
|
"#builtin-getEnv": "language/builtins.html#builtins-getEnv",
|
||||||
"#builtin-getAttr": "expressions/builtins.html#builtins-getAttr",
|
"#builtin-hasAttr": "language/builtins.html#builtins-hasAttr",
|
||||||
"#builtin-getEnv": "expressions/builtins.html#builtins-getEnv",
|
"#builtin-hashFile": "language/builtins.html#builtins-hashFile",
|
||||||
"#builtin-hasAttr": "expressions/builtins.html#builtins-hasAttr",
|
"#builtin-hashString": "language/builtins.html#builtins-hashString",
|
||||||
"#builtin-hashFile": "expressions/builtins.html#builtins-hashFile",
|
"#builtin-head": "language/builtins.html#builtins-head",
|
||||||
"#builtin-hashString": "expressions/builtins.html#builtins-hashString",
|
"#builtin-import": "language/builtins.html#builtins-import",
|
||||||
"#builtin-head": "expressions/builtins.html#builtins-head",
|
"#builtin-intersectAttrs": "language/builtins.html#builtins-intersectAttrs",
|
||||||
"#builtin-import": "expressions/builtins.html#builtins-import",
|
"#builtin-isAttrs": "language/builtins.html#builtins-isAttrs",
|
||||||
"#builtin-intersectAttrs": "expressions/builtins.html#builtins-intersectAttrs",
|
"#builtin-isBool": "language/builtins.html#builtins-isBool",
|
||||||
"#builtin-isAttrs": "expressions/builtins.html#builtins-isAttrs",
|
"#builtin-isFloat": "language/builtins.html#builtins-isFloat",
|
||||||
"#builtin-isBool": "expressions/builtins.html#builtins-isBool",
|
"#builtin-isFunction": "language/builtins.html#builtins-isFunction",
|
||||||
"#builtin-isFloat": "expressions/builtins.html#builtins-isFloat",
|
"#builtin-isInt": "language/builtins.html#builtins-isInt",
|
||||||
"#builtin-isFunction": "expressions/builtins.html#builtins-isFunction",
|
"#builtin-isList": "language/builtins.html#builtins-isList",
|
||||||
"#builtin-isInt": "expressions/builtins.html#builtins-isInt",
|
"#builtin-isNull": "language/builtins.html#builtins-isNull",
|
||||||
"#builtin-isList": "expressions/builtins.html#builtins-isList",
|
"#builtin-isString": "language/builtins.html#builtins-isString",
|
||||||
"#builtin-isNull": "expressions/builtins.html#builtins-isNull",
|
"#builtin-length": "language/builtins.html#builtins-length",
|
||||||
"#builtin-isString": "expressions/builtins.html#builtins-isString",
|
"#builtin-lessThan": "language/builtins.html#builtins-lessThan",
|
||||||
"#builtin-length": "expressions/builtins.html#builtins-length",
|
"#builtin-listToAttrs": "language/builtins.html#builtins-listToAttrs",
|
||||||
"#builtin-lessThan": "expressions/builtins.html#builtins-lessThan",
|
"#builtin-map": "language/builtins.html#builtins-map",
|
||||||
"#builtin-listToAttrs": "expressions/builtins.html#builtins-listToAttrs",
|
"#builtin-match": "language/builtins.html#builtins-match",
|
||||||
"#builtin-map": "expressions/builtins.html#builtins-map",
|
"#builtin-mul": "language/builtins.html#builtins-mul",
|
||||||
"#builtin-match": "expressions/builtins.html#builtins-match",
|
"#builtin-parseDrvName": "language/builtins.html#builtins-parseDrvName",
|
||||||
"#builtin-mul": "expressions/builtins.html#builtins-mul",
|
"#builtin-path": "language/builtins.html#builtins-path",
|
||||||
"#builtin-parseDrvName": "expressions/builtins.html#builtins-parseDrvName",
|
"#builtin-pathExists": "language/builtins.html#builtins-pathExists",
|
||||||
"#builtin-path": "expressions/builtins.html#builtins-path",
|
"#builtin-placeholder": "language/builtins.html#builtins-placeholder",
|
||||||
"#builtin-pathExists": "expressions/builtins.html#builtins-pathExists",
|
"#builtin-readDir": "language/builtins.html#builtins-readDir",
|
||||||
"#builtin-placeholder": "expressions/builtins.html#builtins-placeholder",
|
"#builtin-readFile": "language/builtins.html#builtins-readFile",
|
||||||
"#builtin-readDir": "expressions/builtins.html#builtins-readDir",
|
"#builtin-removeAttrs": "language/builtins.html#builtins-removeAttrs",
|
||||||
"#builtin-readFile": "expressions/builtins.html#builtins-readFile",
|
"#builtin-replaceStrings": "language/builtins.html#builtins-replaceStrings",
|
||||||
"#builtin-removeAttrs": "expressions/builtins.html#builtins-removeAttrs",
|
"#builtin-seq": "language/builtins.html#builtins-seq",
|
||||||
"#builtin-replaceStrings": "expressions/builtins.html#builtins-replaceStrings",
|
"#builtin-sort": "language/builtins.html#builtins-sort",
|
||||||
"#builtin-seq": "expressions/builtins.html#builtins-seq",
|
"#builtin-split": "language/builtins.html#builtins-split",
|
||||||
"#builtin-sort": "expressions/builtins.html#builtins-sort",
|
"#builtin-splitVersion": "language/builtins.html#builtins-splitVersion",
|
||||||
"#builtin-split": "expressions/builtins.html#builtins-split",
|
"#builtin-stringLength": "language/builtins.html#builtins-stringLength",
|
||||||
"#builtin-splitVersion": "expressions/builtins.html#builtins-splitVersion",
|
"#builtin-sub": "language/builtins.html#builtins-sub",
|
||||||
"#builtin-stringLength": "expressions/builtins.html#builtins-stringLength",
|
"#builtin-substring": "language/builtins.html#builtins-substring",
|
||||||
"#builtin-sub": "expressions/builtins.html#builtins-sub",
|
"#builtin-tail": "language/builtins.html#builtins-tail",
|
||||||
"#builtin-substring": "expressions/builtins.html#builtins-substring",
|
"#builtin-throw": "language/builtins.html#builtins-throw",
|
||||||
"#builtin-tail": "expressions/builtins.html#builtins-tail",
|
"#builtin-toFile": "language/builtins.html#builtins-toFile",
|
||||||
"#builtin-throw": "expressions/builtins.html#builtins-throw",
|
"#builtin-toJSON": "language/builtins.html#builtins-toJSON",
|
||||||
"#builtin-toFile": "expressions/builtins.html#builtins-toFile",
|
"#builtin-toPath": "language/builtins.html#builtins-toPath",
|
||||||
"#builtin-toJSON": "expressions/builtins.html#builtins-toJSON",
|
"#builtin-toString": "language/builtins.html#builtins-toString",
|
||||||
"#builtin-toPath": "expressions/builtins.html#builtins-toPath",
|
"#builtin-toXML": "language/builtins.html#builtins-toXML",
|
||||||
"#builtin-toString": "expressions/builtins.html#builtins-toString",
|
"#builtin-trace": "language/builtins.html#builtins-trace",
|
||||||
"#builtin-toXML": "expressions/builtins.html#builtins-toXML",
|
"#builtin-tryEval": "language/builtins.html#builtins-tryEval",
|
||||||
"#builtin-trace": "expressions/builtins.html#builtins-trace",
|
"#builtin-typeOf": "language/builtins.html#builtins-typeOf",
|
||||||
"#builtin-tryEval": "expressions/builtins.html#builtins-tryEval",
|
"#ssec-builtins": "language/builtins.html",
|
||||||
"#builtin-typeOf": "expressions/builtins.html#builtins-typeOf",
|
"#attr-system": "language/derivations.html#attr-system",
|
||||||
"#ssec-builtins": "expressions/builtins.html",
|
"#ssec-derivation": "language/derivations.html",
|
||||||
"#attr-system": "expressions/derivations.html#attr-system",
|
"#ch-expression-language": "language/index.html",
|
||||||
"#ssec-derivation": "expressions/derivations.html",
|
"#sec-constructs": "language/constructs.html",
|
||||||
"#ch-expression-language": "expressions/expression-language.html",
|
"#sect-let-language": "language/constructs.html#let-language",
|
||||||
"#sec-expression-syntax": "expressions/expression-syntax.html",
|
"#ss-functions": "language/constructs.html#functions",
|
||||||
"#sec-generic-builder": "expressions/generic-builder.html",
|
"#sec-language-operators": "language/operators.html",
|
||||||
"#sec-constructs": "expressions/language-constructs.html",
|
"#table-operators": "language/operators.html",
|
||||||
"#sect-let-expressions": "expressions/language-constructs.html#let-expressions",
|
"#ssec-values": "language/values.html",
|
||||||
"#ss-functions": "expressions/language-constructs.html#functions",
|
|
||||||
"#sec-language-operators": "expressions/language-operators.html",
|
|
||||||
"#table-operators": "expressions/language-operators.html",
|
|
||||||
"#ssec-values": "expressions/language-values.html",
|
|
||||||
"#sec-building-simple": "expressions/simple-building-testing.html",
|
|
||||||
"#ch-simple-expression": "expressions/simple-expression.html",
|
|
||||||
"#chap-writing-nix-expressions": "expressions/writing-nix-expressions.html",
|
|
||||||
"#gloss-closure": "glossary.html#gloss-closure",
|
"#gloss-closure": "glossary.html#gloss-closure",
|
||||||
"#gloss-derivation": "glossary.html#gloss-derivation",
|
"#gloss-derivation": "glossary.html#gloss-derivation",
|
||||||
"#gloss-deriver": "glossary.html#gloss-deriver",
|
"#gloss-deriver": "glossary.html#gloss-deriver",
|
||||||
|
|
|
@ -26,21 +26,14 @@
|
||||||
- [Copying Closures via SSH](package-management/copy-closure.md)
|
- [Copying Closures via SSH](package-management/copy-closure.md)
|
||||||
- [Serving a Nix store via SSH](package-management/ssh-substituter.md)
|
- [Serving a Nix store via SSH](package-management/ssh-substituter.md)
|
||||||
- [Serving a Nix store via S3](package-management/s3-substituter.md)
|
- [Serving a Nix store via S3](package-management/s3-substituter.md)
|
||||||
- [Writing Nix Expressions](expressions/writing-nix-expressions.md)
|
- [Nix Language](language/index.md)
|
||||||
- [A Simple Nix Expression](expressions/simple-expression.md)
|
- [Data Types](language/values.md)
|
||||||
- [Expression Syntax](expressions/expression-syntax.md)
|
- [Language Constructs](language/constructs.md)
|
||||||
- [Build Script](expressions/build-script.md)
|
- [Operators](language/operators.md)
|
||||||
- [Arguments and Variables](expressions/arguments-variables.md)
|
- [Derivations](language/derivations.md)
|
||||||
- [Building and Testing](expressions/simple-building-testing.md)
|
- [Advanced Attributes](language/advanced-attributes.md)
|
||||||
- [Generic Builder Syntax](expressions/generic-builder.md)
|
- [Built-in Constants](language/builtin-constants.md)
|
||||||
- [Nix Expression Language](expressions/expression-language.md)
|
- [Built-in Functions](language/builtins.md)
|
||||||
- [Values](expressions/language-values.md)
|
|
||||||
- [Language Constructs](expressions/language-constructs.md)
|
|
||||||
- [Operators](expressions/language-operators.md)
|
|
||||||
- [Derivations](expressions/derivations.md)
|
|
||||||
- [Advanced Attributes](expressions/advanced-attributes.md)
|
|
||||||
- [Built-in Constants](expressions/builtin-constants.md)
|
|
||||||
- [Built-in Functions](expressions/builtins.md)
|
|
||||||
- [Advanced Topics](advanced-topics/advanced-topics.md)
|
- [Advanced Topics](advanced-topics/advanced-topics.md)
|
||||||
- [Remote Builds](advanced-topics/distributed-builds.md)
|
- [Remote Builds](advanced-topics/distributed-builds.md)
|
||||||
- [Tuning Cores and Jobs](advanced-topics/cores-vs-jobs.md)
|
- [Tuning Cores and Jobs](advanced-topics/cores-vs-jobs.md)
|
||||||
|
@ -66,6 +59,14 @@
|
||||||
@manpages@
|
@manpages@
|
||||||
- [Files](command-ref/files.md)
|
- [Files](command-ref/files.md)
|
||||||
- [nix.conf](command-ref/conf-file.md)
|
- [nix.conf](command-ref/conf-file.md)
|
||||||
|
<!--
|
||||||
|
- [Architecture](architecture/architecture.md)
|
||||||
|
- [Store](architecture/store/store.md)
|
||||||
|
- [Closure](architecture/store/store/closure.md)
|
||||||
|
- [Build system terminology](architecture/store/store/build-system-terminology.md)
|
||||||
|
- [Store Path](architecture/store/path.md)
|
||||||
|
- [File System Object](architecture/store/fso.md)
|
||||||
|
-->
|
||||||
- [Glossary](glossary.md)
|
- [Glossary](glossary.md)
|
||||||
- [Contributing](contributing/contributing.md)
|
- [Contributing](contributing/contributing.md)
|
||||||
- [Hacking](contributing/hacking.md)
|
- [Hacking](contributing/hacking.md)
|
||||||
|
|
79
doc/manual/src/architecture/architecture.md
Normal file
79
doc/manual/src/architecture/architecture.md
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# Architecture
|
||||||
|
|
||||||
|
*(This chapter is unstable and a work in progress. Incoming links may rot.)*
|
||||||
|
|
||||||
|
This chapter describes how Nix works.
|
||||||
|
It should help users understand why Nix behaves as it does, and it should help developers understand how to modify Nix and how to write similar tools.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Nix consists of [hierarchical layers][layer-architecture].
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
| Nix |
|
||||||
|
| [ commmand line interface ]------, |
|
||||||
|
| | | |
|
||||||
|
| evaluates | |
|
||||||
|
| | manages |
|
||||||
|
| V | |
|
||||||
|
| [ configuration language ] | |
|
||||||
|
| | | |
|
||||||
|
| +-----------------------------|-------------------V-----------+ |
|
||||||
|
| | store evaluates to | |
|
||||||
|
| | | | |
|
||||||
|
| | referenced by V builds | |
|
||||||
|
| | [ build input ] ---> [ build plan ] ---> [ build result ] | |
|
||||||
|
| | | |
|
||||||
|
| +-------------------------------------------------------------+ |
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
At the top is the [command line interface](../command-ref/command-ref.md), translating from invocations of Nix executables to interactions with the underlying layers.
|
||||||
|
|
||||||
|
Below that is the [Nix expression language](../expressions/expression-language.md), a [purely functional][purely-functional-programming] configuration language.
|
||||||
|
It is used to compose expressions which ultimately evaluate to self-contained *build plans*, used to derive *build results* from referenced *build inputs*.
|
||||||
|
|
||||||
|
The command line and Nix language are what users interact with most.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> The Nix language itself does not have a notion of *packages* or *configurations*.
|
||||||
|
> As far as we are concerned here, the inputs and results of a build plan are just data.
|
||||||
|
|
||||||
|
Underlying these is the [Nix store](./store/store.md), a mechanism to keep track of build plans, data, and references between them.
|
||||||
|
It can also execute build plans to produce new data.
|
||||||
|
|
||||||
|
A build plan is a series of *build tasks*.
|
||||||
|
Each build task has a special build input which is used as *build instructions*.
|
||||||
|
The result of a build task can be input to another build task.
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----------------------------------------------------------------------------------------+
|
||||||
|
| store |
|
||||||
|
| ................................................. |
|
||||||
|
| : build plan : |
|
||||||
|
| : : |
|
||||||
|
| [ build input ]-----instructions-, : |
|
||||||
|
| : | : |
|
||||||
|
| : v : |
|
||||||
|
| [ build input ]----------->[ build task ]--instructions-, : |
|
||||||
|
| : | : |
|
||||||
|
| : | : |
|
||||||
|
| : v : |
|
||||||
|
| : [ build task ]----->[ build result ] |
|
||||||
|
| [ build input ]-----instructions-, ^ : |
|
||||||
|
| : | | : |
|
||||||
|
| : v | : |
|
||||||
|
| [ build input ]----------->[ build task ]---------------' : |
|
||||||
|
| : ^ : |
|
||||||
|
| : | : |
|
||||||
|
| [ build input ]------------------' : |
|
||||||
|
| : : |
|
||||||
|
| : : |
|
||||||
|
| :...............................................: |
|
||||||
|
| |
|
||||||
|
+-----------------------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
[layer-architecture]: https://en.m.wikipedia.org/wiki/Multitier_architecture#Layers
|
||||||
|
[purely-functional-programming]: https://en.m.wikipedia.org/wiki/Purely_functional_programming
|
69
doc/manual/src/architecture/store/fso.md
Normal file
69
doc/manual/src/architecture/store/fso.md
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
# File System Object
|
||||||
|
|
||||||
|
The Nix store uses a simple file system model for the data it holds in [store objects](store.md#store-object).
|
||||||
|
|
||||||
|
Every file system object is one of the following:
|
||||||
|
|
||||||
|
- File: an executable flag, and arbitrary data for contents
|
||||||
|
- Directory: mapping of names to child file system objects
|
||||||
|
- [Symbolic link][symlink]: may point anywhere.
|
||||||
|
|
||||||
|
We call a store object's outermost file system object the *root*.
|
||||||
|
|
||||||
|
data FileSystemObject
|
||||||
|
= File { isExecutable :: Bool, contents :: Bytes }
|
||||||
|
| Directory { entries :: Map FileName FileSystemObject }
|
||||||
|
| SymLink { target :: Path }
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- a directory with contents
|
||||||
|
|
||||||
|
/nix/store/<hash>-hello-2.10
|
||||||
|
├── bin
|
||||||
|
│ └── hello
|
||||||
|
└── share
|
||||||
|
├── info
|
||||||
|
│ └── hello.info
|
||||||
|
└── man
|
||||||
|
└── man1
|
||||||
|
└── hello.1.gz
|
||||||
|
|
||||||
|
- a directory with relative symlink and other contents
|
||||||
|
|
||||||
|
/nix/store/<hash>-go-1.16.9
|
||||||
|
├── bin -> share/go/bin
|
||||||
|
├── nix-support/
|
||||||
|
└── share/
|
||||||
|
|
||||||
|
- a directory with absolute symlink
|
||||||
|
|
||||||
|
/nix/store/d3k...-nodejs
|
||||||
|
└── nix_node -> /nix/store/f20...-nodejs-10.24.
|
||||||
|
|
||||||
|
A bare file or symlink can be a root file system object.
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
/nix/store/<hash>-hello-2.10.tar.gz
|
||||||
|
|
||||||
|
/nix/store/4j5...-pkg-config-wrapper-0.29.2-doc -> /nix/store/i99...-pkg-config-0.29.2-doc
|
||||||
|
|
||||||
|
Symlinks pointing outside of their own root or to a store object without a matching reference are allowed, but might not function as intended.
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- an arbitrarily symlinked file may change or not exist at all
|
||||||
|
|
||||||
|
/nix/store/<hash>-foo
|
||||||
|
└── foo -> /home/foo
|
||||||
|
|
||||||
|
- if a symlink to a store path was not automatically created by Nix, it may be invalid or get invalidated when the store object is deleted
|
||||||
|
|
||||||
|
/nix/store/<hash>-bar
|
||||||
|
└── bar -> /nix/store/abc...-foo
|
||||||
|
|
||||||
|
Nix file system objects do not support [hard links][hardlink]:
|
||||||
|
each file system object which is not the root has exactly one parent and one name.
|
||||||
|
However, as store objects are immutable, an underlying file system can use hard links for optimization.
|
||||||
|
|
||||||
|
[symlink]: https://en.m.wikipedia.org/wiki/Symbolic_link
|
||||||
|
[hardlink]: https://en.m.wikipedia.org/wiki/Hard_link
|
105
doc/manual/src/architecture/store/path.md
Normal file
105
doc/manual/src/architecture/store/path.md
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
# Store Path
|
||||||
|
|
||||||
|
Nix implements [references](store.md#reference) to [store objects](store.md#store-object) as *store paths*.
|
||||||
|
|
||||||
|
Store paths are pairs of
|
||||||
|
|
||||||
|
- a 20-byte [digest](#digest) for identification
|
||||||
|
- a symbolic name for people to read.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
- digest: `b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z`
|
||||||
|
- name: `firefox-33.1`
|
||||||
|
|
||||||
|
It is rendered to a file system path as the concatenation of
|
||||||
|
|
||||||
|
- [store directory](#store-directory)
|
||||||
|
- path-separator (`/`)
|
||||||
|
- [digest](#digest) rendered in a custom variant of [base-32](https://en.m.wikipedia.org/wiki/Base32) (20 arbitrary bytes become 32 ASCII characters)
|
||||||
|
- hyphen (`-`)
|
||||||
|
- name
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
/nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1
|
||||||
|
|--------| |------------------------------| |----------|
|
||||||
|
store directory digest name
|
||||||
|
|
||||||
|
## Store Directory
|
||||||
|
|
||||||
|
Every [store](./store.md) has a store directory.
|
||||||
|
|
||||||
|
If the store has a [file system representation](./store.md#files-and-processes), this directory contains the store’s [file system objects](#file-system-object), which can be addressed by [store paths](#store-path).
|
||||||
|
|
||||||
|
This means a store path is not just derived from the referenced store object itself, but depends on the store the store object is in.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> The store directory defaults to `/nix/store`, but is in principle arbitrary.
|
||||||
|
|
||||||
|
It is important which store a given store object belongs to:
|
||||||
|
Files in the store object can contain store paths, and processes may read these paths.
|
||||||
|
Nix can only guarantee [referential integrity](store/closure.md) if store paths do not cross store boundaries.
|
||||||
|
|
||||||
|
Therefore one can only copy store objects to a different store if
|
||||||
|
|
||||||
|
- the source and target stores' directories match
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
- the store object in question has no references, that is, contains no store paths.
|
||||||
|
|
||||||
|
One cannot copy a store object to a store with a different store directory.
|
||||||
|
Instead, it has to be rebuilt, together with all its dependencies.
|
||||||
|
It is in general not enough to replace the store directory string in file contents, as this may render executables unusable by invalidating their internal offsets or checksums.
|
||||||
|
|
||||||
|
# Digest
|
||||||
|
|
||||||
|
In a [store path](#store-path), the [digest][digest] is the output of a [cryptographic hash function][hash] of either all *inputs* involved in building the referenced store object or its actual *contents*.
|
||||||
|
|
||||||
|
Store objects are therefore said to be either [input-addressed](#input-addressing) or [content-addressed](#content-addressing).
|
||||||
|
|
||||||
|
> **Historical Note**
|
||||||
|
> The 20 byte restriction is because originally digests were [SHA-1][sha-1] hashes.
|
||||||
|
> Nix now uses [SHA-256][sha-256], and longer hashes are still reduced to 20 bytes for compatibility.
|
||||||
|
|
||||||
|
[digest]: https://en.m.wiktionary.org/wiki/digest#Noun
|
||||||
|
[hash]: https://en.m.wikipedia.org/wiki/Cryptographic_hash_function
|
||||||
|
[sha-1]: https://en.m.wikipedia.org/wiki/SHA-1
|
||||||
|
[sha-256]: https://en.m.wikipedia.org/wiki/SHA-256
|
||||||
|
|
||||||
|
### Reference scanning
|
||||||
|
|
||||||
|
When a new store object is built, Nix scans its file contents for store paths to construct its set of references.
|
||||||
|
|
||||||
|
The special format of a store path's [digest](#digest) allows reliably detecting it among arbitrary data.
|
||||||
|
Nix uses the [closure](store.md#closure) of build inputs to derive the list of allowed store paths, to avoid false positives.
|
||||||
|
|
||||||
|
This way, scanning files captures run time dependencies without the user having to declare them explicitly.
|
||||||
|
Doing it at build time and persisting references in the store object avoids repeating this time-consuming operation.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> In practice, it is sometimes still necessary for users to declare certain dependencies explicitly, if they are to be preserved in the build result's closure.
|
||||||
|
This depends on the specifics of the software to build and run.
|
||||||
|
>
|
||||||
|
> For example, Java programs are compressed after compilation, which obfuscates any store paths they may refer to and prevents Nix from automatically detecting them.
|
||||||
|
|
||||||
|
## Input Addressing
|
||||||
|
|
||||||
|
Input addressing means that the digest derives from how the store object was produced, namely its build inputs and build plan.
|
||||||
|
|
||||||
|
To compute the hash of a store object one needs a deterministic serialisation, i.e., a binary string representation which only changes if the store object changes.
|
||||||
|
|
||||||
|
Nix has a custom serialisation format called Nix Archive (NAR)
|
||||||
|
|
||||||
|
Store object references of this sort can *not* be validated from the content of the store object.
|
||||||
|
Rather, a cryptographic signature has to be used to indicate that someone is vouching for the store object really being produced from a build plan with that digest.
|
||||||
|
|
||||||
|
## Content Addressing
|
||||||
|
|
||||||
|
Content addressing means that the digest derives from the store object's contents, namely its file system objects and references.
|
||||||
|
If one knows content addressing was used, one can recalculate the reference and thus verify the store object.
|
||||||
|
|
||||||
|
Content addressing is currently only used for the special cases of source files and "fixed-output derivations", where the contents of a store object are known in advance.
|
||||||
|
Content addressing of build results is still an [experimental feature subject to some restrictions](https://github.com/tweag/rfcs/blob/cas-rfc/rfcs/0062-content-addressed-paths.md).
|
||||||
|
|
151
doc/manual/src/architecture/store/store.md
Normal file
151
doc/manual/src/architecture/store/store.md
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
# Store
|
||||||
|
|
||||||
|
A Nix store is a collection of *store objects* with references between them.
|
||||||
|
It supports operations to manipulate that collection.
|
||||||
|
|
||||||
|
The following concept map is a graphical outline of this chapter.
|
||||||
|
Arrows indicate suggested reading order.
|
||||||
|
|
||||||
|
```
|
||||||
|
,--------------[ store ]----------------,
|
||||||
|
| | |
|
||||||
|
v v v
|
||||||
|
[ store object ] [ closure ]--, [ operations ]
|
||||||
|
| | | | | |
|
||||||
|
v | | v v |
|
||||||
|
[ files and processes ] | | [ garbage collection ] |
|
||||||
|
/ \ | | |
|
||||||
|
v v | v v
|
||||||
|
[ file system object ] [ store path ] | [ derivation ]--->[ building ]
|
||||||
|
| ^ | | |
|
||||||
|
v | v v |
|
||||||
|
[ digest ]----' [ reference scanning ]<------------'
|
||||||
|
/ \
|
||||||
|
v v
|
||||||
|
[ input addressing ] [ content addressing ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Store Object
|
||||||
|
|
||||||
|
A store object can hold
|
||||||
|
|
||||||
|
- arbitrary *data*
|
||||||
|
- *references* to other store objects.
|
||||||
|
|
||||||
|
Store objects can be build inputs, build results, or build tasks.
|
||||||
|
|
||||||
|
Store objects are [immutable][immutable-object]: once created, they do not change until they are deleted.
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
A store object reference is an [opaque][opaque-data-type], [unique identifier][unique-identifier]:
|
||||||
|
The only way to obtain references is by adding or building store objects.
|
||||||
|
A reference will always point to exactly one store object.
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
A Nix store can *add*, *retrieve*, and *delete* store objects.
|
||||||
|
|
||||||
|
[ data ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ store ] ---> add ----> [ store' ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ reference ]
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
[ reference ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ store ] ---> get
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ store object ]
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
[ reference ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ store ] --> delete --> [ store' ]
|
||||||
|
|
||||||
|
|
||||||
|
It can *perform builds*, that is, create new store objects by transforming build inputs into build outputs, using instructions from the build tasks.
|
||||||
|
|
||||||
|
|
||||||
|
[ reference ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ store ] --> build --(maybe)--> [ store' ]
|
||||||
|
|
|
||||||
|
V
|
||||||
|
[ reference ]
|
||||||
|
|
||||||
|
|
||||||
|
As it keeps track of references, it can [garbage-collect][garbage-collection] unused store objects.
|
||||||
|
|
||||||
|
|
||||||
|
[ store ] --> collect garbage --> [ store' ]
|
||||||
|
|
||||||
|
## Files and Processes
|
||||||
|
|
||||||
|
Nix maps between its store model and the [Unix paradigm][unix-paradigm] of [files and processes][file-descriptor], by encoding immutable store objects and opaque identifiers as file system primitives: files and directories, and paths.
|
||||||
|
That allows processes to resolve references contained in files and thus access the contents of store objects.
|
||||||
|
|
||||||
|
Store objects are therefore implemented as the pair of
|
||||||
|
|
||||||
|
- a [file system object](fso.md) for data
|
||||||
|
- a set of [store paths](path.md) for references.
|
||||||
|
|
||||||
|
[unix-paradigm]: https://en.m.wikipedia.org/wiki/Everything_is_a_file
|
||||||
|
[file-descriptor]: https://en.m.wikipedia.org/wiki/File_descriptor
|
||||||
|
|
||||||
|
The following diagram shows a radical simplification of how Nix interacts with the operating system:
|
||||||
|
It uses files as build inputs, and build outputs are files again.
|
||||||
|
On the operating system, files can be run as processes, which in turn operate on files.
|
||||||
|
A build function also amounts to an operating system process (not depicted).
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
| Nix |
|
||||||
|
| [ commmand line interface ]------, |
|
||||||
|
| | | |
|
||||||
|
| evaluates | |
|
||||||
|
| | manages |
|
||||||
|
| V | |
|
||||||
|
| [ configuration language ] | |
|
||||||
|
| | | |
|
||||||
|
| +-----------------------------|-------------------V-----------+ |
|
||||||
|
| | store evaluates to | |
|
||||||
|
| | | | |
|
||||||
|
| | referenced by V builds | |
|
||||||
|
| | [ build input ] ---> [ build plan ] ---> [ build result ] | |
|
||||||
|
| | ^ | | |
|
||||||
|
| +---------|----------------------------------------|----------+ |
|
||||||
|
+-----------|----------------------------------------|------------+
|
||||||
|
| |
|
||||||
|
file system object store path
|
||||||
|
| |
|
||||||
|
+-----------|----------------------------------------|------------+
|
||||||
|
| operating system +------------+ | |
|
||||||
|
| '------------ | | <-----------' |
|
||||||
|
| | file | |
|
||||||
|
| ,-- | | <-, |
|
||||||
|
| | +------------+ | |
|
||||||
|
| execute as | | read, write, execute |
|
||||||
|
| | +------------+ | |
|
||||||
|
| '-> | process | --' |
|
||||||
|
| +------------+ |
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
There exist different types of stores, which all follow this model.
|
||||||
|
Examples:
|
||||||
|
- store on the local file system
|
||||||
|
- remote store accessible via SSH
|
||||||
|
- binary cache store accessible via HTTP
|
||||||
|
|
||||||
|
To make store objects accessible to processes, stores ultimately have to expose store objects through the file system.
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# A [Rosetta stone][rosetta-stone] for build system terminology
|
||||||
|
|
||||||
|
The Nix store's design is comparable to other build systems.
|
||||||
|
Usage of terms is, for historic reasons, not entirely consistent within the Nix ecosystem, and still subject to slow change.
|
||||||
|
|
||||||
|
The following translation table points out similarities and equivalent terms, to help clarify their meaning and inform consistent use in the future.
|
||||||
|
|
||||||
|
| generic build system | Nix | [Bazel][bazel] | [Build Systems à la Carte][bsalc] | programming language |
|
||||||
|
| -------------------------------- | ---------------- | -------------------------------------------------------------------- | --------------------------------- | ------------------------ |
|
||||||
|
| data (build input, build result) | store object | [artifact][bazel-artifact] | value | value |
|
||||||
|
| build instructions | builder | ([depends on action type][bazel-actions]) | function | function |
|
||||||
|
| build task | derivation | [action][bazel-action] | `Task` | [thunk][thunk] |
|
||||||
|
| build plan | derivation graph | [action graph][bazel-action-graph], [build graph][bazel-build-graph] | `Tasks` | [call graph][call-graph] |
|
||||||
|
| build | build | build | application of `Build` | evaluation |
|
||||||
|
| persistence layer | store | [action cache][bazel-action-cache] | `Store` | heap |
|
||||||
|
|
||||||
|
All of these systems share features of [declarative programming][declarative-programming] languages, a key insight first put forward by Eelco Dolstra et al. in [Imposing a Memory Management Discipline on Software Deployment][immdsd] (2004), elaborated in his PhD thesis [The Purely Functional Software Deployment Model][phd-thesis] (2006), and further refined by Andrey Mokhov et al. in [Build Systems à la Carte][bsalc] (2018).
|
||||||
|
|
||||||
|
[rosetta-stone]: https://en.m.wikipedia.org/wiki/Rosetta_Stone
|
||||||
|
[bazel]: https://bazel.build/start/bazel-intro
|
||||||
|
[bazel-artifact]: https://bazel.build/reference/glossary#artifact
|
||||||
|
[bazel-actions]: https://docs.bazel.build/versions/main/skylark/lib/actions.html
|
||||||
|
[bazel-action]: https://bazel.build/reference/glossary#action
|
||||||
|
[bazel-action-graph]: https://bazel.build/reference/glossary#action-graph
|
||||||
|
[bazel-build-graph]: https://bazel.build/reference/glossary#build-graph
|
||||||
|
[bazel-action-cache]: https://bazel.build/reference/glossary#action-cache
|
||||||
|
[thunk]: https://en.m.wikipedia.org/wiki/Thunk
|
||||||
|
[call-graph]: https://en.m.wikipedia.org/wiki/Call_graph
|
||||||
|
[declarative-programming]: https://en.m.wikipedia.org/wiki/Declarative_programming
|
||||||
|
[immdsd]: https://edolstra.github.io/pubs/immdsd-icse2004-final.pdf
|
||||||
|
[phd-thesis]: https://edolstra.github.io/pubs/phd-thesis.pdf
|
||||||
|
[bsalc]: https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf
|
29
doc/manual/src/architecture/store/store/closure.md
Normal file
29
doc/manual/src/architecture/store/store/closure.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Closure
|
||||||
|
|
||||||
|
Nix stores ensure [referential integrity][referential-integrity]: for each store object in the store, all the store objects it references must also be in the store.
|
||||||
|
|
||||||
|
The set of all store objects reachable by following references from a given initial set of store objects is called a *closure*.
|
||||||
|
|
||||||
|
Adding, building, copying and deleting store objects must be done in a way that preserves referential integrity:
|
||||||
|
|
||||||
|
- A newly added store object cannot have references, unless it is a build task.
|
||||||
|
|
||||||
|
- Build results must only refer to store objects in the closure of the build inputs.
|
||||||
|
|
||||||
|
Building a store object will add appropriate references, according to the build task.
|
||||||
|
|
||||||
|
- Store objects being copied must refer to objects already in the destination store.
|
||||||
|
|
||||||
|
Recursive copying must either proceed in dependency order or be atomic.
|
||||||
|
|
||||||
|
- We can only safely delete store objects which are not reachable from any reference still in use.
|
||||||
|
|
||||||
|
<!-- more details in section on garbage collection, link to it once it exists -->
|
||||||
|
|
||||||
|
[referential-integrity]: https://en.m.wikipedia.org/wiki/Referential_integrity
|
||||||
|
[garbage-collection]: https://en.m.wikipedia.org/wiki/Garbage_collection_(computer_science)
|
||||||
|
[immutable-object]: https://en.m.wikipedia.org/wiki/Immutable_object
|
||||||
|
[opaque-data-type]: https://en.m.wikipedia.org/wiki/Opaque_data_type
|
||||||
|
[unique-identifier]: https://en.m.wikipedia.org/wiki/Unique_identifier
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ a number of possible ways:
|
||||||
another.
|
another.
|
||||||
|
|
||||||
- If `--from-expression` is given, *args* are Nix
|
- If `--from-expression` is given, *args* are Nix
|
||||||
[functions](../expressions/language-constructs.md#functions)
|
[functions](../language/constructs.md#functions)
|
||||||
that are called with the active Nix expression as their single
|
that are called with the active Nix expression as their single
|
||||||
argument. The derivations returned by those function calls are
|
argument. The derivations returned by those function calls are
|
||||||
installed. This allows derivations to be specified in an
|
installed. This allows derivations to be specified in an
|
||||||
|
|
|
@ -51,7 +51,7 @@ standard input.
|
||||||
- `--strict`\
|
- `--strict`\
|
||||||
When used with `--eval`, recursively evaluate list elements and
|
When used with `--eval`, recursively evaluate list elements and
|
||||||
attributes. Normally, such sub-expressions are left unevaluated
|
attributes. Normally, such sub-expressions are left unevaluated
|
||||||
(since the Nix expression language is lazy).
|
(since the Nix language is lazy).
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
|
@ -66,7 +66,7 @@ standard input.
|
||||||
When used with `--eval`, print the resulting value as an XML
|
When used with `--eval`, print the resulting value as an XML
|
||||||
representation of the abstract syntax tree rather than as an ATerm.
|
representation of the abstract syntax tree rather than as an ATerm.
|
||||||
The schema is the same as that used by the [`toXML`
|
The schema is the same as that used by the [`toXML`
|
||||||
built-in](../expressions/builtins.md).
|
built-in](../language/builtins.md).
|
||||||
|
|
||||||
- `--read-write-mode`\
|
- `--read-write-mode`\
|
||||||
When used with `--eval`, perform evaluation in read/write mode so
|
When used with `--eval`, perform evaluation in read/write mode so
|
||||||
|
|
|
@ -121,7 +121,7 @@ Special exit codes:
|
||||||
- `102`\
|
- `102`\
|
||||||
Hash mismatch, the build output was rejected because it does not
|
Hash mismatch, the build output was rejected because it does not
|
||||||
match the [`outputHash` attribute of the
|
match the [`outputHash` attribute of the
|
||||||
derivation](../expressions/advanced-attributes.md).
|
derivation](../language/advanced-attributes.md).
|
||||||
|
|
||||||
- `104`\
|
- `104`\
|
||||||
Not deterministic, the build succeeded in check mode but the
|
Not deterministic, the build succeeded in check mode but the
|
||||||
|
|
|
@ -145,7 +145,7 @@ Most Nix commands accept the following command-line options:
|
||||||
expression evaluator will automatically try to call functions that
|
expression evaluator will automatically try to call functions that
|
||||||
it encounters. It can automatically call functions for which every
|
it encounters. It can automatically call functions for which every
|
||||||
argument has a [default
|
argument has a [default
|
||||||
value](../expressions/language-constructs.md#functions) (e.g.,
|
value](../language/constructs.md#functions) (e.g.,
|
||||||
`{ argName ? defaultValue }: ...`). With `--arg`, you can also
|
`{ argName ? defaultValue }: ...`). With `--arg`, you can also
|
||||||
call functions that have arguments without a default value (or
|
call functions that have arguments without a default value (or
|
||||||
override a default value). That is, if the evaluator encounters a
|
override a default value). That is, if the evaluator encounters a
|
||||||
|
@ -164,7 +164,7 @@ Most Nix commands accept the following command-line options:
|
||||||
|
|
||||||
So if you call this Nix expression (e.g., when you do `nix-env -iA
|
So if you call this Nix expression (e.g., when you do `nix-env -iA
|
||||||
pkgname`), the function will be called automatically using the
|
pkgname`), the function will be called automatically using the
|
||||||
value [`builtins.currentSystem`](../expressions/builtins.md) for
|
value [`builtins.currentSystem`](../language/builtins.md) for
|
||||||
the `system` argument. You can override this using `--arg`, e.g.,
|
the `system` argument. You can override this using `--arg`, e.g.,
|
||||||
`nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
|
`nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
|
||||||
since the argument is a Nix string literal, you have to escape the
|
since the argument is a Nix string literal, you have to escape the
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
# Arguments and Variables
|
|
||||||
|
|
||||||
The [Nix expression for GNU Hello](expression-syntax.md) is a
|
|
||||||
function; it is missing some arguments that have to be filled in
|
|
||||||
somewhere. In the Nix Packages collection this is done in the file
|
|
||||||
`pkgs/top-level/all-packages.nix`, where all Nix expressions for
|
|
||||||
packages are imported and called with the appropriate arguments. Here
|
|
||||||
are some fragments of `all-packages.nix`, with annotations of what
|
|
||||||
they mean:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
...
|
|
||||||
|
|
||||||
rec { ①
|
|
||||||
|
|
||||||
hello = import ../applications/misc/hello/ex-1 ② { ③
|
|
||||||
inherit fetchurl stdenv perl;
|
|
||||||
};
|
|
||||||
|
|
||||||
perl = import ../development/interpreters/perl { ④
|
|
||||||
inherit fetchurl stdenv;
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchurl = import ../build-support/fetchurl {
|
|
||||||
inherit stdenv; ...
|
|
||||||
};
|
|
||||||
|
|
||||||
stdenv = ...;
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. This file defines a set of attributes, all of which are concrete
|
|
||||||
derivations (i.e., not functions). In fact, we define a *mutually
|
|
||||||
recursive* set of attributes. That is, the attributes can refer to
|
|
||||||
each other. This is precisely what we want since we want to “plug”
|
|
||||||
the various packages into each other.
|
|
||||||
|
|
||||||
2. Here we *import* the Nix expression for GNU Hello. The import
|
|
||||||
operation just loads and returns the specified Nix expression. In
|
|
||||||
fact, we could just have put the contents of the Nix expression
|
|
||||||
for GNU Hello in `all-packages.nix` at this point. That would be
|
|
||||||
completely equivalent, but it would make `all-packages.nix` rather
|
|
||||||
bulky.
|
|
||||||
|
|
||||||
Note that we refer to `../applications/misc/hello/ex-1`, not
|
|
||||||
`../applications/misc/hello/ex-1/default.nix`. When you try to
|
|
||||||
import a directory, Nix automatically appends `/default.nix` to the
|
|
||||||
file name.
|
|
||||||
|
|
||||||
3. This is where the actual composition takes place. Here we *call* the
|
|
||||||
function imported from `../applications/misc/hello/ex-1` with a set
|
|
||||||
containing the things that the function expects, namely `fetchurl`,
|
|
||||||
`stdenv`, and `perl`. We use inherit again to use the attributes
|
|
||||||
defined in the surrounding scope (we could also have written
|
|
||||||
`fetchurl = fetchurl;`, etc.).
|
|
||||||
|
|
||||||
The result of this function call is an actual derivation that can be
|
|
||||||
built by Nix (since when we fill in the arguments of the function,
|
|
||||||
what we get is its body, which is the call to `stdenv.mkDerivation`
|
|
||||||
in the [Nix expression for GNU Hello](expression-syntax.md)).
|
|
||||||
|
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> Nixpkgs has a convenience function `callPackage` that imports and
|
|
||||||
> calls a function, filling in any missing arguments by passing the
|
|
||||||
> corresponding attribute from the Nixpkgs set, like this:
|
|
||||||
>
|
|
||||||
> ```nix
|
|
||||||
> hello = callPackage ../applications/misc/hello/ex-1 { };
|
|
||||||
> ```
|
|
||||||
>
|
|
||||||
> If necessary, you can set or override arguments:
|
|
||||||
>
|
|
||||||
> ```nix
|
|
||||||
> hello = callPackage ../applications/misc/hello/ex-1 { stdenv = myStdenv; };
|
|
||||||
> ```
|
|
||||||
|
|
||||||
4. Likewise, we have to instantiate Perl, `fetchurl`, and the standard
|
|
||||||
environment.
|
|
|
@ -1,70 +0,0 @@
|
||||||
# Build Script
|
|
||||||
|
|
||||||
Here is the builder referenced from Hello's Nix expression (stored in
|
|
||||||
`pkgs/applications/misc/hello/ex-1/builder.sh`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source $stdenv/setup ①
|
|
||||||
|
|
||||||
PATH=$perl/bin:$PATH ②
|
|
||||||
|
|
||||||
tar xvfz $src ③
|
|
||||||
cd hello-*
|
|
||||||
./configure --prefix=$out ④
|
|
||||||
make ⑤
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
The builder can actually be made a lot shorter by using the *generic
|
|
||||||
builder* functions provided by `stdenv`, but here we write out the build
|
|
||||||
steps to elucidate what a builder does. It performs the following steps:
|
|
||||||
|
|
||||||
1. When Nix runs a builder, it initially completely clears the
|
|
||||||
environment (except for the attributes declared in the derivation).
|
|
||||||
This is done to prevent undeclared inputs from being used in the
|
|
||||||
build process. If for example the `PATH` contained `/usr/bin`, then
|
|
||||||
you might accidentally use `/usr/bin/gcc`.
|
|
||||||
|
|
||||||
So the first step is to set up the environment. This is done by
|
|
||||||
calling the `setup` script of the standard environment. The
|
|
||||||
environment variable `stdenv` points to the location of the
|
|
||||||
standard environment being used. (It wasn't specified explicitly
|
|
||||||
as an attribute in Hello's Nix expression, but `mkDerivation` adds
|
|
||||||
it automatically.)
|
|
||||||
|
|
||||||
2. Since Hello needs Perl, we have to make sure that Perl is in the
|
|
||||||
`PATH`. The `perl` environment variable points to the location of
|
|
||||||
the Perl package (since it was passed in as an attribute to the
|
|
||||||
derivation), so `$perl/bin` is the directory containing the Perl
|
|
||||||
interpreter.
|
|
||||||
|
|
||||||
3. Now we have to unpack the sources. The `src` attribute was bound to
|
|
||||||
the result of fetching the Hello source tarball from the network, so
|
|
||||||
the `src` environment variable points to the location in the Nix
|
|
||||||
store to which the tarball was downloaded. After unpacking, we `cd`
|
|
||||||
to the resulting source directory.
|
|
||||||
|
|
||||||
The whole build is performed in a temporary directory created in
|
|
||||||
`/tmp`, by the way. This directory is removed after the builder
|
|
||||||
finishes, so there is no need to clean up the sources afterwards.
|
|
||||||
Also, the temporary directory is always newly created, so you don't
|
|
||||||
have to worry about files from previous builds interfering with the
|
|
||||||
current build.
|
|
||||||
|
|
||||||
4. GNU Hello is a typical Autoconf-based package, so we first have to
|
|
||||||
run its `configure` script. In Nix every package is stored in a
|
|
||||||
separate location in the Nix store, for instance
|
|
||||||
`/nix/store/9a54ba97fb71b65fda531012d0443ce2-hello-2.1.1`. Nix
|
|
||||||
computes this path by cryptographically hashing all attributes of
|
|
||||||
the derivation. The path is passed to the builder through the `out`
|
|
||||||
environment variable. So here we give `configure` the parameter
|
|
||||||
`--prefix=$out` to cause Hello to be installed in the expected
|
|
||||||
location.
|
|
||||||
|
|
||||||
5. Finally we build Hello (`make`) and install it into the location
|
|
||||||
specified by `out` (`make install`).
|
|
||||||
|
|
||||||
If you are wondering about the absence of error checking on the result
|
|
||||||
of various commands called in the builder: this is because the shell
|
|
||||||
script is evaluated with Bash's `-e` option, which causes the script to
|
|
||||||
be aborted if any command fails without an error check.
|
|
|
@ -1,93 +0,0 @@
|
||||||
# Expression Syntax
|
|
||||||
|
|
||||||
Here is a Nix expression for GNU Hello:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ stdenv, fetchurl, perl }: ①
|
|
||||||
|
|
||||||
stdenv.mkDerivation { ②
|
|
||||||
name = "hello-2.1.1"; ③
|
|
||||||
builder = ./builder.sh; ④
|
|
||||||
src = fetchurl { ⑤
|
|
||||||
url = "ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz";
|
|
||||||
sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465";
|
|
||||||
};
|
|
||||||
inherit perl; ⑥
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This file is actually already in the Nix Packages collection in
|
|
||||||
`pkgs/applications/misc/hello/ex-1/default.nix`. It is customary to
|
|
||||||
place each package in a separate directory and call the single Nix
|
|
||||||
expression in that directory `default.nix`. The file has the following
|
|
||||||
elements (referenced from the figure by number):
|
|
||||||
|
|
||||||
1. This states that the expression is a *function* that expects to be
|
|
||||||
called with three arguments: `stdenv`, `fetchurl`, and `perl`. They
|
|
||||||
are needed to build Hello, but we don't know how to build them here;
|
|
||||||
that's why they are function arguments. `stdenv` is a package that
|
|
||||||
is used by almost all Nix Packages; it provides a
|
|
||||||
“standard” environment consisting of the things you would expect
|
|
||||||
in a basic Unix environment: a C/C++ compiler (GCC, to be precise),
|
|
||||||
the Bash shell, fundamental Unix tools such as `cp`, `grep`, `tar`,
|
|
||||||
etc. `fetchurl` is a function that downloads files. `perl` is the
|
|
||||||
Perl interpreter.
|
|
||||||
|
|
||||||
Nix functions generally have the form `{ x, y, ..., z }: e` where
|
|
||||||
`x`, `y`, etc. are the names of the expected arguments, and where
|
|
||||||
*e* is the body of the function. So here, the entire remainder of
|
|
||||||
the file is the body of the function; when given the required
|
|
||||||
arguments, the body should describe how to build an instance of
|
|
||||||
the Hello package.
|
|
||||||
|
|
||||||
2. So we have to build a package. Building something from other stuff
|
|
||||||
is called a *derivation* in Nix (as opposed to sources, which are
|
|
||||||
built by humans instead of computers). We perform a derivation by
|
|
||||||
calling `stdenv.mkDerivation`. `mkDerivation` is a function
|
|
||||||
provided by `stdenv` that builds a package from a set of
|
|
||||||
*attributes*. A set is just a list of key/value pairs where each
|
|
||||||
key is a string and each value is an arbitrary Nix
|
|
||||||
expression. They take the general form `{ name1 = expr1; ...
|
|
||||||
nameN = exprN; }`.
|
|
||||||
|
|
||||||
3. The attribute `name` specifies the symbolic name and version of
|
|
||||||
the package. Nix doesn't really care about these things, but they
|
|
||||||
are used by for instance `nix-env -q` to show a “human-readable”
|
|
||||||
name for packages. This attribute is required by `mkDerivation`.
|
|
||||||
|
|
||||||
4. The attribute `builder` specifies the builder. This attribute can
|
|
||||||
sometimes be omitted, in which case `mkDerivation` will fill in a
|
|
||||||
default builder (which does a `configure; make; make install`, in
|
|
||||||
essence). Hello is sufficiently simple that the default builder
|
|
||||||
would suffice, but in this case, we will show an actual builder
|
|
||||||
for educational purposes. The value `./builder.sh` refers to the
|
|
||||||
shell script shown in the [next section](build-script.md),
|
|
||||||
discussed below.
|
|
||||||
|
|
||||||
5. The builder has to know what the sources of the package are. Here,
|
|
||||||
the attribute `src` is bound to the result of a call to the
|
|
||||||
`fetchurl` function. Given a URL and a SHA-256 hash of the expected
|
|
||||||
contents of the file at that URL, this function builds a derivation
|
|
||||||
that downloads the file and checks its hash. So the sources are a
|
|
||||||
dependency that like all other dependencies is built before Hello
|
|
||||||
itself is built.
|
|
||||||
|
|
||||||
Instead of `src` any other name could have been used, and in fact
|
|
||||||
there can be any number of sources (bound to different attributes).
|
|
||||||
However, `src` is customary, and it's also expected by the default
|
|
||||||
builder (which we don't use in this example).
|
|
||||||
|
|
||||||
6. Since the derivation requires Perl, we have to pass the value of the
|
|
||||||
`perl` function argument to the builder. All attributes in the set
|
|
||||||
are actually passed as environment variables to the builder, so
|
|
||||||
declaring an attribute
|
|
||||||
|
|
||||||
```nix
|
|
||||||
perl = perl;
|
|
||||||
```
|
|
||||||
|
|
||||||
will do the trick: it binds an attribute `perl` to the function
|
|
||||||
argument which also happens to be called `perl`. However, it looks a
|
|
||||||
bit silly, so there is a shorter syntax. The `inherit` keyword
|
|
||||||
causes the specified attributes to be bound to whatever variables
|
|
||||||
with the same name happen to be in scope.
|
|
|
@ -1,66 +0,0 @@
|
||||||
# Generic Builder Syntax
|
|
||||||
|
|
||||||
Recall that the [build script for GNU Hello](build-script.md) looked
|
|
||||||
something like this:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
PATH=$perl/bin:$PATH
|
|
||||||
tar xvfz $src
|
|
||||||
cd hello-*
|
|
||||||
./configure --prefix=$out
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
The builders for almost all Unix packages look like this — set up some
|
|
||||||
environment variables, unpack the sources, configure, build, and
|
|
||||||
install. For this reason the standard environment provides some Bash
|
|
||||||
functions that automate the build process. Here is what a builder using
|
|
||||||
the generic build facilities looks like:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
buildInputs="$perl" ①
|
|
||||||
|
|
||||||
source $stdenv/setup ②
|
|
||||||
|
|
||||||
genericBuild ③
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is what each line means:
|
|
||||||
|
|
||||||
1. The `buildInputs` variable tells `setup` to use the indicated
|
|
||||||
packages as “inputs”. This means that if a package provides a `bin`
|
|
||||||
subdirectory, it's added to `PATH`; if it has a `include`
|
|
||||||
subdirectory, it's added to GCC's header search path; and so on.
|
|
||||||
(This is implemented in a modular way: `setup` tries to source the
|
|
||||||
file `pkg/nix-support/setup-hook` of all dependencies. These “setup
|
|
||||||
hooks” can then set up whatever environment variables they want; for
|
|
||||||
instance, the setup hook for Perl sets the `PERL5LIB` environment
|
|
||||||
variable to contain the `lib/site_perl` directories of all inputs.)
|
|
||||||
|
|
||||||
2. The function `genericBuild` is defined in the file `$stdenv/setup`.
|
|
||||||
|
|
||||||
3. The final step calls the shell function `genericBuild`, which
|
|
||||||
performs the steps that were done explicitly in the previous build
|
|
||||||
script. The generic builder is smart enough to figure out whether
|
|
||||||
to unpack the sources using `gzip`, `bzip2`, etc. It can be
|
|
||||||
customised in many ways; see the Nixpkgs manual for details.
|
|
||||||
|
|
||||||
Discerning readers will note that the `buildInputs` could just as well
|
|
||||||
have been set in the Nix expression, like this:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
buildInputs = [ perl ];
|
|
||||||
```
|
|
||||||
|
|
||||||
The `perl` attribute can then be removed, and the builder becomes even
|
|
||||||
shorter:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source $stdenv/setup
|
|
||||||
genericBuild
|
|
||||||
```
|
|
||||||
|
|
||||||
In fact, `mkDerivation` provides a default builder that looks exactly
|
|
||||||
like that, so it is actually possible to omit the builder for Hello
|
|
||||||
entirely.
|
|
|
@ -1,253 +0,0 @@
|
||||||
# Values
|
|
||||||
|
|
||||||
## Simple Values
|
|
||||||
|
|
||||||
Nix has the following basic data types:
|
|
||||||
|
|
||||||
- *Strings* can be written in three ways.
|
|
||||||
|
|
||||||
The most common way is to enclose the string between double quotes,
|
|
||||||
e.g., `"foo bar"`. Strings can span multiple lines. The special
|
|
||||||
characters `"` and `\` and the character sequence `${` must be
|
|
||||||
escaped by prefixing them with a backslash (`\`). Newlines, carriage
|
|
||||||
returns and tabs can be written as `\n`, `\r` and `\t`,
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
You can include the result of an expression into a string by
|
|
||||||
enclosing it in `${...}`, a feature known as *antiquotation*. The
|
|
||||||
enclosed expression must evaluate to something that can be coerced
|
|
||||||
into a string (meaning that it must be a string, a path, or a
|
|
||||||
derivation). For instance, rather than writing
|
|
||||||
|
|
||||||
```nix
|
|
||||||
"--with-freetype2-library=" + freetype + "/lib"
|
|
||||||
```
|
|
||||||
|
|
||||||
(where `freetype` is a derivation), you can instead write the more
|
|
||||||
natural
|
|
||||||
|
|
||||||
```nix
|
|
||||||
"--with-freetype2-library=${freetype}/lib"
|
|
||||||
```
|
|
||||||
|
|
||||||
The latter is automatically translated to the former. A more
|
|
||||||
complicated example (from the Nix expression for
|
|
||||||
[Qt](http://www.trolltech.com/products/qt)):
|
|
||||||
|
|
||||||
```nix
|
|
||||||
configureFlags = "
|
|
||||||
-system-zlib -system-libpng -system-libjpeg
|
|
||||||
${if openglSupport then "-dlopen-opengl
|
|
||||||
-L${mesa}/lib -I${mesa}/include
|
|
||||||
-L${libXmu}/lib -I${libXmu}/include" else ""}
|
|
||||||
${if threadSupport then "-thread" else "-no-thread"}
|
|
||||||
";
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that Nix expressions and strings can be arbitrarily nested; in
|
|
||||||
this case the outer string contains various antiquotations that
|
|
||||||
themselves contain strings (e.g., `"-thread"`), some of which in
|
|
||||||
turn contain expressions (e.g., `${mesa}`).
|
|
||||||
|
|
||||||
The second way to write string literals is as an *indented string*,
|
|
||||||
which is enclosed between pairs of *double single-quotes*, like so:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
''
|
|
||||||
This is the first line.
|
|
||||||
This is the second line.
|
|
||||||
This is the third line.
|
|
||||||
''
|
|
||||||
```
|
|
||||||
|
|
||||||
This kind of string literal intelligently strips indentation from
|
|
||||||
the start of each line. To be precise, it strips from each line a
|
|
||||||
number of spaces equal to the minimal indentation of the string as a
|
|
||||||
whole (disregarding the indentation of empty lines). For instance,
|
|
||||||
the first and second line are indented two spaces, while the third
|
|
||||||
line is indented four spaces. Thus, two spaces are stripped from
|
|
||||||
each line, so the resulting string is
|
|
||||||
|
|
||||||
```nix
|
|
||||||
"This is the first line.\nThis is the second line.\n This is the third line.\n"
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the whitespace and newline following the opening `''` is
|
|
||||||
ignored if there is no non-whitespace text on the initial line.
|
|
||||||
|
|
||||||
Antiquotation (`${expr}`) is supported in indented strings.
|
|
||||||
|
|
||||||
Since `${` and `''` have special meaning in indented strings, you
|
|
||||||
need a way to quote them. `$` can be escaped by prefixing it with
|
|
||||||
`''` (that is, two single quotes), i.e., `''$`. `''` can be escaped
|
|
||||||
by prefixing it with `'`, i.e., `'''`. `$` removes any special
|
|
||||||
meaning from the following `$`. Linefeed, carriage-return and tab
|
|
||||||
characters can be written as `''\n`, `''\r`, `''\t`, and `''\`
|
|
||||||
escapes any other character.
|
|
||||||
|
|
||||||
Indented strings are primarily useful in that they allow multi-line
|
|
||||||
string literals to follow the indentation of the enclosing Nix
|
|
||||||
expression, and that less escaping is typically necessary for
|
|
||||||
strings representing languages such as shell scripts and
|
|
||||||
configuration files because `''` is much less common than `"`.
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
...
|
|
||||||
postInstall =
|
|
||||||
''
|
|
||||||
mkdir $out/bin $out/etc
|
|
||||||
cp foo $out/bin
|
|
||||||
echo "Hello World" > $out/etc/foo.conf
|
|
||||||
${if enableBar then "cp bar $out/bin" else ""}
|
|
||||||
'';
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, as a convenience, *URIs* as defined in appendix B of
|
|
||||||
[RFC 2396](http://www.ietf.org/rfc/rfc2396.txt) can be written *as
|
|
||||||
is*, without quotes. For instance, the string
|
|
||||||
`"http://example.org/foo.tar.bz2"` can also be written as
|
|
||||||
`http://example.org/foo.tar.bz2`.
|
|
||||||
|
|
||||||
- Numbers, which can be *integers* (like `123`) or *floating point*
|
|
||||||
(like `123.43` or `.27e13`).
|
|
||||||
|
|
||||||
Numbers are type-compatible: pure integer operations will always
|
|
||||||
return integers, whereas any operation involving at least one
|
|
||||||
floating point number will have a floating point number as a result.
|
|
||||||
|
|
||||||
- *Paths*, e.g., `/bin/sh` or `./builder.sh`. A path must contain at
|
|
||||||
least one slash to be recognised as such. For instance, `builder.sh`
|
|
||||||
is not a path: it's parsed as an expression that selects the
|
|
||||||
attribute `sh` from the variable `builder`. If the file name is
|
|
||||||
relative, i.e., if it does not begin with a slash, it is made
|
|
||||||
absolute at parse time relative to the directory of the Nix
|
|
||||||
expression that contained it. For instance, if a Nix expression in
|
|
||||||
`/foo/bar/bla.nix` refers to `../xyzzy/fnord.nix`, the absolute path
|
|
||||||
is `/foo/xyzzy/fnord.nix`.
|
|
||||||
|
|
||||||
If the first component of a path is a `~`, it is interpreted as if
|
|
||||||
the rest of the path were relative to the user's home directory.
|
|
||||||
e.g. `~/foo` would be equivalent to `/home/edolstra/foo` for a user
|
|
||||||
whose home directory is `/home/edolstra`.
|
|
||||||
|
|
||||||
Paths can also be specified between angle brackets, e.g.
|
|
||||||
`<nixpkgs>`. This means that the directories listed in the
|
|
||||||
environment variable `NIX_PATH` will be searched for the given file
|
|
||||||
or directory name.
|
|
||||||
|
|
||||||
Antiquotation is supported in any paths except those in angle brackets.
|
|
||||||
`./${foo}-${bar}.nix` is a more convenient way of writing
|
|
||||||
`./. + "/" + foo + "-" + bar + ".nix"` or `./. + "/${foo}-${bar}.nix"`. At
|
|
||||||
least one slash must appear *before* any antiquotations for this to be
|
|
||||||
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
|
||||||
operation. `./a.${foo}/b.${bar}` is a path.
|
|
||||||
|
|
||||||
- *Booleans* with values `true` and `false`.
|
|
||||||
|
|
||||||
- The null value, denoted as `null`.
|
|
||||||
|
|
||||||
## Lists
|
|
||||||
|
|
||||||
Lists are formed by enclosing a whitespace-separated list of values
|
|
||||||
between square brackets. For example,
|
|
||||||
|
|
||||||
```nix
|
|
||||||
[ 123 ./foo.nix "abc" (f { x = y; }) ]
|
|
||||||
```
|
|
||||||
|
|
||||||
defines a list of four elements, the last being the result of a call to
|
|
||||||
the function `f`. Note that function calls have to be enclosed in
|
|
||||||
parentheses. If they had been omitted, e.g.,
|
|
||||||
|
|
||||||
```nix
|
|
||||||
[ 123 ./foo.nix "abc" f { x = y; } ]
|
|
||||||
```
|
|
||||||
|
|
||||||
the result would be a list of five elements, the fourth one being a
|
|
||||||
function and the fifth being a set.
|
|
||||||
|
|
||||||
Note that lists are only lazy in values, and they are strict in length.
|
|
||||||
|
|
||||||
## Attribute Sets
|
|
||||||
|
|
||||||
Attribute sets are collections of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
|
||||||
|
|
||||||
Names and values are separated by an equal sign (`=`).
|
|
||||||
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
|
||||||
|
|
||||||
Attributes can appear in any order.
|
|
||||||
An attribute name may only occur once.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
x = 123;
|
|
||||||
text = "Hello";
|
|
||||||
y = f { bla = 456; };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This defines a set with attributes named `x`, `text`, `y`.
|
|
||||||
|
|
||||||
Attributes can be selected from a set using the `.` operator. For
|
|
||||||
instance,
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ a = "Foo"; b = "Bar"; }.a
|
|
||||||
```
|
|
||||||
|
|
||||||
evaluates to `"Foo"`. It is possible to provide a default value in an
|
|
||||||
attribute selection using the `or` keyword. For example,
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
|
||||||
```
|
|
||||||
|
|
||||||
will evaluate to `"Xyzzy"` because there is no `c` attribute in the set.
|
|
||||||
|
|
||||||
You can use arbitrary double-quoted strings as attribute names:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ "foo ${bar}" = 123; "nix-1.0" = 456; }."foo ${bar}"
|
|
||||||
```
|
|
||||||
|
|
||||||
This will evaluate to `123` (Assuming `bar` is antiquotable). In the
|
|
||||||
case where an attribute name is just a single antiquotation, the quotes
|
|
||||||
can be dropped:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ foo = 123; }.${bar} or 456
|
|
||||||
```
|
|
||||||
|
|
||||||
This will evaluate to `123` if `bar` evaluates to `"foo"` when coerced
|
|
||||||
to a string and `456` otherwise (again assuming `bar` is antiquotable).
|
|
||||||
|
|
||||||
In the special case where an attribute name inside of a set declaration
|
|
||||||
evaluates to `null` (which is normally an error, as `null` is not
|
|
||||||
antiquotable), that attribute is simply not added to the set:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ ${if foo then "bar" else null} = true; }
|
|
||||||
```
|
|
||||||
|
|
||||||
This will evaluate to `{}` if `foo` evaluates to `false`.
|
|
||||||
|
|
||||||
A set that has a `__functor` attribute whose value is callable (i.e. is
|
|
||||||
itself a function or a set with a `__functor` attribute whose value is
|
|
||||||
callable) can be applied as if it were a function, with the set itself
|
|
||||||
passed in first , e.g.,
|
|
||||||
|
|
||||||
```nix
|
|
||||||
let add = { __functor = self: x: x + self.x; };
|
|
||||||
inc = add // { x = 1; };
|
|
||||||
in inc 1
|
|
||||||
```
|
|
||||||
|
|
||||||
evaluates to `2`. This can be used to attach metadata to a function
|
|
||||||
without the caller needing to treat it specially, or to implement a form
|
|
||||||
of object-oriented programming, for example.
|
|
|
@ -1,61 +0,0 @@
|
||||||
# Building and Testing
|
|
||||||
|
|
||||||
You can now try to build Hello. Of course, you could do `nix-env -f . -iA
|
|
||||||
hello`, but you may not want to install a possibly broken package just
|
|
||||||
yet. The best way to test the package is by using the command
|
|
||||||
`nix-build`, which builds a Nix expression and creates a symlink named
|
|
||||||
`result` in the current directory:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ nix-build -A hello
|
|
||||||
building path `/nix/store/632d2b22514d...-hello-2.1.1'
|
|
||||||
hello-2.1.1/
|
|
||||||
hello-2.1.1/intl/
|
|
||||||
hello-2.1.1/intl/ChangeLog
|
|
||||||
...
|
|
||||||
|
|
||||||
$ ls -l result
|
|
||||||
lrwxrwxrwx ... 2006-09-29 10:43 result -> /nix/store/632d2b22514d...-hello-2.1.1
|
|
||||||
|
|
||||||
$ ./result/bin/hello
|
|
||||||
Hello, world!
|
|
||||||
```
|
|
||||||
|
|
||||||
The `-A` option selects the `hello` attribute. This is faster than
|
|
||||||
using the symbolic package name specified by the `name` attribute
|
|
||||||
(which also happens to be `hello`) and is unambiguous (there can be
|
|
||||||
multiple packages with the symbolic name `hello`, but there can be
|
|
||||||
only one attribute in a set named `hello`).
|
|
||||||
|
|
||||||
`nix-build` registers the `./result` symlink as a garbage collection
|
|
||||||
root, so unless and until you delete the `./result` symlink, the output
|
|
||||||
of the build will be safely kept on your system. You can use
|
|
||||||
`nix-build`’s `-o` switch to give the symlink another name.
|
|
||||||
|
|
||||||
Nix has transactional semantics. Once a build finishes successfully, Nix
|
|
||||||
makes a note of this in its database: it registers that the path denoted
|
|
||||||
by `out` is now “valid”. If you try to build the derivation again, Nix
|
|
||||||
will see that the path is already valid and finish immediately. If a
|
|
||||||
build fails, either because it returns a non-zero exit code, because Nix
|
|
||||||
or the builder are killed, or because the machine crashes, then the
|
|
||||||
output paths will not be registered as valid. If you try to build the
|
|
||||||
derivation again, Nix will remove the output paths if they exist (e.g.,
|
|
||||||
because the builder died half-way through `make
|
|
||||||
install`) and try again. Note that there is no “negative caching”: Nix
|
|
||||||
doesn't remember that a build failed, and so a failed build can always
|
|
||||||
be repeated. This is because Nix cannot distinguish between permanent
|
|
||||||
failures (e.g., a compiler error due to a syntax error in the source)
|
|
||||||
and transient failures (e.g., a disk full condition).
|
|
||||||
|
|
||||||
Nix also performs locking. If you run multiple Nix builds
|
|
||||||
simultaneously, and they try to build the same derivation, the first Nix
|
|
||||||
instance that gets there will perform the build, while the others block
|
|
||||||
(or perform other derivations if available) until the build finishes:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ nix-build -A hello
|
|
||||||
waiting for lock on `/nix/store/0h5b7hp8d4hqfrw8igvx97x1xawrjnac-hello-2.1.1x'
|
|
||||||
```
|
|
||||||
|
|
||||||
So it is always safe to run multiple instances of Nix in parallel (which
|
|
||||||
isn’t the case with, say, `make`).
|
|
|
@ -1,23 +0,0 @@
|
||||||
# A Simple Nix Expression
|
|
||||||
|
|
||||||
This section shows how to add and test the [GNU Hello
|
|
||||||
package](http://www.gnu.org/software/hello/hello.html) to the Nix
|
|
||||||
Packages collection. Hello is a program that prints out the text “Hello,
|
|
||||||
world\!”.
|
|
||||||
|
|
||||||
To add a package to the Nix Packages collection, you generally need to
|
|
||||||
do three things:
|
|
||||||
|
|
||||||
1. Write a Nix expression for the package. This is a file that
|
|
||||||
describes all the inputs involved in building the package, such as
|
|
||||||
dependencies, sources, and so on.
|
|
||||||
|
|
||||||
2. Write a *builder*. This is a shell script that builds the package
|
|
||||||
from the inputs. (In fact, it can be written in any language, but
|
|
||||||
typically it's a `bash` shell script.)
|
|
||||||
|
|
||||||
3. Add the package to the file `pkgs/top-level/all-packages.nix`. The
|
|
||||||
Nix expression written in the first step is a *function*; it
|
|
||||||
requires other packages in order to build it. In this step you put
|
|
||||||
it all together, i.e., you call the function with the right
|
|
||||||
arguments to build the actual package.
|
|
|
@ -1,12 +0,0 @@
|
||||||
This chapter shows you how to write Nix expressions, which instruct Nix
|
|
||||||
how to build packages. It starts with a simple example (a Nix expression
|
|
||||||
for GNU Hello), and then moves on to a more in-depth look at the Nix
|
|
||||||
expression language.
|
|
||||||
|
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> This chapter is mostly about the Nix expression language. For more
|
|
||||||
> extensive information on adding packages to the Nix Packages
|
|
||||||
> collection (such as functions in the standard environment and coding
|
|
||||||
> conventions), please consult [its
|
|
||||||
> manual](http://nixos.org/nixpkgs/manual/).
|
|
|
@ -3,7 +3,7 @@
|
||||||
- [derivation]{#gloss-derivation}\
|
- [derivation]{#gloss-derivation}\
|
||||||
A description of a build action. The result of a derivation is a
|
A description of a build action. The result of a derivation is a
|
||||||
store object. Derivations are typically specified in Nix expressions
|
store object. Derivations are typically specified in Nix expressions
|
||||||
using the [`derivation` primitive](expressions/derivations.md). These are
|
using the [`derivation` primitive](language/derivations.md). These are
|
||||||
translated into low-level *store derivations* (implicitly by
|
translated into low-level *store derivations* (implicitly by
|
||||||
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,8 @@ and `/etc/zshrc` which you may remove.
|
||||||
This will remove all the build users that no longer serve a purpose.
|
This will remove all the build users that no longer serve a purpose.
|
||||||
|
|
||||||
4. Edit fstab using `sudo vifs` to remove the line mounting the Nix Store
|
4. Edit fstab using `sudo vifs` to remove the line mounting the Nix Store
|
||||||
volume on `/nix`, which looks like this,
|
volume on `/nix`, which looks like
|
||||||
|
`UUID=<uuid> /nix apfs rw,noauto,nobrowse,suid,owners` or
|
||||||
`LABEL=Nix\040Store /nix apfs rw,nobrowse`. This will prevent automatic
|
`LABEL=Nix\040Store /nix apfs rw,nobrowse`. This will prevent automatic
|
||||||
mounting of the Nix Store volume.
|
mounting of the Nix Store volume.
|
||||||
|
|
||||||
|
@ -175,6 +176,18 @@ and `/etc/zshrc` which you may remove.
|
||||||
This will remove the Nix Store volume and everything that was added to the
|
This will remove the Nix Store volume and everything that was added to the
|
||||||
store.
|
store.
|
||||||
|
|
||||||
|
If the output indicates that the command couldn't remove the volume, you should
|
||||||
|
make sure you don't have an _unmounted_ Nix Store volume. Look for a
|
||||||
|
"Nix Store" volume in the output of the following command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
diskutil list
|
||||||
|
```
|
||||||
|
|
||||||
|
If you _do_ see a "Nix Store" volume, delete it by re-running the diskutil
|
||||||
|
deleteVolume command, but replace `/nix` with the store volume's `diskXsY`
|
||||||
|
identifier.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> After you complete the steps here, you will still have an empty `/nix`
|
> After you complete the steps here, you will still have an empty `/nix`
|
||||||
|
@ -191,8 +204,7 @@ and `/etc/zshrc` which you may remove.
|
||||||
<!-- Note: anchors above to catch permalinks to old explanations -->
|
<!-- Note: anchors above to catch permalinks to old explanations -->
|
||||||
|
|
||||||
We believe we have ironed out how to cleanly support the read-only root
|
We believe we have ironed out how to cleanly support the read-only root
|
||||||
on modern macOS. New installs will do this automatically, and you can
|
on modern macOS. New installs will do this automatically.
|
||||||
also re-run a new installer to convert your existing setup.
|
|
||||||
|
|
||||||
This section previously detailed the situation, options, and trade-offs,
|
This section previously detailed the situation, options, and trade-offs,
|
||||||
but it now only outlines what the installer does. You don't need to know
|
but it now only outlines what the installer does. You don't need to know
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Nix Expression Language
|
# Nix Language
|
||||||
|
|
||||||
The Nix expression language is a pure, lazy, functional language. Purity
|
The Nix language is a pure, lazy, functional language. Purity
|
||||||
means that operations in the language don't have side-effects (for
|
means that operations in the language don't have side-effects (for
|
||||||
instance, there is no variable assignment). Laziness means that
|
instance, there is no variable assignment). Laziness means that
|
||||||
arguments to functions are evaluated only when they are needed.
|
arguments to functions are evaluated only when they are needed.
|
||||||
|
@ -10,3 +10,4 @@ full-featured, general purpose language. Its main job is to describe
|
||||||
packages, compositions of packages, and the variability within packages.
|
packages, compositions of packages, and the variability within packages.
|
||||||
|
|
||||||
This section presents the various features of the language.
|
This section presents the various features of the language.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Operators
|
# Operators
|
||||||
|
|
||||||
The table below lists the operators in the Nix expression language, in
|
The table below lists the operators in the Nix language, in
|
||||||
order of precedence (from strongest to weakest binding).
|
order of precedence (from strongest to weakest binding).
|
||||||
|
|
||||||
| Name | Syntax | Associativity | Description | Precedence |
|
| Name | Syntax | Associativity | Description | Precedence |
|
261
doc/manual/src/language/values.md
Normal file
261
doc/manual/src/language/values.md
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
# Data Types
|
||||||
|
|
||||||
|
## Primitives
|
||||||
|
|
||||||
|
- <a id="type-string" href="#type-string">String</a>
|
||||||
|
|
||||||
|
*Strings* can be written in three ways.
|
||||||
|
|
||||||
|
The most common way is to enclose the string between double quotes,
|
||||||
|
e.g., `"foo bar"`. Strings can span multiple lines. The special
|
||||||
|
characters `"` and `\` and the character sequence `${` must be
|
||||||
|
escaped by prefixing them with a backslash (`\`). Newlines, carriage
|
||||||
|
returns and tabs can be written as `\n`, `\r` and `\t`,
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
You can include the result of an expression into a string by
|
||||||
|
enclosing it in `${...}`, a feature known as *antiquotation*. The
|
||||||
|
enclosed expression must evaluate to something that can be coerced
|
||||||
|
into a string (meaning that it must be a string, a path, or a
|
||||||
|
derivation). For instance, rather than writing
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"--with-freetype2-library=" + freetype + "/lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
(where `freetype` is a derivation), you can instead write the more
|
||||||
|
natural
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"--with-freetype2-library=${freetype}/lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
The latter is automatically translated to the former. A more
|
||||||
|
complicated example (from the Nix expression for
|
||||||
|
[Qt](http://www.trolltech.com/products/qt)):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
configureFlags = "
|
||||||
|
-system-zlib -system-libpng -system-libjpeg
|
||||||
|
${if openglSupport then "-dlopen-opengl
|
||||||
|
-L${mesa}/lib -I${mesa}/include
|
||||||
|
-L${libXmu}/lib -I${libXmu}/include" else ""}
|
||||||
|
${if threadSupport then "-thread" else "-no-thread"}
|
||||||
|
";
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that Nix expressions and strings can be arbitrarily nested; in
|
||||||
|
this case the outer string contains various antiquotations that
|
||||||
|
themselves contain strings (e.g., `"-thread"`), some of which in
|
||||||
|
turn contain expressions (e.g., `${mesa}`).
|
||||||
|
|
||||||
|
The second way to write string literals is as an *indented string*,
|
||||||
|
which is enclosed between pairs of *double single-quotes*, like so:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
''
|
||||||
|
This is the first line.
|
||||||
|
This is the second line.
|
||||||
|
This is the third line.
|
||||||
|
''
|
||||||
|
```
|
||||||
|
|
||||||
|
This kind of string literal intelligently strips indentation from
|
||||||
|
the start of each line. To be precise, it strips from each line a
|
||||||
|
number of spaces equal to the minimal indentation of the string as a
|
||||||
|
whole (disregarding the indentation of empty lines). For instance,
|
||||||
|
the first and second line are indented two spaces, while the third
|
||||||
|
line is indented four spaces. Thus, two spaces are stripped from
|
||||||
|
each line, so the resulting string is
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"This is the first line.\nThis is the second line.\n This is the third line.\n"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the whitespace and newline following the opening `''` is
|
||||||
|
ignored if there is no non-whitespace text on the initial line.
|
||||||
|
|
||||||
|
Antiquotation (`${expr}`) is supported in indented strings.
|
||||||
|
|
||||||
|
Since `${` and `''` have special meaning in indented strings, you
|
||||||
|
need a way to quote them. `$` can be escaped by prefixing it with
|
||||||
|
`''` (that is, two single quotes), i.e., `''$`. `''` can be escaped
|
||||||
|
by prefixing it with `'`, i.e., `'''`. `$` removes any special
|
||||||
|
meaning from the following `$`. Linefeed, carriage-return and tab
|
||||||
|
characters can be written as `''\n`, `''\r`, `''\t`, and `''\`
|
||||||
|
escapes any other character.
|
||||||
|
|
||||||
|
Indented strings are primarily useful in that they allow multi-line
|
||||||
|
string literals to follow the indentation of the enclosing Nix
|
||||||
|
expression, and that less escaping is typically necessary for
|
||||||
|
strings representing languages such as shell scripts and
|
||||||
|
configuration files because `''` is much less common than `"`.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
...
|
||||||
|
postInstall =
|
||||||
|
''
|
||||||
|
mkdir $out/bin $out/etc
|
||||||
|
cp foo $out/bin
|
||||||
|
echo "Hello World" > $out/etc/foo.conf
|
||||||
|
${if enableBar then "cp bar $out/bin" else ""}
|
||||||
|
'';
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, as a convenience, *URIs* as defined in appendix B of
|
||||||
|
[RFC 2396](http://www.ietf.org/rfc/rfc2396.txt) can be written *as
|
||||||
|
is*, without quotes. For instance, the string
|
||||||
|
`"http://example.org/foo.tar.bz2"` can also be written as
|
||||||
|
`http://example.org/foo.tar.bz2`.
|
||||||
|
|
||||||
|
- <a id="type-number" href="#type-number">Number</a>
|
||||||
|
|
||||||
|
Numbers, which can be *integers* (like `123`) or *floating point*
|
||||||
|
(like `123.43` or `.27e13`).
|
||||||
|
|
||||||
|
Numbers are type-compatible: pure integer operations will always
|
||||||
|
return integers, whereas any operation involving at least one
|
||||||
|
floating point number will have a floating point number as a result.
|
||||||
|
|
||||||
|
- <a id="type-path" href="#type-path">Path</a>
|
||||||
|
|
||||||
|
*Paths*, e.g., `/bin/sh` or `./builder.sh`. A path must contain at
|
||||||
|
least one slash to be recognised as such. For instance, `builder.sh`
|
||||||
|
is not a path: it's parsed as an expression that selects the
|
||||||
|
attribute `sh` from the variable `builder`. If the file name is
|
||||||
|
relative, i.e., if it does not begin with a slash, it is made
|
||||||
|
absolute at parse time relative to the directory of the Nix
|
||||||
|
expression that contained it. For instance, if a Nix expression in
|
||||||
|
`/foo/bar/bla.nix` refers to `../xyzzy/fnord.nix`, the absolute path
|
||||||
|
is `/foo/xyzzy/fnord.nix`.
|
||||||
|
|
||||||
|
If the first component of a path is a `~`, it is interpreted as if
|
||||||
|
the rest of the path were relative to the user's home directory.
|
||||||
|
e.g. `~/foo` would be equivalent to `/home/edolstra/foo` for a user
|
||||||
|
whose home directory is `/home/edolstra`.
|
||||||
|
|
||||||
|
Paths can also be specified between angle brackets, e.g.
|
||||||
|
`<nixpkgs>`. This means that the directories listed in the
|
||||||
|
environment variable `NIX_PATH` will be searched for the given file
|
||||||
|
or directory name.
|
||||||
|
|
||||||
|
Antiquotation is supported in any paths except those in angle brackets.
|
||||||
|
`./${foo}-${bar}.nix` is a more convenient way of writing
|
||||||
|
`./. + "/" + foo + "-" + bar + ".nix"` or `./. + "/${foo}-${bar}.nix"`. At
|
||||||
|
least one slash must appear *before* any antiquotations for this to be
|
||||||
|
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
||||||
|
operation. `./a.${foo}/b.${bar}` is a path.
|
||||||
|
|
||||||
|
- <a id="type-boolean" href="#type-boolean">Boolean</a>
|
||||||
|
|
||||||
|
*Booleans* with values `true` and `false`.
|
||||||
|
|
||||||
|
- <a id="type-null" href="#type-null">Null</a>
|
||||||
|
|
||||||
|
The null value, denoted as `null`.
|
||||||
|
|
||||||
|
## List
|
||||||
|
|
||||||
|
Lists are formed by enclosing a whitespace-separated list of values
|
||||||
|
between square brackets. For example,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
[ 123 ./foo.nix "abc" (f { x = y; }) ]
|
||||||
|
```
|
||||||
|
|
||||||
|
defines a list of four elements, the last being the result of a call to
|
||||||
|
the function `f`. Note that function calls have to be enclosed in
|
||||||
|
parentheses. If they had been omitted, e.g.,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
[ 123 ./foo.nix "abc" f { x = y; } ]
|
||||||
|
```
|
||||||
|
|
||||||
|
the result would be a list of five elements, the fourth one being a
|
||||||
|
function and the fifth being a set.
|
||||||
|
|
||||||
|
Note that lists are only lazy in values, and they are strict in length.
|
||||||
|
|
||||||
|
## Attribute Set
|
||||||
|
|
||||||
|
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
||||||
|
|
||||||
|
Names and values are separated by an equal sign (`=`).
|
||||||
|
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
||||||
|
|
||||||
|
Attributes can appear in any order.
|
||||||
|
An attribute name may only occur once.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
x = 123;
|
||||||
|
text = "Hello";
|
||||||
|
y = f { bla = 456; };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This defines a set with attributes named `x`, `text`, `y`.
|
||||||
|
|
||||||
|
Attributes can be selected from a set using the `.` operator. For
|
||||||
|
instance,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ a = "Foo"; b = "Bar"; }.a
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to `"Foo"`. It is possible to provide a default value in an
|
||||||
|
attribute selection using the `or` keyword. For example,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
||||||
|
```
|
||||||
|
|
||||||
|
will evaluate to `"Xyzzy"` because there is no `c` attribute in the set.
|
||||||
|
|
||||||
|
You can use arbitrary double-quoted strings as attribute names:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ "foo ${bar}" = 123; "nix-1.0" = 456; }."foo ${bar}"
|
||||||
|
```
|
||||||
|
|
||||||
|
This will evaluate to `123` (Assuming `bar` is antiquotable). In the
|
||||||
|
case where an attribute name is just a single antiquotation, the quotes
|
||||||
|
can be dropped:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ foo = 123; }.${bar} or 456
|
||||||
|
```
|
||||||
|
|
||||||
|
This will evaluate to `123` if `bar` evaluates to `"foo"` when coerced
|
||||||
|
to a string and `456` otherwise (again assuming `bar` is antiquotable).
|
||||||
|
|
||||||
|
In the special case where an attribute name inside of a set declaration
|
||||||
|
evaluates to `null` (which is normally an error, as `null` is not
|
||||||
|
antiquotable), that attribute is simply not added to the set:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ ${if foo then "bar" else null} = true; }
|
||||||
|
```
|
||||||
|
|
||||||
|
This will evaluate to `{}` if `foo` evaluates to `false`.
|
||||||
|
|
||||||
|
A set that has a `__functor` attribute whose value is callable (i.e. is
|
||||||
|
itself a function or a set with a `__functor` attribute whose value is
|
||||||
|
callable) can be applied as if it were a function, with the set itself
|
||||||
|
passed in first , e.g.,
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let add = { __functor = self: x: x + self.x; };
|
||||||
|
inc = add // { x = 1; };
|
||||||
|
in inc 1
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to `2`. This can be used to attach metadata to a function
|
||||||
|
without the caller needing to treat it specially, or to implement a form
|
||||||
|
of object-oriented programming, for example.
|
|
@ -1,5 +1,4 @@
|
||||||
This chapter discusses how to do package management with Nix, i.e.,
|
This chapter discusses how to do package management with Nix, i.e.,
|
||||||
how to obtain, install, upgrade, and erase packages. This is the
|
how to obtain, install, upgrade, and erase packages. This is the
|
||||||
“user’s” perspective of the Nix system — people who want to *create*
|
“user’s” perspective of the Nix system — people who want to *create*
|
||||||
packages should consult the [chapter on writing Nix
|
packages should consult the chapter on the [Nix language](../language/index.md).
|
||||||
expressions](../expressions/writing-nix-expressions.md).
|
|
||||||
|
|
|
@ -640,7 +640,7 @@ place_channel_configuration() {
|
||||||
|
|
||||||
check_selinux() {
|
check_selinux() {
|
||||||
if command -v getenforce > /dev/null 2>&1; then
|
if command -v getenforce > /dev/null 2>&1; then
|
||||||
if ! [ "$(getenforce)" = "Disabled" ]; then
|
if [ "$(getenforce)" = "Enforcing" ]; then
|
||||||
failure <<EOF
|
failure <<EOF
|
||||||
Nix does not work with selinux enabled yet!
|
Nix does not work with selinux enabled yet!
|
||||||
see https://github.com/NixOS/nix/issues/2374
|
see https://github.com/NixOS/nix/issues/2374
|
||||||
|
|
|
@ -2501,18 +2501,18 @@ void EvalState::printStats()
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto list = topObj.list("functions");
|
auto list = topObj.list("functions");
|
||||||
for (auto & i : functionCalls) {
|
for (auto & [fun, count] : functionCalls) {
|
||||||
auto obj = list.object();
|
auto obj = list.object();
|
||||||
if (i.first->name)
|
if (fun->name)
|
||||||
obj.attr("name", (const std::string &) i.first->name);
|
obj.attr("name", (std::string_view) symbols[fun->name]);
|
||||||
else
|
else
|
||||||
obj.attr("name", nullptr);
|
obj.attr("name", nullptr);
|
||||||
if (auto pos = positions[i.first->pos]) {
|
if (auto pos = positions[fun->pos]) {
|
||||||
obj.attr("file", (const std::string &) pos.file);
|
obj.attr("file", (std::string_view) pos.file);
|
||||||
obj.attr("line", pos.line);
|
obj.attr("line", pos.line);
|
||||||
obj.attr("column", pos.column);
|
obj.attr("column", pos.column);
|
||||||
}
|
}
|
||||||
obj.attr("count", i.second);
|
obj.attr("count", count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -341,7 +341,6 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
debug("old lock file: %s", oldLockFile);
|
debug("old lock file: %s", oldLockFile);
|
||||||
|
|
||||||
// FIXME: check whether all overrides are used.
|
|
||||||
std::map<InputPath, FlakeInput> overrides;
|
std::map<InputPath, FlakeInput> overrides;
|
||||||
std::set<InputPath> overridesUsed, updatesUsed;
|
std::set<InputPath> overridesUsed, updatesUsed;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ typedef std::string FlakeId;
|
||||||
* object that fetcher generates (usually via
|
* object that fetcher generates (usually via
|
||||||
* FlakeRef::fromAttrs(attrs) or parseFlakeRef(url) calls).
|
* FlakeRef::fromAttrs(attrs) or parseFlakeRef(url) calls).
|
||||||
*
|
*
|
||||||
* The actual fetch not have been performed yet (i.e. a FlakeRef may
|
* The actual fetch may not have been performed yet (i.e. a FlakeRef may
|
||||||
* be lazy), but the fetcher can be invoked at any time via the
|
* be lazy), but the fetcher can be invoked at any time via the
|
||||||
* FlakeRef to ensure the store is populated with this input.
|
* FlakeRef to ensure the store is populated with this input.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void toJSON(std::ostream & str, const char * start, const char * end)
|
template<>
|
||||||
|
void toJSON<std::string_view>(std::ostream & str, const std::string_view & s)
|
||||||
{
|
{
|
||||||
constexpr size_t BUF_SIZE = 4096;
|
constexpr size_t BUF_SIZE = 4096;
|
||||||
char buf[BUF_SIZE + 7]; // BUF_SIZE + largest single sequence of puts
|
char buf[BUF_SIZE + 7]; // BUF_SIZE + largest single sequence of puts
|
||||||
|
@ -21,7 +22,7 @@ void toJSON(std::ostream & str, const char * start, const char * end)
|
||||||
};
|
};
|
||||||
|
|
||||||
put('"');
|
put('"');
|
||||||
for (auto i = start; i != end; i++) {
|
for (auto i = s.begin(); i != s.end(); i++) {
|
||||||
if (bufPos >= BUF_SIZE) flush();
|
if (bufPos >= BUF_SIZE) flush();
|
||||||
if (*i == '\"' || *i == '\\') { put('\\'); put(*i); }
|
if (*i == '\"' || *i == '\\') { put('\\'); put(*i); }
|
||||||
else if (*i == '\n') { put('\\'); put('n'); }
|
else if (*i == '\n') { put('\\'); put('n'); }
|
||||||
|
@ -44,7 +45,7 @@ void toJSON(std::ostream & str, const char * start, const char * end)
|
||||||
|
|
||||||
void toJSON(std::ostream & str, const char * s)
|
void toJSON(std::ostream & str, const char * s)
|
||||||
{
|
{
|
||||||
if (!s) str << "null"; else toJSON(str, s, s + strlen(s));
|
if (!s) str << "null"; else toJSON(str, std::string_view(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void toJSON<int>(std::ostream & str, const int & n) { str << n; }
|
template<> void toJSON<int>(std::ostream & str, const int & n) { str << n; }
|
||||||
|
@ -55,11 +56,7 @@ template<> void toJSON<long long>(std::ostream & str, const long long & n) { str
|
||||||
template<> void toJSON<unsigned long long>(std::ostream & str, const unsigned long long & n) { str << n; }
|
template<> void toJSON<unsigned long long>(std::ostream & str, const unsigned long long & n) { str << n; }
|
||||||
template<> void toJSON<float>(std::ostream & str, const float & n) { str << n; }
|
template<> void toJSON<float>(std::ostream & str, const float & n) { str << n; }
|
||||||
template<> void toJSON<double>(std::ostream & str, const double & n) { str << n; }
|
template<> void toJSON<double>(std::ostream & str, const double & n) { str << n; }
|
||||||
|
template<> void toJSON<std::string>(std::ostream & str, const std::string & s) { toJSON(str, (std::string_view) s); }
|
||||||
template<> void toJSON<std::string>(std::ostream & str, const std::string & s)
|
|
||||||
{
|
|
||||||
toJSON(str, s.c_str(), s.c_str() + s.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> void toJSON<bool>(std::ostream & str, const bool & b)
|
template<> void toJSON<bool>(std::ostream & str, const bool & b)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +151,7 @@ JSONObject::~JSONObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSONObject::attr(const std::string & s)
|
void JSONObject::attr(std::string_view s)
|
||||||
{
|
{
|
||||||
comma();
|
comma();
|
||||||
toJSON(state->str, s);
|
toJSON(state->str, s);
|
||||||
|
@ -162,19 +159,19 @@ void JSONObject::attr(const std::string & s)
|
||||||
if (state->indent) state->str << ' ';
|
if (state->indent) state->str << ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONList JSONObject::list(const std::string & name)
|
JSONList JSONObject::list(std::string_view name)
|
||||||
{
|
{
|
||||||
attr(name);
|
attr(name);
|
||||||
return JSONList(state);
|
return JSONList(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject JSONObject::object(const std::string & name)
|
JSONObject JSONObject::object(std::string_view name)
|
||||||
{
|
{
|
||||||
attr(name);
|
attr(name);
|
||||||
return JSONObject(state);
|
return JSONObject(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONPlaceholder JSONObject::placeholder(const std::string & name)
|
JSONPlaceholder JSONObject::placeholder(std::string_view name)
|
||||||
{
|
{
|
||||||
attr(name);
|
attr(name);
|
||||||
return JSONPlaceholder(state);
|
return JSONPlaceholder(state);
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void toJSON(std::ostream & str, const char * start, const char * end);
|
|
||||||
void toJSON(std::ostream & str, const char * s);
|
void toJSON(std::ostream & str, const char * s);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -107,7 +106,7 @@ private:
|
||||||
open();
|
open();
|
||||||
}
|
}
|
||||||
|
|
||||||
void attr(const std::string & s);
|
void attr(std::string_view s);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -128,18 +127,18 @@ public:
|
||||||
~JSONObject();
|
~JSONObject();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
JSONObject & attr(const std::string & name, const T & v)
|
JSONObject & attr(std::string_view name, const T & v)
|
||||||
{
|
{
|
||||||
attr(name);
|
attr(name);
|
||||||
toJSON(state->str, v);
|
toJSON(state->str, v);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONList list(const std::string & name);
|
JSONList list(std::string_view name);
|
||||||
|
|
||||||
JSONObject object(const std::string & name);
|
JSONObject object(std::string_view name);
|
||||||
|
|
||||||
JSONPlaceholder placeholder(const std::string & name);
|
JSONPlaceholder placeholder(std::string_view name);
|
||||||
};
|
};
|
||||||
|
|
||||||
class JSONPlaceholder : JSONWriter
|
class JSONPlaceholder : JSONWriter
|
||||||
|
|
|
@ -102,8 +102,8 @@ namespace nix {
|
||||||
|
|
||||||
TEST(toJSON, substringEscape) {
|
TEST(toJSON, substringEscape) {
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
const char *s = "foo\t";
|
std::string_view s = "foo\t";
|
||||||
toJSON(out, s+3, s + strlen(s));
|
toJSON(out, s.substr(3));
|
||||||
|
|
||||||
ASSERT_EQ(out.str(), "\"\\t\"");
|
ASSERT_EQ(out.str(), "\"\\t\"");
|
||||||
}
|
}
|
||||||
|
|
|
@ -522,6 +522,7 @@ Path getHome()
|
||||||
{
|
{
|
||||||
static Path homeDir = []()
|
static Path homeDir = []()
|
||||||
{
|
{
|
||||||
|
std::optional<std::string> unownedUserHomeDir = {};
|
||||||
auto homeDir = getEnv("HOME");
|
auto homeDir = getEnv("HOME");
|
||||||
if (homeDir) {
|
if (homeDir) {
|
||||||
// Only use $HOME if doesn't exist or is owned by the current user.
|
// Only use $HOME if doesn't exist or is owned by the current user.
|
||||||
|
@ -533,8 +534,7 @@ Path getHome()
|
||||||
homeDir.reset();
|
homeDir.reset();
|
||||||
}
|
}
|
||||||
} else if (st.st_uid != geteuid()) {
|
} else if (st.st_uid != geteuid()) {
|
||||||
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file", *homeDir);
|
unownedUserHomeDir.swap(homeDir);
|
||||||
homeDir.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!homeDir) {
|
if (!homeDir) {
|
||||||
|
@ -545,6 +545,9 @@ Path getHome()
|
||||||
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
||||||
throw Error("cannot determine user's home directory");
|
throw Error("cannot determine user's home directory");
|
||||||
homeDir = pw->pw_dir;
|
homeDir = pw->pw_dir;
|
||||||
|
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
|
||||||
|
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *homeDir;
|
return *homeDir;
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -6,7 +6,7 @@ R""(
|
||||||
lock file:
|
lock file:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix flake update
|
# nix flake update --commit-lock-file
|
||||||
* Updated 'nix': 'github:NixOS/nix/9fab14adbc3810d5cc1f88672fde1eee4358405c' -> 'github:NixOS/nix/8927cba62f5afb33b01016d5c4f7f8b7d0adde3c'
|
* Updated 'nix': 'github:NixOS/nix/9fab14adbc3810d5cc1f88672fde1eee4358405c' -> 'github:NixOS/nix/8927cba62f5afb33b01016d5c4f7f8b7d0adde3c'
|
||||||
* Updated 'nixpkgs': 'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' -> 'github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293'
|
* Updated 'nixpkgs': 'github:NixOS/nixpkgs/3d2d8f281a27d466fa54b469b5993f7dde198375' -> 'github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293'
|
||||||
…
|
…
|
||||||
|
|
Loading…
Reference in a new issue