mirror of
https://github.com/NixOS/nix
synced 2025-06-28 22:01:15 +02:00
Merge remote-tracking branch 'origin/master' into lfs
This commit is contained in:
commit
1cb9a354fb
61 changed files with 921 additions and 478 deletions
|
@ -346,6 +346,9 @@ const redirects = {
|
||||||
"scoping-rules": "scoping.html",
|
"scoping-rules": "scoping.html",
|
||||||
"string-literal": "string-literals.html",
|
"string-literal": "string-literals.html",
|
||||||
},
|
},
|
||||||
|
"language/derivations.md": {
|
||||||
|
"builder-execution": "store/drv/building.md#builder-execution",
|
||||||
|
},
|
||||||
"installation/installing-binary.html": {
|
"installation/installing-binary.html": {
|
||||||
"linux": "uninstall.html#linux",
|
"linux": "uninstall.html#linux",
|
||||||
"macos": "uninstall.html#macos",
|
"macos": "uninstall.html#macos",
|
||||||
|
@ -372,6 +375,7 @@ const redirects = {
|
||||||
"glossary.html": {
|
"glossary.html": {
|
||||||
"gloss-local-store": "store/types/local-store.html",
|
"gloss-local-store": "store/types/local-store.html",
|
||||||
"gloss-chroot-store": "store/types/local-store.html",
|
"gloss-chroot-store": "store/types/local-store.html",
|
||||||
|
"gloss-content-addressed-derivation": "#gloss-content-addressing-derivation",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
- [Store Object](store/store-object.md)
|
- [Store Object](store/store-object.md)
|
||||||
- [Content-Addressing Store Objects](store/store-object/content-address.md)
|
- [Content-Addressing Store Objects](store/store-object/content-address.md)
|
||||||
- [Store Path](store/store-path.md)
|
- [Store Path](store/store-path.md)
|
||||||
|
- [Store Derivation and Deriving Path](store/drv.md)
|
||||||
|
- [Building](store/building.md)
|
||||||
- [Store Types](store/types/index.md)
|
- [Store Types](store/types/index.md)
|
||||||
{{#include ./store/types/SUMMARY.md}}
|
{{#include ./store/types/SUMMARY.md}}
|
||||||
- [Nix Language](language/index.md)
|
- [Nix Language](language/index.md)
|
||||||
|
|
|
@ -69,7 +69,7 @@ It can also execute build plans to produce new data, which are made available to
|
||||||
A build plan itself is a series of *build tasks*, together with their build inputs.
|
A build plan itself is a series of *build tasks*, together with their build inputs.
|
||||||
|
|
||||||
> **Important**
|
> **Important**
|
||||||
> A build task in Nix is called [derivation](@docroot@/glossary.md#gloss-derivation).
|
> A build task in Nix is called [store derivation](@docroot@/glossary.md#gloss-store-derivation).
|
||||||
|
|
||||||
Each build task has a special build input executed as *build instructions* in order to perform the build.
|
Each build task has a special build input executed as *build instructions* in order to perform the build.
|
||||||
The result of a build task can be input to another build task.
|
The result of a build task can be input to another build task.
|
||||||
|
|
|
@ -22,11 +22,11 @@ It is based on the current generation of the active [profile](@docroot@/command-
|
||||||
|
|
||||||
The arguments *args* map to store paths in a number of possible ways:
|
The arguments *args* map to store paths in a number of possible ways:
|
||||||
|
|
||||||
- By default, *args* is a set of [derivation] names denoting derivations in the [default Nix expression].
|
- By default, *args* is a set of names denoting derivations in the [default Nix expression].
|
||||||
These are [realised], and the resulting output paths are installed.
|
These are [realised], and the resulting output paths are installed.
|
||||||
Currently installed derivations with a name equal to the name of a derivation being added are removed unless the option `--preserve-installed` is specified.
|
Currently installed derivations with a name equal to the name of a derivation being added are removed unless the option `--preserve-installed` is specified.
|
||||||
|
|
||||||
[derivation]: @docroot@/glossary.md#gloss-derivation
|
[derivation expression]: @docroot@/glossary.md#gloss-derivation-expression
|
||||||
[default Nix expression]: @docroot@/command-ref/files/default-nix-expression.md
|
[default Nix expression]: @docroot@/command-ref/files/default-nix-expression.md
|
||||||
[realised]: @docroot@/glossary.md#gloss-realise
|
[realised]: @docroot@/glossary.md#gloss-realise
|
||||||
|
|
||||||
|
@ -66,11 +66,11 @@ The arguments *args* map to store paths in a number of possible ways:
|
||||||
This can be used to override the priority of the derivations being installed.
|
This can be used to override the priority of the derivations being installed.
|
||||||
This is useful if *args* are [store paths], which don't have any priority information.
|
This is useful if *args* are [store paths], which don't have any priority information.
|
||||||
|
|
||||||
- If *args* are [store derivations](@docroot@/glossary.md#gloss-store-derivation), then these are [realised], and the resulting output paths are installed.
|
- If *args* are [store paths] that point to [store derivations][store derivation], then those store derivations are [realised], and the resulting output paths are installed.
|
||||||
|
|
||||||
- If *args* are [store paths] that are not store derivations, then these are [realised] and installed.
|
- If *args* are [store paths] that do not point to store derivations, then these are [realised] and installed.
|
||||||
|
|
||||||
- By default all [outputs](@docroot@/language/derivations.md#attr-outputs) are installed for each [derivation].
|
- By default all [outputs](@docroot@/language/derivations.md#attr-outputs) are installed for each [store derivation].
|
||||||
This can be overridden by adding a `meta.outputsToInstall` attribute on the derivation listing a subset of the output names.
|
This can be overridden by adding a `meta.outputsToInstall` attribute on the derivation listing a subset of the output names.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -122,6 +122,8 @@ The arguments *args* map to store paths in a number of possible ways:
|
||||||
manifest.nix
|
manifest.nix
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
|
||||||
- `--prebuilt-only` / `-b`
|
- `--prebuilt-only` / `-b`
|
||||||
|
|
|
@ -125,7 +125,10 @@ derivation is shown unless `--no-name` is specified.
|
||||||
|
|
||||||
- `--drv-path`
|
- `--drv-path`
|
||||||
|
|
||||||
Print the path of the [store derivation](@docroot@/glossary.md#gloss-store-derivation).
|
Print the [store path] to the [store derivation].
|
||||||
|
|
||||||
|
[store path]: @docroot@/glossary.md#gloss-store-path
|
||||||
|
[store derivation]: @docroot@/glossary.md#gloss-derivation
|
||||||
|
|
||||||
- `--out-path`
|
- `--out-path`
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ md5sum`.
|
||||||
- `--type` *hashAlgo*
|
- `--type` *hashAlgo*
|
||||||
|
|
||||||
Use the specified cryptographic hash algorithm, which can be one of
|
Use the specified cryptographic hash algorithm, which can be one of
|
||||||
`md5`, `sha1`, `sha256`, and `sha512`.
|
`blake3`, `md5`, `sha1`, `sha256`, and `sha512`.
|
||||||
|
|
||||||
- `--to-base16`
|
- `--to-base16`
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,8 @@ standard input.
|
||||||
- `--eval`
|
- `--eval`
|
||||||
|
|
||||||
Just parse and evaluate the input files, and print the resulting
|
Just parse and evaluate the input files, and print the resulting
|
||||||
values on standard output. No instantiation of store derivations
|
values on standard output.
|
||||||
takes place.
|
Store derivations are not serialized and written to the store, but instead just hashed and discarded.
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
|
|
|
@ -42,7 +42,7 @@ the path of the downloaded file in the Nix store is also printed.
|
||||||
- `--type` *hashAlgo*
|
- `--type` *hashAlgo*
|
||||||
|
|
||||||
Use the specified cryptographic hash algorithm,
|
Use the specified cryptographic hash algorithm,
|
||||||
which can be one of `md5`, `sha1`, `sha256`, and `sha512`.
|
which can be one of `blake3`, `md5`, `sha1`, `sha256`, and `sha512`.
|
||||||
The default is `sha256`.
|
The default is `sha256`.
|
||||||
|
|
||||||
- `--print-path`
|
- `--print-path`
|
||||||
|
|
|
@ -15,7 +15,7 @@ Each of *paths* is processed as follows:
|
||||||
1. If it is not [valid], substitute the store derivation file itself.
|
1. If it is not [valid], substitute the store derivation file itself.
|
||||||
2. Realise its [output paths]:
|
2. Realise its [output paths]:
|
||||||
- Try to fetch from [substituters] the [store objects] associated with the output paths in the store derivation's [closure].
|
- Try to fetch from [substituters] the [store objects] associated with the output paths in the store derivation's [closure].
|
||||||
- With [content-addressed derivations] (experimental):
|
- With [content-addressing derivations] (experimental):
|
||||||
Determine the output paths to realise by querying content-addressed realisation entries in the [Nix database].
|
Determine the output paths to realise by querying content-addressed realisation entries in the [Nix database].
|
||||||
- For any store paths that cannot be substituted, produce the required store objects:
|
- For any store paths that cannot be substituted, produce the required store objects:
|
||||||
1. Realise all outputs of the derivation's dependencies
|
1. Realise all outputs of the derivation's dependencies
|
||||||
|
@ -32,7 +32,7 @@ If no substitutes are available and no store derivation is given, realisation fa
|
||||||
[store objects]: @docroot@/store/store-object.md
|
[store objects]: @docroot@/store/store-object.md
|
||||||
[closure]: @docroot@/glossary.md#gloss-closure
|
[closure]: @docroot@/glossary.md#gloss-closure
|
||||||
[substituters]: @docroot@/command-ref/conf-file.md#conf-substituters
|
[substituters]: @docroot@/command-ref/conf-file.md#conf-substituters
|
||||||
[content-addressed derivations]: @docroot@/development/experimental-features.md#xp-feature-ca-derivations
|
[content-addressing derivations]: @docroot@/development/experimental-features.md#xp-feature-ca-derivations
|
||||||
[Nix database]: @docroot@/glossary.md#gloss-nix-database
|
[Nix database]: @docroot@/glossary.md#gloss-nix-database
|
||||||
|
|
||||||
The resulting paths are printed on standard output.
|
The resulting paths are printed on standard output.
|
||||||
|
|
|
@ -167,11 +167,13 @@ It is useful to perform multiple cross and native builds on the same source tree
|
||||||
for example to ensure that better support for one platform doesn't break the build for another.
|
for example to ensure that better support for one platform doesn't break the build for another.
|
||||||
Meson thankfully makes this very easy by confining all build products to the build directory --- one simple shares the source directory between multiple build directories, each of which contains the build for Nix to a different platform.
|
Meson thankfully makes this very easy by confining all build products to the build directory --- one simple shares the source directory between multiple build directories, each of which contains the build for Nix to a different platform.
|
||||||
|
|
||||||
Nixpkgs's `configurePhase` always chooses `build` in the current directory as the name and location of the build.
|
Here's how to do that:
|
||||||
This makes having multiple build directories slightly more inconvenient.
|
|
||||||
The good news is that Meson/Ninja seem to cope well with relocating the build directory after it is created.
|
|
||||||
|
|
||||||
Here's how to do that
|
1. Instruct Nixpkgs's infra where we want Meson to put its build directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mesonBuildDir=build-my-variant-name
|
||||||
|
```
|
||||||
|
|
||||||
1. Configure as usual
|
1. Configure as usual
|
||||||
|
|
||||||
|
@ -179,24 +181,12 @@ Here's how to do that
|
||||||
configurePhase
|
configurePhase
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Rename the build directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd .. # since `configurePhase` cd'd inside
|
|
||||||
mv build build-linux # or whatever name we want
|
|
||||||
cd build-linux
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Build as usual
|
3. Build as usual
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
buildPhase
|
buildPhase
|
||||||
```
|
```
|
||||||
|
|
||||||
> **N.B.**
|
|
||||||
> [`nixpkgs#335818`](https://github.com/NixOS/nixpkgs/issues/335818) tracks giving `mesonConfigurePhase` proper support for custom build directories.
|
|
||||||
> When it is fixed, we can simplify these instructions and then remove this notice.
|
|
||||||
|
|
||||||
## System type
|
## System type
|
||||||
|
|
||||||
Nix uses a string with the following format to identify the *system type* or *platform* it runs on:
|
Nix uses a string with the following format to identify the *system type* or *platform* it runs on:
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
This section shows how to build and debug Nix with debug symbols enabled.
|
This section shows how to build and debug Nix with debug symbols enabled.
|
||||||
|
|
||||||
|
Additionally, see [Testing Nix](./testing.md) for further instructions on how to debug Nix in the context of a unit test or functional test.
|
||||||
|
|
||||||
## Building Nix with Debug Symbols
|
## Building Nix with Debug Symbols
|
||||||
|
|
||||||
In the development shell, set the `mesonBuildType` environment variable to `debug` before configuring the build:
|
In the development shell, set the `mesonBuildType` environment variable to `debug` before configuring the build:
|
||||||
|
@ -13,6 +15,15 @@ In the development shell, set the `mesonBuildType` environment variable to `debu
|
||||||
Then, proceed to build Nix as described in [Building Nix](./building.md).
|
Then, proceed to build Nix as described in [Building Nix](./building.md).
|
||||||
This will build Nix with debug symbols, which are essential for effective debugging.
|
This will build Nix with debug symbols, which are essential for effective debugging.
|
||||||
|
|
||||||
|
It is also possible to build without debugging for faster build:
|
||||||
|
|
||||||
|
```console
|
||||||
|
[nix-shell]$ NIX_HARDENING_ENABLE=$(printLines $NIX_HARDENING_ENABLE | grep -v fortify)
|
||||||
|
[nix-shell]$ export mesonBuildType=debug
|
||||||
|
```
|
||||||
|
|
||||||
|
(The first line is needed because `fortify` hardening requires at least some optimization.)
|
||||||
|
|
||||||
## Debugging the Nix Binary
|
## Debugging the Nix Binary
|
||||||
|
|
||||||
Obtain your preferred debugger within the development shell:
|
Obtain your preferred debugger within the development shell:
|
||||||
|
|
|
@ -87,7 +87,11 @@ A environment variables that Google Test accepts are also worth knowing:
|
||||||
|
|
||||||
This is used to avoid logging passing tests.
|
This is used to avoid logging passing tests.
|
||||||
|
|
||||||
Putting the two together, one might run
|
3. [`GTEST_BREAK_ON_FAILURE`](https://google.github.io/googletest/advanced.html#turning-assertion-failures-into-break-points)
|
||||||
|
|
||||||
|
This is used to create a debugger breakpoint when an assertion failure occurs.
|
||||||
|
|
||||||
|
Putting the first two together, one might run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
GTEST_BRIEF=1 GTEST_FILTER='ErrorTraceTest.*' meson test nix-expr-tests -v
|
GTEST_BRIEF=1 GTEST_FILTER='ErrorTraceTest.*' meson test nix-expr-tests -v
|
||||||
|
@ -95,6 +99,22 @@ GTEST_BRIEF=1 GTEST_FILTER='ErrorTraceTest.*' meson test nix-expr-tests -v
|
||||||
|
|
||||||
for short but comprensive output.
|
for short but comprensive output.
|
||||||
|
|
||||||
|
### Debugging tests
|
||||||
|
|
||||||
|
For debugging, it is useful to combine the third option above with Meson's [`--gdb`](https://mesonbuild.com/Unit-tests.html#other-test-options) flag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GTEST_BRIEF=1 GTEST_FILTER='Group.my-failing-test' meson test nix-expr-tests --gdb
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
|
||||||
|
1. Run the unit test with GDB
|
||||||
|
|
||||||
|
2. Run just `Group.my-failing-test`
|
||||||
|
|
||||||
|
3. Stop the program when the test fails, allowing the user to then issue arbitrary commands to GDB.
|
||||||
|
|
||||||
### Characterisation testing { #characaterisation-testing-unit }
|
### Characterisation testing { #characaterisation-testing-unit }
|
||||||
|
|
||||||
See [functional characterisation testing](#characterisation-testing-functional) for a broader discussion of characterisation testing.
|
See [functional characterisation testing](#characterisation-testing-functional) for a broader discussion of characterisation testing.
|
||||||
|
@ -144,7 +164,7 @@ $ checkPhase
|
||||||
|
|
||||||
Sometimes it is useful to group related tests so they can be easily run together without running the entire test suite.
|
Sometimes it is useful to group related tests so they can be easily run together without running the entire test suite.
|
||||||
Each test group is in a subdirectory of `tests`.
|
Each test group is in a subdirectory of `tests`.
|
||||||
For example, `tests/functional/ca/meson.build` defines a `ca` test group for content-addressed derivation outputs.
|
For example, `tests/functional/ca/meson.build` defines a `ca` test group for content-addressing derivation outputs.
|
||||||
|
|
||||||
That test group can be run like this:
|
That test group can be run like this:
|
||||||
|
|
||||||
|
@ -213,10 +233,10 @@ edit it like so:
|
||||||
bar
|
bar
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, running the test with `./mk/debug-test.sh` will drop you into GDB once the script reaches that point:
|
Then, running the test with [`--interactive`](https://mesonbuild.com/Unit-tests.html#other-test-options) will prevent Meson from hijacking the terminal so you can drop you into GDB once the script reaches that point:
|
||||||
|
|
||||||
```shell-session
|
```shell-session
|
||||||
$ ./mk/debug-test.sh tests/functional/${testName}.sh
|
$ meson test ${testName} --interactive
|
||||||
...
|
...
|
||||||
+ gdb blash blub
|
+ gdb blash blub
|
||||||
GNU gdb (GDB) 12.1
|
GNU gdb (GDB) 12.1
|
||||||
|
|
|
@ -13,37 +13,41 @@
|
||||||
|
|
||||||
- [Content-Addressing File System Objects](@docroot@/store/file-system-object/content-address.md)
|
- [Content-Addressing File System Objects](@docroot@/store/file-system-object/content-address.md)
|
||||||
- [Content-Addressing Store Objects](@docroot@/store/store-object/content-address.md)
|
- [Content-Addressing Store Objects](@docroot@/store/store-object/content-address.md)
|
||||||
- [content-addressed derivation](#gloss-content-addressed-derivation)
|
- [content-addressing derivation](#gloss-content-addressing-derivation)
|
||||||
|
|
||||||
Software Heritage's writing on [*Intrinsic and Extrinsic identifiers*](https://www.softwareheritage.org/2020/07/09/intrinsic-vs-extrinsic-identifiers) is also a good introduction to the value of content-addressing over other referencing schemes.
|
Software Heritage's writing on [*Intrinsic and Extrinsic identifiers*](https://www.softwareheritage.org/2020/07/09/intrinsic-vs-extrinsic-identifiers) is also a good introduction to the value of content-addressing over other referencing schemes.
|
||||||
|
|
||||||
Besides content addressing, the Nix store also uses [input addressing](#gloss-input-addressed-store-object).
|
Besides content addressing, the Nix store also uses [input addressing](#gloss-input-addressed-store-object).
|
||||||
|
|
||||||
- [derivation]{#gloss-derivation}
|
|
||||||
|
|
||||||
A description of a build task. The result of a derivation is a
|
|
||||||
store object. Derivations declared in Nix expressions are specified
|
|
||||||
using the [`derivation` primitive](./language/derivations.md). These are
|
|
||||||
translated into low-level *store derivations* (implicitly by
|
|
||||||
`nix-build`, or explicitly by `nix-instantiate`).
|
|
||||||
|
|
||||||
[derivation]: #gloss-derivation
|
|
||||||
|
|
||||||
- [store derivation]{#gloss-store-derivation}
|
- [store derivation]{#gloss-store-derivation}
|
||||||
|
|
||||||
A [derivation] represented as a `.drv` file in the [store].
|
A single build task.
|
||||||
It has a [store path], like any [store object].
|
See [Store Derivation](@docroot@/store/drv.md#store-derivation) for details.
|
||||||
It is the [instantiated][instantiate] form of a derivation.
|
|
||||||
|
|
||||||
Example: `/nix/store/g946hcz4c8mdvq2g8vxx42z51qb71rvp-git-2.38.1.drv`
|
|
||||||
|
|
||||||
See [`nix derivation show`](./command-ref/new-cli/nix3-derivation-show.md) (experimental) for displaying the contents of store derivations.
|
|
||||||
|
|
||||||
[store derivation]: #gloss-store-derivation
|
[store derivation]: #gloss-store-derivation
|
||||||
|
|
||||||
|
- [derivation path]{#gloss-derivation-path}
|
||||||
|
|
||||||
|
A [store path] which uniquely identifies a [store derivation].
|
||||||
|
|
||||||
|
See [Referencing Store Derivations](@docroot@/store/drv.md#derivation-path) for details.
|
||||||
|
|
||||||
|
Not to be confused with [deriving path].
|
||||||
|
|
||||||
|
[derivation path]: #gloss-derivation-path
|
||||||
|
|
||||||
|
- [derivation expression]{#gloss-derivation-expression}
|
||||||
|
|
||||||
|
A description of a [store derivation] in the Nix language.
|
||||||
|
The output(s) of a derivation are store objects.
|
||||||
|
Derivations are typically specified in Nix expressions using the [`derivation` primitive](./language/derivations.md).
|
||||||
|
These are translated into store layer *derivations* (implicitly by `nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
||||||
|
|
||||||
|
[derivation expression]: #gloss-derivation-expression
|
||||||
|
|
||||||
- [instantiate]{#gloss-instantiate}, instantiation
|
- [instantiate]{#gloss-instantiate}, instantiation
|
||||||
|
|
||||||
Save an evaluated [derivation] as a [store derivation] in the Nix [store].
|
Translate a [derivation expression] into a [store derivation].
|
||||||
|
|
||||||
See [`nix-instantiate`](./command-ref/nix-instantiate.md), which produces a store derivation from a Nix expression that evaluates to a derivation.
|
See [`nix-instantiate`](./command-ref/nix-instantiate.md), which produces a store derivation from a Nix expression that evaluates to a derivation.
|
||||||
|
|
||||||
|
@ -55,7 +59,7 @@
|
||||||
|
|
||||||
This can be achieved by:
|
This can be achieved by:
|
||||||
- Fetching a pre-built [store object] from a [substituter]
|
- Fetching a pre-built [store object] from a [substituter]
|
||||||
- Running the [`builder`](@docroot@/language/derivations.md#attr-builder) executable as specified in the corresponding [derivation]
|
- Running the [`builder`](@docroot@/language/derivations.md#attr-builder) executable as specified in the corresponding [store derivation]
|
||||||
- Delegating to a [remote machine](@docroot@/command-ref/conf-file.md#conf-builders) and retrieving the outputs
|
- Delegating to a [remote machine](@docroot@/command-ref/conf-file.md#conf-builders) and retrieving the outputs
|
||||||
<!-- TODO: link [running] to build process page, #8888 -->
|
<!-- TODO: link [running] to build process page, #8888 -->
|
||||||
|
|
||||||
|
@ -65,7 +69,7 @@
|
||||||
|
|
||||||
[realise]: #gloss-realise
|
[realise]: #gloss-realise
|
||||||
|
|
||||||
- [content-addressed derivation]{#gloss-content-addressed-derivation}
|
- [content-addressing derivation]{#gloss-content-addressing-derivation}
|
||||||
|
|
||||||
A derivation which has the
|
A derivation which has the
|
||||||
[`__contentAddressed`](./language/advanced-attributes.md#adv-attr-__contentAddressed)
|
[`__contentAddressed`](./language/advanced-attributes.md#adv-attr-__contentAddressed)
|
||||||
|
@ -73,7 +77,7 @@
|
||||||
|
|
||||||
- [fixed-output derivation]{#gloss-fixed-output-derivation} (FOD)
|
- [fixed-output derivation]{#gloss-fixed-output-derivation} (FOD)
|
||||||
|
|
||||||
A [derivation] where a cryptographic hash of the [output] is determined in advance using the [`outputHash`](./language/advanced-attributes.md#adv-attr-outputHash) attribute, and where the [`builder`](@docroot@/language/derivations.md#attr-builder) executable has access to the network.
|
A [store derivation] where a cryptographic hash of the [output] is determined in advance using the [`outputHash`](./language/advanced-attributes.md#adv-attr-outputHash) attribute, and where the [`builder`](@docroot@/language/derivations.md#attr-builder) executable has access to the network.
|
||||||
|
|
||||||
- [store]{#gloss-store}
|
- [store]{#gloss-store}
|
||||||
|
|
||||||
|
@ -130,7 +134,7 @@
|
||||||
- [input-addressed store object]{#gloss-input-addressed-store-object}
|
- [input-addressed store object]{#gloss-input-addressed-store-object}
|
||||||
|
|
||||||
A store object produced by building a
|
A store object produced by building a
|
||||||
non-[content-addressed](#gloss-content-addressed-derivation),
|
non-[content-addressed](#gloss-content-addressing-derivation),
|
||||||
non-[fixed-output](#gloss-fixed-output-derivation)
|
non-[fixed-output](#gloss-fixed-output-derivation)
|
||||||
derivation.
|
derivation.
|
||||||
|
|
||||||
|
@ -138,7 +142,7 @@
|
||||||
|
|
||||||
A [store object] which is [content-addressed](#gloss-content-address),
|
A [store object] which is [content-addressed](#gloss-content-address),
|
||||||
i.e. whose [store path] is determined by its contents.
|
i.e. whose [store path] is determined by its contents.
|
||||||
This includes derivations, the outputs of [content-addressed derivations](#gloss-content-addressed-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
|
This includes derivations, the outputs of [content-addressing derivations](#gloss-content-addressing-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
|
||||||
|
|
||||||
See [Content-Addressing Store Objects](@docroot@/store/store-object/content-address.md) for details.
|
See [Content-Addressing Store Objects](@docroot@/store/store-object/content-address.md) for details.
|
||||||
|
|
||||||
|
@ -188,7 +192,7 @@
|
||||||
>
|
>
|
||||||
> The contents of a `.nix` file form a Nix expression.
|
> The contents of a `.nix` file form a Nix expression.
|
||||||
|
|
||||||
Nix expressions specify [derivations][derivation], which are [instantiated][instantiate] into the Nix store as [store derivations][store derivation].
|
Nix expressions specify [derivation expressions][derivation expression], which are [instantiated][instantiate] into the Nix store as [store derivations][store derivation].
|
||||||
These derivations can then be [realised][realise] to produce [outputs][output].
|
These derivations can then be [realised][realise] to produce [outputs][output].
|
||||||
|
|
||||||
> **Example**
|
> **Example**
|
||||||
|
@ -230,14 +234,14 @@
|
||||||
|
|
||||||
- [output]{#gloss-output}
|
- [output]{#gloss-output}
|
||||||
|
|
||||||
A [store object] produced by a [derivation].
|
A [store object] produced by a [store derivation].
|
||||||
See [the `outputs` argument to the `derivation` function](@docroot@/language/derivations.md#attr-outputs) for details.
|
See [the `outputs` argument to the `derivation` function](@docroot@/language/derivations.md#attr-outputs) for details.
|
||||||
|
|
||||||
[output]: #gloss-output
|
[output]: #gloss-output
|
||||||
|
|
||||||
- [output path]{#gloss-output-path}
|
- [output path]{#gloss-output-path}
|
||||||
|
|
||||||
The [store path] to the [output] of a [derivation].
|
The [store path] to the [output] of a [store derivation].
|
||||||
|
|
||||||
[output path]: #gloss-output-path
|
[output path]: #gloss-output-path
|
||||||
|
|
||||||
|
@ -246,14 +250,11 @@
|
||||||
|
|
||||||
- [deriving path]{#gloss-deriving-path}
|
- [deriving path]{#gloss-deriving-path}
|
||||||
|
|
||||||
Deriving paths are a way to refer to [store objects][store object] that ar not yet [realised][realise].
|
Deriving paths are a way to refer to [store objects][store object] that might not yet be [realised][realise].
|
||||||
This is necessary because, in general and particularly for [content-addressed derivations][content-addressed derivation], the [output path] of an [output] is not known in advance.
|
|
||||||
There are two forms:
|
|
||||||
|
|
||||||
- *constant*: just a [store path]
|
See [Deriving Path](./store/drv.md#deriving-path) for details.
|
||||||
It can be made [valid][validity] by copying it into the store: from the evaluator, command line interface or another store.
|
|
||||||
|
|
||||||
- *output*: a pair of a [store path] to a [derivation] and an [output] name.
|
Not to be confused with [derivation path].
|
||||||
|
|
||||||
- [deriver]{#gloss-deriver}
|
- [deriver]{#gloss-deriver}
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ Derivations can declare some infrequently used optional attributes.
|
||||||
The [`convertHash`](@docroot@/language/builtins.md#builtins-convertHash) function shows how to convert between different encodings, and the [`nix-hash` command](../command-ref/nix-hash.md) has information about obtaining the hash for some contents, as well as converting to and from encodings.
|
The [`convertHash`](@docroot@/language/builtins.md#builtins-convertHash) function shows how to convert between different encodings, and the [`nix-hash` command](../command-ref/nix-hash.md) has information about obtaining the hash for some contents, as well as converting to and from encodings.
|
||||||
|
|
||||||
The `outputHashAlgo` attribute specifies the hash algorithm used to compute the hash.
|
The `outputHashAlgo` attribute specifies the hash algorithm used to compute the hash.
|
||||||
It can currently be `"sha1"`, `"sha256"`, `"sha512"`, or `null`.
|
It can currently be `"blake3", "sha1"`, `"sha256"`, `"sha512"`, or `null`.
|
||||||
`outputHashAlgo` can only be `null` when `outputHash` follows the SRI format.
|
`outputHashAlgo` can only be `null` when `outputHash` follows the SRI format.
|
||||||
|
|
||||||
The `outputHashMode` attribute determines how the hash is computed.
|
The `outputHashMode` attribute determines how the hash is computed.
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
# Derivations
|
# Derivations
|
||||||
|
|
||||||
The most important built-in function is `derivation`, which is used to describe a single derivation:
|
The most important built-in function is `derivation`, which is used to describe a single store-layer [store derivation].
|
||||||
a specification for running an executable on precisely defined input files to repeatably produce output files at uniquely determined file system paths.
|
Consult the [store chapter](@docroot@/store/drv.md) for what a store derivation is;
|
||||||
|
this section just concerns how to create one from the Nix language.
|
||||||
|
|
||||||
It takes as input an attribute set, the attributes of which specify the inputs to the process.
|
This builtin function takes as input an attribute set, the attributes of which specify the inputs to the process.
|
||||||
It outputs an attribute set, and produces a [store derivation] as a side effect of evaluation.
|
It outputs an attribute set, and produces a [store derivation] as a side effect of evaluation.
|
||||||
|
|
||||||
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
@ -15,7 +16,7 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
- [`name`]{#attr-name} ([String](@docroot@/language/types.md#type-string))
|
- [`name`]{#attr-name} ([String](@docroot@/language/types.md#type-string))
|
||||||
|
|
||||||
A symbolic name for the derivation.
|
A symbolic name for the derivation.
|
||||||
It is added to the [store path] of the corresponding [store derivation] as well as to its [output paths](@docroot@/glossary.md#gloss-output-path).
|
See [derivation outputs](@docroot@/store/drv.md#outputs) for what this is affects.
|
||||||
|
|
||||||
[store path]: @docroot@/store/store-path.md
|
[store path]: @docroot@/store/store-path.md
|
||||||
|
|
||||||
|
@ -28,17 +29,12 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> The store derivation's path will be `/nix/store/<hash>-hello.drv`.
|
> The derivation's path will be `/nix/store/<hash>-hello.drv`.
|
||||||
> The [output](#attr-outputs) paths will be of the form `/nix/store/<hash>-hello[-<output>]`
|
> The [output](#attr-outputs) paths will be of the form `/nix/store/<hash>-hello[-<output>]`
|
||||||
|
|
||||||
- [`system`]{#attr-system} ([String](@docroot@/language/types.md#type-string))
|
- [`system`]{#attr-system} ([String](@docroot@/language/types.md#type-string))
|
||||||
|
|
||||||
The system type on which the [`builder`](#attr-builder) executable is meant to be run.
|
See [system](@docroot@/store/drv.md#system).
|
||||||
|
|
||||||
A necessary condition for Nix to build derivations locally is that the `system` attribute matches the current [`system` configuration option].
|
|
||||||
It can automatically [build on other platforms](@docroot@/language/derivations.md#attr-builder) by forwarding build requests to other machines.
|
|
||||||
|
|
||||||
[`system` configuration option]: @docroot@/command-ref/conf-file.md#conf-system
|
|
||||||
|
|
||||||
> **Example**
|
> **Example**
|
||||||
>
|
>
|
||||||
|
@ -68,7 +64,7 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
|
|
||||||
- [`builder`]{#attr-builder} ([Path](@docroot@/language/types.md#type-path) | [String](@docroot@/language/types.md#type-string))
|
- [`builder`]{#attr-builder} ([Path](@docroot@/language/types.md#type-path) | [String](@docroot@/language/types.md#type-string))
|
||||||
|
|
||||||
Path to an executable that will perform the build.
|
See [builder](@docroot@/store/drv.md#builder).
|
||||||
|
|
||||||
> **Example**
|
> **Example**
|
||||||
>
|
>
|
||||||
|
@ -117,7 +113,7 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
|
|
||||||
Default: `[ ]`
|
Default: `[ ]`
|
||||||
|
|
||||||
Command-line arguments to be passed to the [`builder`](#attr-builder) executable.
|
See [args](@docroot@/store/drv.md#args).
|
||||||
|
|
||||||
> **Example**
|
> **Example**
|
||||||
>
|
>
|
||||||
|
@ -239,77 +235,3 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
passed as an empty string.
|
passed as an empty string.
|
||||||
|
|
||||||
<!-- FIXME: add a section on output attributes -->
|
<!-- FIXME: add a section on output attributes -->
|
||||||
|
|
||||||
## Builder execution
|
|
||||||
|
|
||||||
The [`builder`](#attr-builder) is executed as follows:
|
|
||||||
|
|
||||||
- A temporary directory is created under the directory specified by
|
|
||||||
`TMPDIR` (default `/tmp`) where the build will take place. The
|
|
||||||
current directory is changed to this directory.
|
|
||||||
|
|
||||||
- The environment is cleared and set to the derivation attributes, as
|
|
||||||
specified above.
|
|
||||||
|
|
||||||
- In addition, the following variables are set:
|
|
||||||
|
|
||||||
- `NIX_BUILD_TOP` contains the path of the temporary directory for
|
|
||||||
this build.
|
|
||||||
|
|
||||||
- Also, `TMPDIR`, `TEMPDIR`, `TMP`, `TEMP` are set to point to the
|
|
||||||
temporary directory. This is to prevent the builder from
|
|
||||||
accidentally writing temporary files anywhere else. Doing so
|
|
||||||
might cause interference by other processes.
|
|
||||||
|
|
||||||
- `PATH` is set to `/path-not-set` to prevent shells from
|
|
||||||
initialising it to their built-in default value.
|
|
||||||
|
|
||||||
- `HOME` is set to `/homeless-shelter` to prevent programs from
|
|
||||||
using `/etc/passwd` or the like to find the user's home
|
|
||||||
directory, which could cause impurity. Usually, when `HOME` is
|
|
||||||
set, it is used as the location of the home directory, even if
|
|
||||||
it points to a non-existent path.
|
|
||||||
|
|
||||||
- `NIX_STORE` is set to the path of the top-level Nix store
|
|
||||||
directory (typically, `/nix/store`).
|
|
||||||
|
|
||||||
- `NIX_ATTRS_JSON_FILE` & `NIX_ATTRS_SH_FILE` if `__structuredAttrs`
|
|
||||||
is set to `true` for the derivation. A detailed explanation of this
|
|
||||||
behavior can be found in the
|
|
||||||
[section about structured attrs](./advanced-attributes.md#adv-attr-structuredAttrs).
|
|
||||||
|
|
||||||
- For each output declared in `outputs`, the corresponding
|
|
||||||
environment variable is set to point to the intended path in the
|
|
||||||
Nix store for that output. Each output path is a concatenation
|
|
||||||
of the cryptographic hash of all build inputs, the `name`
|
|
||||||
attribute and the output name. (The output name is omitted if
|
|
||||||
it’s `out`.)
|
|
||||||
|
|
||||||
- If an output path already exists, it is removed. Also, locks are
|
|
||||||
acquired to prevent multiple Nix instances from performing the same
|
|
||||||
build at the same time.
|
|
||||||
|
|
||||||
- A log of the combined standard output and error is written to
|
|
||||||
`/nix/var/log/nix`.
|
|
||||||
|
|
||||||
- The builder is executed with the arguments specified by the
|
|
||||||
attribute `args`. If it exits with exit code 0, it is considered to
|
|
||||||
have succeeded.
|
|
||||||
|
|
||||||
- The temporary directory is removed (unless the `-K` option was
|
|
||||||
specified).
|
|
||||||
|
|
||||||
- If the build was successful, Nix scans each output path for
|
|
||||||
references to input paths by looking for the hash parts of the input
|
|
||||||
paths. Since these are potential runtime dependencies, Nix registers
|
|
||||||
them as dependencies of the output paths.
|
|
||||||
|
|
||||||
- After the build, Nix sets the last-modified timestamp on all files
|
|
||||||
in the build result to 1 (00:00:01 1/1/1970 UTC), sets the group to
|
|
||||||
the default group, and sets the mode of the file to 0444 or 0555
|
|
||||||
(i.e., read-only, with execute permission enabled if the file was
|
|
||||||
originally executable). Note that possible `setuid` and `setgid`
|
|
||||||
bits are cleared. Setuid and setgid programs are not currently
|
|
||||||
supported by Nix. This is because the Nix archives used in
|
|
||||||
deployment have no concept of ownership information, and because it
|
|
||||||
makes the build result dependent on the user performing the build.
|
|
||||||
|
|
|
@ -71,8 +71,9 @@ Boxes are data structures, arrow labels are transformations.
|
||||||
| evaluate | | |
|
| evaluate | | |
|
||||||
| | | | |
|
| | | | |
|
||||||
| V | | |
|
| V | | |
|
||||||
| .------------. | | .------------------. |
|
| .------------. | | |
|
||||||
| | derivation |----|-instantiate-|->| store derivation | |
|
| | derivation | | | .------------------. |
|
||||||
|
| | expression |----|-instantiate-|->| store derivation | |
|
||||||
| '------------' | | '------------------' |
|
| '------------' | | '------------------' |
|
||||||
| | | | |
|
| | | | |
|
||||||
| | | realise |
|
| | | realise |
|
||||||
|
|
|
@ -22,9 +22,9 @@ Rather than writing
|
||||||
"--with-freetype2-library=" + freetype + "/lib"
|
"--with-freetype2-library=" + freetype + "/lib"
|
||||||
```
|
```
|
||||||
|
|
||||||
(where `freetype` is a [derivation]), you can instead write
|
(where `freetype` is a [derivation expression]), you can instead write
|
||||||
|
|
||||||
[derivation]: @docroot@/glossary.md#gloss-derivation
|
[derivation expression]: @docroot@/glossary.md#gloss-derivation-expression
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
"--with-freetype2-library=${freetype}/lib"
|
"--with-freetype2-library=${freetype}/lib"
|
||||||
|
@ -148,7 +148,7 @@ An expression that is interpolated must evaluate to one of the following:
|
||||||
- `__toString` must be a function that takes the attribute set itself and returns a string
|
- `__toString` must be a function that takes the attribute set itself and returns a string
|
||||||
- `outPath` must be a string
|
- `outPath` must be a string
|
||||||
|
|
||||||
This includes [derivations](./derivations.md) or [flake inputs](@docroot@/command-ref/new-cli/nix3-flake.md#flake-inputs) (experimental).
|
This includes [derivation expressions](./derivations.md) or [flake inputs](@docroot@/command-ref/new-cli/nix3-flake.md#flake-inputs) (experimental).
|
||||||
|
|
||||||
A string interpolates to itself.
|
A string interpolates to itself.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Derivation "ATerm" file format
|
# Derivation "ATerm" file format
|
||||||
|
|
||||||
For historical reasons, [derivations](@docroot@/glossary.md#gloss-store-derivation) are stored on-disk in [ATerm](https://homepages.cwi.nl/~daybuild/daily-books/technology/aterm-guide/aterm-guide.html) format.
|
For historical reasons, [store derivations][store derivation] are stored on-disk in [ATerm](https://homepages.cwi.nl/~daybuild/daily-books/technology/aterm-guide/aterm-guide.html) format.
|
||||||
|
|
||||||
|
## The ATerm format used
|
||||||
|
|
||||||
Derivations are serialised in one of the following formats:
|
Derivations are serialised in one of the following formats:
|
||||||
|
|
||||||
|
@ -17,3 +19,20 @@ Derivations are serialised in one of the following formats:
|
||||||
The only `version-string`s that are in use today are for [experimental features](@docroot@/development/experimental-features.md):
|
The only `version-string`s that are in use today are for [experimental features](@docroot@/development/experimental-features.md):
|
||||||
|
|
||||||
- `"xp-dyn-drv"` for the [`dynamic-derivations`](@docroot@/development/experimental-features.md#xp-feature-dynamic-derivations) experimental feature.
|
- `"xp-dyn-drv"` for the [`dynamic-derivations`](@docroot@/development/experimental-features.md#xp-feature-dynamic-derivations) experimental feature.
|
||||||
|
|
||||||
|
## Use for encoding to store object
|
||||||
|
|
||||||
|
When derivation is encoded to a [store object] we make the following choices:
|
||||||
|
|
||||||
|
- The store path name is the derivation name with `.drv` suffixed at the end
|
||||||
|
|
||||||
|
Indeed, the ATerm format above does *not* contain the name of the derivation, on the assumption that a store path will also be provided out-of-band.
|
||||||
|
|
||||||
|
- The derivation is content-addressed using the ["Text" method] of content-addressing derivations
|
||||||
|
|
||||||
|
Currently we always encode derivations to store object using the ATerm format (and the previous two choices),
|
||||||
|
but we reserve the option to encode new sorts of derivations differently in the future.
|
||||||
|
|
||||||
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
[store object]: @docroot@/glossary.md#gloss-store-object
|
||||||
|
["Text" method]: @docroot@/store/store-object/content-address.md#method-text
|
||||||
|
|
|
@ -38,6 +38,7 @@ is a JSON object with the following fields:
|
||||||
For an output which will be [content addresed], the name of the hash algorithm used.
|
For an output which will be [content addresed], the name of the hash algorithm used.
|
||||||
Valid algorithm strings are:
|
Valid algorithm strings are:
|
||||||
|
|
||||||
|
- `blake3`
|
||||||
- `md5`
|
- `md5`
|
||||||
- `sha1`
|
- `sha1`
|
||||||
- `sha256`
|
- `sha256`
|
||||||
|
|
|
@ -41,10 +41,10 @@ In other words, the same store object residing in different store could have dif
|
||||||
|
|
||||||
* `deriver`:
|
* `deriver`:
|
||||||
|
|
||||||
If known, the path to the [derivation] from which this store object was produced.
|
If known, the path to the [store derivation] from which this store object was produced.
|
||||||
Otherwise `null`.
|
Otherwise `null`.
|
||||||
|
|
||||||
[derivation]: @docroot@/glossary.md#gloss-store-derivation
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
|
||||||
* `registrationTime` (optional):
|
* `registrationTime` (optional):
|
||||||
|
|
||||||
|
|
97
doc/manual/source/store/building.md
Normal file
97
doc/manual/source/store/building.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# Building
|
||||||
|
|
||||||
|
## Normalizing derivation inputs
|
||||||
|
|
||||||
|
- Each input must be [realised] prior to building the derivation in question.
|
||||||
|
|
||||||
|
[realised]: @docroot@/glossary.md#gloss-realise
|
||||||
|
|
||||||
|
- Once this is done, the derivation is *normalized*, replacing each input deriving path with its store path, which we now know from realising the input.
|
||||||
|
|
||||||
|
## Builder Execution
|
||||||
|
|
||||||
|
The [`builder`](./drv.md#builder) is executed as follows:
|
||||||
|
|
||||||
|
- A temporary directory is created under the directory specified by
|
||||||
|
`TMPDIR` (default `/tmp`) where the build will take place. The
|
||||||
|
current directory is changed to this directory.
|
||||||
|
|
||||||
|
- The environment is cleared and set to the derivation attributes, as
|
||||||
|
specified above.
|
||||||
|
|
||||||
|
- In addition, the following variables are set:
|
||||||
|
|
||||||
|
- `NIX_BUILD_TOP` contains the path of the temporary directory for
|
||||||
|
this build.
|
||||||
|
|
||||||
|
- Also, `TMPDIR`, `TEMPDIR`, `TMP`, `TEMP` are set to point to the
|
||||||
|
temporary directory. This is to prevent the builder from
|
||||||
|
accidentally writing temporary files anywhere else. Doing so
|
||||||
|
might cause interference by other processes.
|
||||||
|
|
||||||
|
- `PATH` is set to `/path-not-set` to prevent shells from
|
||||||
|
initialising it to their built-in default value.
|
||||||
|
|
||||||
|
- `HOME` is set to `/homeless-shelter` to prevent programs from
|
||||||
|
using `/etc/passwd` or the like to find the user's home
|
||||||
|
directory, which could cause impurity. Usually, when `HOME` is
|
||||||
|
set, it is used as the location of the home directory, even if
|
||||||
|
it points to a non-existent path.
|
||||||
|
|
||||||
|
- `NIX_STORE` is set to the path of the top-level Nix store
|
||||||
|
directory (typically, `/nix/store`).
|
||||||
|
|
||||||
|
- `NIX_ATTRS_JSON_FILE` & `NIX_ATTRS_SH_FILE` if `__structuredAttrs`
|
||||||
|
is set to `true` for the derivation. A detailed explanation of this
|
||||||
|
behavior can be found in the
|
||||||
|
[section about structured attrs](@docroot@/language/advanced-attributes.md#adv-attr-structuredAttrs).
|
||||||
|
|
||||||
|
- For each output declared in `outputs`, the corresponding
|
||||||
|
environment variable is set to point to the intended path in the
|
||||||
|
Nix store for that output. Each output path is a concatenation
|
||||||
|
of the cryptographic hash of all build inputs, the `name`
|
||||||
|
attribute and the output name. (The output name is omitted if
|
||||||
|
it’s `out`.)
|
||||||
|
|
||||||
|
- If an output path already exists, it is removed. Also, locks are
|
||||||
|
acquired to prevent multiple Nix instances from performing the same
|
||||||
|
build at the same time.
|
||||||
|
|
||||||
|
- A log of the combined standard output and error is written to
|
||||||
|
`/nix/var/log/nix`.
|
||||||
|
|
||||||
|
- The builder is executed with the arguments specified by the
|
||||||
|
attribute `args`. If it exits with exit code 0, it is considered to
|
||||||
|
have succeeded.
|
||||||
|
|
||||||
|
- The temporary directory is removed (unless the `-K` option was
|
||||||
|
specified).
|
||||||
|
|
||||||
|
## Processing outputs
|
||||||
|
|
||||||
|
If the builder exited successfully, the following steps happen in order to turn the output directories left behind by the builder into proper store objects:
|
||||||
|
|
||||||
|
- **Normalize the file permissions**
|
||||||
|
|
||||||
|
Nix sets the last-modified timestamp on all files
|
||||||
|
in the build result to 1 (00:00:01 1/1/1970 UTC), sets the group to
|
||||||
|
the default group, and sets the mode of the file to 0444 or 0555
|
||||||
|
(i.e., read-only, with execute permission enabled if the file was
|
||||||
|
originally executable). Any possible `setuid` and `setgid`
|
||||||
|
bits are cleared.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Setuid and setgid programs are not currently supported by Nix.
|
||||||
|
> This is because the Nix archives used in deployment have no concept of ownership information,
|
||||||
|
> and because it makes the build result dependent on the user performing the build.
|
||||||
|
|
||||||
|
- **Calculate the references**
|
||||||
|
|
||||||
|
Nix scans each output path for
|
||||||
|
references to input paths by looking for the hash parts of the input
|
||||||
|
paths. Since these are potential runtime dependencies, Nix registers
|
||||||
|
them as dependencies of the output paths.
|
||||||
|
|
||||||
|
Nix also scans for references to other outputs' paths in the same way, because outputs are allowed to refer to each other.
|
||||||
|
If the outputs' references to each other form a cycle, this is an error, because the references of store objects much be acyclic.
|
310
doc/manual/source/store/drv.md
Normal file
310
doc/manual/source/store/drv.md
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
# Store Derivation and Deriving Path
|
||||||
|
|
||||||
|
Besides functioning as a [content addressed store] the Nix store layer works as a [build system].
|
||||||
|
Other system (like Git or IPFS) also store and transfer immutable data, but they don't concern themselves with *how* that data was created.
|
||||||
|
|
||||||
|
This is where Nix distinguishes itself.
|
||||||
|
*Derivations* represent individual build steps, and *deriving paths* are needed to refer to the *outputs* of those build steps before they are built.
|
||||||
|
<!-- The two concepts need to be introduced together because, as described below, each depends on the other. -->
|
||||||
|
|
||||||
|
## Store Derivation {#store-derivation}
|
||||||
|
|
||||||
|
A derivation is a specification for running an executable on precisely defined input files to repeatably produce output files at uniquely determined file system paths.
|
||||||
|
|
||||||
|
A derivation consists of:
|
||||||
|
|
||||||
|
- A name
|
||||||
|
|
||||||
|
- A set of [*inputs*][inputs], a set of [deriving paths][deriving path]
|
||||||
|
|
||||||
|
- A map of [*outputs*][outputs], from names to other data
|
||||||
|
|
||||||
|
- The ["system" type][system] (e.g. `x86_64-linux`) where the executable is to run.
|
||||||
|
|
||||||
|
- The [process creation fields]: to spawn the arbitrary process which will perform the build step.
|
||||||
|
|
||||||
|
[store derivation]: #store-derivation
|
||||||
|
[inputs]: #inputs
|
||||||
|
[input]: #inputs
|
||||||
|
[outputs]: #outputs
|
||||||
|
[output]: #outputs
|
||||||
|
[process creation fields]: #process-creation-fields
|
||||||
|
[builder]: #builder
|
||||||
|
[args]: #args
|
||||||
|
[env]: #env
|
||||||
|
[system]: #system
|
||||||
|
|
||||||
|
### Referencing derivations {#derivation-path}
|
||||||
|
|
||||||
|
Derivations are always referred to by the [store path] of the store object they are encoded to.
|
||||||
|
See the [encoding section](#derivation-encoding) for more details on how this encoding works, and thus what exactly what store path we would end up with for a given derivation.
|
||||||
|
|
||||||
|
The store path of the store object which encodes a derivation is often called a *derivation path* for brevity.
|
||||||
|
|
||||||
|
## Deriving path {#deriving-path}
|
||||||
|
|
||||||
|
Deriving paths are a way to refer to [store objects][store object] that may or may not yet be [realised][realise].
|
||||||
|
There are two forms:
|
||||||
|
|
||||||
|
- [*constant*]{#deriving-path-constant}: just a [store path].
|
||||||
|
It can be made [valid][validity] by copying it into the store: from the evaluator, command line interface or another store.
|
||||||
|
|
||||||
|
- [*output*]{#deriving-path-output}: a pair of a [store path] to a [store derivation] and an [output] name.
|
||||||
|
|
||||||
|
In pseudo code:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type OutputName = String;
|
||||||
|
|
||||||
|
type ConstantPath = {
|
||||||
|
path: StorePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OutputPath = {
|
||||||
|
drvPath: StorePath;
|
||||||
|
output: OutputName;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DerivingPath = ConstantPath | OutputPath;
|
||||||
|
```
|
||||||
|
|
||||||
|
Deriving paths are necessary because, in general and particularly for [content-addressing derivations][content-addressing derivation], the [store path] of an [output] is not known in advance.
|
||||||
|
We can use an output deriving path to refer to such an out, instead of the store path which we do not yet know.
|
||||||
|
|
||||||
|
[deriving path]: #deriving-path
|
||||||
|
[validity]: @docroot@/glossary.md#gloss-validity
|
||||||
|
|
||||||
|
## Parts of a derivation
|
||||||
|
|
||||||
|
A derivation is constructed from the parts documented in the following subsections.
|
||||||
|
|
||||||
|
### Inputs {#inputs}
|
||||||
|
|
||||||
|
The inputs are a set of [deriving paths][deriving path], refering to all store objects needed in order to perform this build step.
|
||||||
|
|
||||||
|
The [process creation fields] will presumably include many [store paths][store path]:
|
||||||
|
|
||||||
|
- The path to the executable normally starts with a store path
|
||||||
|
- The arguments and environment variables likely contain many other store paths.
|
||||||
|
|
||||||
|
But rather than somehow scanning all the other fields for inputs, Nix requires that all inputs be explicitly collected in the inputs field. It is instead the responsibility of the creator of a derivation (e.g. the evaluator) to ensure that every store object referenced in another field (e.g. referenced by store path) is included in this inputs field.
|
||||||
|
|
||||||
|
### Outputs {#outputs}
|
||||||
|
|
||||||
|
The outputs are the derivations are the [store objects][store object] it is obligated to produce.
|
||||||
|
|
||||||
|
Outputs are assigned names, and also consistent of other information based on the type of derivation.
|
||||||
|
|
||||||
|
Output names can be any string which is also a valid [store path] name.
|
||||||
|
The store path of the output store object (also called an [output path] for short), has a name based on the derivation name and the output name.
|
||||||
|
In the general case, store paths have name `derivationName + "-" + outputName`.
|
||||||
|
However, an output named "out" has a store path with name is just the derivation name.
|
||||||
|
This is to allow derivations with a single output to avoid a superfluous `"-${outputName}"` in their single output's name when no disambiguation is needed.
|
||||||
|
|
||||||
|
> **Example**
|
||||||
|
>
|
||||||
|
> A derivation is named `hello`, and has two outputs, `out`, and `dev`
|
||||||
|
>
|
||||||
|
> - The derivation's path will be: `/nix/store/<hash>-hello.drv`.
|
||||||
|
>
|
||||||
|
> - The store path of `out` will be: `/nix/store/<hash>-hello`.
|
||||||
|
>
|
||||||
|
> - The store path of `dev` will be: `/nix/store/<hash>-hello-dev`.
|
||||||
|
|
||||||
|
### System {#system}
|
||||||
|
|
||||||
|
The system type on which the [`builder`](#attr-builder) executable is meant to be run.
|
||||||
|
|
||||||
|
A necessary condition for Nix to schedule a given derivation on some Nix instance is for the "system" of that derivation to match that instance's [`system` configuration option].
|
||||||
|
|
||||||
|
By putting the `system` in each derivation, Nix allows *heterogenous* build plans, where not all steps can be run on the same machine or same sort of machine.
|
||||||
|
Nix can schedule builds such that it automatically builds on other platforms by [forwarding build requests](@docroot@/advanced-topics/distributed-builds.md) to other Nix instances.
|
||||||
|
|
||||||
|
[`system` configuration option]: @docroot@/command-ref/conf-file.md#conf-system
|
||||||
|
|
||||||
|
[content-addressing derivation]: @docroot@/glossary.md#gloss-content-addressing-derivation
|
||||||
|
[realise]: @docroot@/glossary.md#gloss-realise
|
||||||
|
[store object]: @docroot@/store/store-object.md
|
||||||
|
[store path]: @docroot@/store/store-path.md
|
||||||
|
|
||||||
|
### Process creation fields {#process-creation-fields}
|
||||||
|
|
||||||
|
These are the three fields which describe how to spawn the process which (along with any of its own child processes) will perform the build.
|
||||||
|
You may note that this has everything needed for an `execve` system call.
|
||||||
|
|
||||||
|
#### Builder {#builder}
|
||||||
|
|
||||||
|
This is the path to an executable that will perform the build and produce the [outputs].
|
||||||
|
|
||||||
|
#### Arguments {#args}
|
||||||
|
|
||||||
|
Command-line arguments to be passed to the [`builder`](#builder) executable.
|
||||||
|
|
||||||
|
Note that these are the arguments after the first argument.
|
||||||
|
The first argument passed to the `builder` will be the value of `builder`, as per the usual convention on Unix.
|
||||||
|
See [Wikipedia](https://en.wikipedia.org/wiki/Argv) for details.
|
||||||
|
|
||||||
|
#### Environment Variables {#env}
|
||||||
|
|
||||||
|
Environment variables which will be passed to the [builder](#builder) executable.
|
||||||
|
|
||||||
|
### Placeholders
|
||||||
|
|
||||||
|
Placeholders are opaque values used within the [process creation fields] to [store objects] for which we don't yet know [store path]s.
|
||||||
|
They are strings in the form `/<hash>` that are embedded anywhere within the strings of those fields, and we are [considering](https://github.com/NixOS/nix/issues/12361) to add store-path-like placeholders.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Output Deriving Path exist to solve the same problem as placeholders --- that is, referring to store objects for which we don't yet know a store path.
|
||||||
|
> They also have a string syntax with `^`, [described in the encoding section](#deriving-path-encoding).
|
||||||
|
> We could use that syntax instead of `/<hash>` for placeholders, but its human-legibility would cause problems.
|
||||||
|
|
||||||
|
There are two types of placeholder, corresponding to the two cases where this problem arises:
|
||||||
|
|
||||||
|
- [Output placeholder]{#output-placeholder}:
|
||||||
|
|
||||||
|
This is a placeholder for a derivation's own output.
|
||||||
|
|
||||||
|
- [Input placeholder]{#input-placeholder}:
|
||||||
|
|
||||||
|
This is a placeholder to a derivation's non-constant [input],
|
||||||
|
i.e. an input that is an [output derived path].
|
||||||
|
|
||||||
|
> **Explanation**
|
||||||
|
>
|
||||||
|
> In general, we need to realise [realise] a [store object] in order to be sure to have a store object for it.
|
||||||
|
> But for these two cases this is either impossible or impractical:
|
||||||
|
>
|
||||||
|
> - In the output case this is impossible:
|
||||||
|
>
|
||||||
|
> We cannot build the output until we have a correct derivation, and we cannot have a correct derivation (without using placeholders) until we have the output path.
|
||||||
|
>
|
||||||
|
> - In the input case this is impractical:
|
||||||
|
>
|
||||||
|
> If we always build a dependency first, and then refer to its output by store path, we would lose the ability for a derivation graph to describe an entire build plan consisting of multiple build steps.
|
||||||
|
|
||||||
|
## Encoding
|
||||||
|
|
||||||
|
### Derivation {#derivation-encoding}
|
||||||
|
|
||||||
|
There are two formats, documented separately:
|
||||||
|
|
||||||
|
- The legacy ["ATerm" format](@docroot@/protocols/derivation-aterm.md)
|
||||||
|
|
||||||
|
- The experimental, currently under development and changing [JSON format](@docroot@/protocols/json/derivation.md)
|
||||||
|
|
||||||
|
Every derivation has a canonical choice of encoding used to serialize it to a store object.
|
||||||
|
This ensures that there is a canonical [store path] used to refer to the derivation, as described in [Referencing derivations](#derivation-path).
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Currently, the canonical encoding for every derivation is the "ATerm" format,
|
||||||
|
> but this is subject to change for types derivations which are not yet stable.
|
||||||
|
|
||||||
|
Regardless of the format used, when serializing a derivation to a store object, that store object will be content-addressed.
|
||||||
|
|
||||||
|
In the common case, the inputs to store objects are either:
|
||||||
|
|
||||||
|
- [constant deriving paths](#deriving-path-constant) for content-addressed source objects, which are "initial inputs" rather than the outputs of some other derivation
|
||||||
|
|
||||||
|
- the outputs of other derivations
|
||||||
|
|
||||||
|
If those other derivations *also* abide by this common case (and likewise for transitive inputs), then the entire closure of the serialized derivation will be content-addressed.
|
||||||
|
|
||||||
|
### Deriving Path {#deriving-path-encoding}
|
||||||
|
|
||||||
|
- *constant*
|
||||||
|
|
||||||
|
Constant deriving paths are encoded simply as the underlying store path is.
|
||||||
|
Thus, we see that every encoded store path is also a valid encoded (constant) deriving path.
|
||||||
|
|
||||||
|
- *output*
|
||||||
|
|
||||||
|
Output deriving paths are encoded by
|
||||||
|
|
||||||
|
- encoding of a store path referring to a derivation
|
||||||
|
|
||||||
|
- a `^` separator (or `!` in some legacy contexts)
|
||||||
|
|
||||||
|
- the name of an output of the previously referred derivation
|
||||||
|
|
||||||
|
> **Example**
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> /nix/store/lxrn8v5aamkikg6agxwdqd1jz7746wz4-firefox-98.0.2.drv^out
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> This parses like so:
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> /nix/store/lxrn8v5aamkikg6agxwdqd1jz7746wz4-firefox-98.0.2.drv^out
|
||||||
|
> |------------------------------------------------------------| |-|
|
||||||
|
> store path (usual encoding) output name
|
||||||
|
> |--|
|
||||||
|
> note the ".drv"
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## Extending the model to be higher-order
|
||||||
|
|
||||||
|
**Experimental feature**: [`dynamic-derivations`](@docroot@/development/experimental-features.md#xp-feature-dynamic-derivations)
|
||||||
|
|
||||||
|
So far, we have used store paths to refer to derivations.
|
||||||
|
That works because we've implicitly assumed that all derivations are created *statically* --- created by some mechanism out of band, and then manually inserted into the store.
|
||||||
|
But what if derivations could also be created dynamically within Nix?
|
||||||
|
In other words, what if derivations could be the outputs of other derivations?
|
||||||
|
|
||||||
|
:::{.note}
|
||||||
|
In the parlance of "Build Systems à la carte", we are generalizing the Nix store layer to be a "Monadic" instead of "Applicative" build system.
|
||||||
|
:::
|
||||||
|
|
||||||
|
How should we refer to such derivations?
|
||||||
|
A deriving path works, the same as how we refer to other derivation outputs.
|
||||||
|
But what about a dynamic derivations output?
|
||||||
|
(i.e. how do we refer to the output of an output of a derivation?)
|
||||||
|
For that we need to generalize the definition of deriving path, replacing the store path used to refer to the derivation with a nested deriving path:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
type OutputPath = {
|
||||||
|
- drvPath: StorePath;
|
||||||
|
+ drvPath: DerivingPath;
|
||||||
|
output: OutputName;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, the `drvPath` field of `OutputPath` is itself a `DerivingPath` instead of a `StorePath`.
|
||||||
|
|
||||||
|
With that change, here is updated definition:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type OutputName = String;
|
||||||
|
|
||||||
|
type ConstantPath = {
|
||||||
|
path: StorePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OutputPath = {
|
||||||
|
drvPath: DerivingPath;
|
||||||
|
output: OutputName;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DerivingPath = ConstantPath | OutputPath;
|
||||||
|
```
|
||||||
|
|
||||||
|
Under this extended model, `DerivingPath`s are thus inductively built up from a root `ConstantPath`, wrapped with zero or more outer `OutputPath`s.
|
||||||
|
|
||||||
|
### Encoding {#deriving-path-encoding}
|
||||||
|
|
||||||
|
The encoding is adjusted in the natural way, encoding the `drv` field recursively using the same deriving path encoding.
|
||||||
|
The result of this is that it is possible to have a chain of `^<output-name>` at the end of the final string, as opposed to just a single one.
|
||||||
|
|
||||||
|
> **Example**
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> /nix/store/lxrn8v5aamkikg6agxwdqd1jz7746wz4-firefox-98.0.2.drv^foo.drv^bar.drv^out
|
||||||
|
> |----------------------------------------------------------------------------| |-|
|
||||||
|
> inner deriving path (usual encoding) output name
|
||||||
|
> |--------------------------------------------------------------------| |-----|
|
||||||
|
> even more inner deriving path (usual encoding) output name
|
||||||
|
> |------------------------------------------------------------| |-----|
|
||||||
|
> innermost constant store path (usual encoding) output name
|
||||||
|
> ```
|
|
@ -35,7 +35,6 @@
|
||||||
echo "ERROR: found merge/patch conflicts in files"
|
echo "ERROR: found merge/patch conflicts in files"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
touch $out
|
|
||||||
''}";
|
''}";
|
||||||
};
|
};
|
||||||
nixfmt-rfc-style = {
|
nixfmt-rfc-style = {
|
||||||
|
|
|
@ -21,14 +21,21 @@ function add_path --argument-names new_path
|
||||||
end
|
end
|
||||||
|
|
||||||
# Main configuration
|
# Main configuration
|
||||||
|
|
||||||
|
# Set up the per-user profile.
|
||||||
|
|
||||||
|
set --local NIX_LINK $HOME/.nix-profile
|
||||||
|
|
||||||
|
# Set up environment.
|
||||||
|
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
||||||
set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||||
|
|
||||||
# Populate bash completions, .desktop files, etc
|
# Populate bash completions, .desktop files, etc
|
||||||
if test -z "$XDG_DATA_DIRS"
|
if test -z "$XDG_DATA_DIRS"
|
||||||
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
||||||
set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:/nix/var/nix/profiles/default/share"
|
set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||||
else
|
else
|
||||||
set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:/nix/var/nix/profiles/default/share"
|
set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||||
|
@ -56,7 +63,7 @@ else
|
||||||
end
|
end
|
||||||
|
|
||||||
add_path "@localstatedir@/nix/profiles/default/bin"
|
add_path "@localstatedir@/nix/profiles/default/bin"
|
||||||
add_path "$HOME/.nix-profile/bin"
|
add_path "$NIX_LINK/bin"
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ end
|
||||||
|
|
||||||
# Set up the per-user profile.
|
# Set up the per-user profile.
|
||||||
|
|
||||||
set NIX_LINK $HOME/.nix-profile
|
set --local NIX_LINK $HOME/.nix-profile
|
||||||
|
|
||||||
# Set up environment.
|
# Set up environment.
|
||||||
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
||||||
|
@ -63,7 +63,6 @@ if set --query MANPATH
|
||||||
end
|
end
|
||||||
|
|
||||||
add_path "$NIX_LINK/bin"
|
add_path "$NIX_LINK/bin"
|
||||||
set --erase NIX_LINK
|
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ Args::Flag hashAlgo(std::string && longName, HashAlgorithm * ha)
|
||||||
{
|
{
|
||||||
return Args::Flag {
|
return Args::Flag {
|
||||||
.longName = std::move(longName),
|
.longName = std::move(longName),
|
||||||
.description = "Hash algorithm (`md5`, `sha1`, `sha256`, or `sha512`).",
|
.description = "Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`).",
|
||||||
.labels = {"hash-algo"},
|
.labels = {"hash-algo"},
|
||||||
.handler = {[ha](std::string s) {
|
.handler = {[ha](std::string s) {
|
||||||
*ha = parseHashAlgo(s);
|
*ha = parseHashAlgo(s);
|
||||||
|
@ -63,7 +63,7 @@ Args::Flag hashAlgoOpt(std::string && longName, std::optional<HashAlgorithm> * o
|
||||||
{
|
{
|
||||||
return Args::Flag {
|
return Args::Flag {
|
||||||
.longName = std::move(longName),
|
.longName = std::move(longName),
|
||||||
.description = "Hash algorithm (`md5`, `sha1`, `sha256`, or `sha512`). Can be omitted for SRI hashes.",
|
.description = "Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`). Can be omitted for SRI hashes.",
|
||||||
.labels = {"hash-algo"},
|
.labels = {"hash-algo"},
|
||||||
.handler = {[oha](std::string s) {
|
.handler = {[oha](std::string s) {
|
||||||
*oha = std::optional<HashAlgorithm>{parseHashAlgo(s)};
|
*oha = std::optional<HashAlgorithm>{parseHashAlgo(s)};
|
||||||
|
@ -120,7 +120,7 @@ Args::Flag contentAddressMethod(ContentAddressMethod * method)
|
||||||
|
|
||||||
- [`text`](@docroot@/store/store-object/content-address.md#method-text):
|
- [`text`](@docroot@/store/store-object/content-address.md#method-text):
|
||||||
Like `flat`, but used for
|
Like `flat`, but used for
|
||||||
[derivations](@docroot@/glossary.md#store-derivation) serialized in store object and
|
[derivations](@docroot@/glossary.md#gloss-store-derivation) serialized in store object and
|
||||||
[`builtins.toFile`](@docroot@/language/builtins.html#builtins-toFile).
|
[`builtins.toFile`](@docroot@/language/builtins.html#builtins-toFile).
|
||||||
For advanced use-cases only;
|
For advanced use-cases only;
|
||||||
for regular usage prefer `nar` and `flat`.
|
for regular usage prefer `nar` and `flat`.
|
||||||
|
|
|
@ -1152,7 +1152,7 @@ namespace nix {
|
||||||
|
|
||||||
ASSERT_TRACE1("hashString \"foo\" \"content\"",
|
ASSERT_TRACE1("hashString \"foo\" \"content\"",
|
||||||
UsageError,
|
UsageError,
|
||||||
HintFmt("unknown hash algorithm '%s', expect 'md5', 'sha1', 'sha256', or 'sha512'", "foo"));
|
HintFmt("unknown hash algorithm '%s', expect 'blake3', 'md5', 'sha1', 'sha256', or 'sha512'", "foo"));
|
||||||
|
|
||||||
ASSERT_TRACE2("hashString \"sha256\" {}",
|
ASSERT_TRACE2("hashString \"sha256\" {}",
|
||||||
TypeError,
|
TypeError,
|
||||||
|
|
|
@ -172,7 +172,7 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
|
||||||
|
|
||||||
TEST_F(nix_api_expr_test, nix_expr_realise_context)
|
TEST_F(nix_api_expr_test, nix_expr_realise_context)
|
||||||
{
|
{
|
||||||
// TODO (ca-derivations): add a content-addressed derivation output, which produces a placeholder
|
// TODO (ca-derivations): add a content-addressing derivation output, which produces a placeholder
|
||||||
auto expr = R"(
|
auto expr = R"(
|
||||||
''
|
''
|
||||||
a derivation output: ${
|
a derivation output: ${
|
||||||
|
|
|
@ -1595,9 +1595,13 @@ static RegisterPrimOp primop_placeholder({
|
||||||
.name = "placeholder",
|
.name = "placeholder",
|
||||||
.args = {"output"},
|
.args = {"output"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Return a placeholder string for the specified *output* that will be
|
Return at
|
||||||
substituted by the corresponding output path at build time. Typical
|
[output placeholder string](@docroot@/store/drv.md#output-placeholder)
|
||||||
outputs would be `"out"`, `"bin"` or `"dev"`.
|
for the specified *output* that will be substituted by the corresponding
|
||||||
|
[output path](@docroot@/glossary.md#gloss-output-path)
|
||||||
|
at build time.
|
||||||
|
|
||||||
|
Typical outputs would be `"out"`, `"bin"` or `"dev"`.
|
||||||
)",
|
)",
|
||||||
.fun = prim_placeholder,
|
.fun = prim_placeholder,
|
||||||
});
|
});
|
||||||
|
@ -2135,12 +2139,15 @@ static RegisterPrimOp primop_outputOf({
|
||||||
.name = "__outputOf",
|
.name = "__outputOf",
|
||||||
.args = {"derivation-reference", "output-name"},
|
.args = {"derivation-reference", "output-name"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Return the output path of a derivation, literally or using a placeholder if needed.
|
Return the output path of a derivation, literally or using an
|
||||||
|
[input placeholder string](@docroot@/store/drv.md#input-placeholder)
|
||||||
|
if needed.
|
||||||
|
|
||||||
If the derivation has a statically-known output path (i.e. the derivation output is input-addressed, or fixed content-addresed), the output path will just be returned.
|
If the derivation has a statically-known output path (i.e. the derivation output is input-addressed, or fixed content-addresed), the output path will just be returned.
|
||||||
But if the derivation is content-addressed or if the derivation is itself not-statically produced (i.e. is the output of another derivation), a placeholder will be returned instead.
|
But if the derivation is content-addressed or if the derivation is itself not-statically produced (i.e. is the output of another derivation), an input placeholder will be returned instead.
|
||||||
|
|
||||||
*`derivation reference`* must be a string that may contain a regular store path to a derivation, or may be a placeholder reference. If the derivation is produced by a derivation, you must explicitly select `drv.outPath`.
|
*`derivation reference`* must be a string that may contain a regular store path to a derivation, or may be an input placeholder reference.
|
||||||
|
If the derivation is produced by a derivation, you must explicitly select `drv.outPath`.
|
||||||
This primop can be chained arbitrarily deeply.
|
This primop can be chained arbitrarily deeply.
|
||||||
For instance,
|
For instance,
|
||||||
|
|
||||||
|
@ -2150,9 +2157,9 @@ static RegisterPrimOp primop_outputOf({
|
||||||
"out"
|
"out"
|
||||||
```
|
```
|
||||||
|
|
||||||
will return a placeholder for the output of the output of `myDrv`.
|
will return a input placeholder for the output of the output of `myDrv`.
|
||||||
|
|
||||||
This primop corresponds to the `^` sigil for derivable paths, e.g. as part of installable syntax on the command line.
|
This primop corresponds to the `^` sigil for [deriving paths](@docroot@/glossary.md#gloss-deriving-paths), e.g. as part of installable syntax on the command line.
|
||||||
)",
|
)",
|
||||||
.fun = prim_outputOf,
|
.fun = prim_outputOf,
|
||||||
.experimentalFeature = Xp::DynamicDerivations,
|
.experimentalFeature = Xp::DynamicDerivations,
|
||||||
|
|
|
@ -69,7 +69,7 @@ std::optional<std::string> readHead(const Path & path)
|
||||||
|
|
||||||
std::string_view line = output;
|
std::string_view line = output;
|
||||||
line = line.substr(0, line.find("\n"));
|
line = line.substr(0, line.find("\n"));
|
||||||
if (const auto parseResult = git::parseLsRemoteLine(line)) {
|
if (const auto parseResult = git::parseLsRemoteLine(line); parseResult && parseResult->reference == "HEAD") {
|
||||||
switch (parseResult->kind) {
|
switch (parseResult->kind) {
|
||||||
case git::LsRemoteRefLine::Kind::Symbolic:
|
case git::LsRemoteRefLine::Kind::Symbolic:
|
||||||
debug("resolved HEAD ref '%s' for repo '%s'", parseResult->target, path);
|
debug("resolved HEAD ref '%s' for repo '%s'", parseResult->target, path);
|
||||||
|
@ -467,8 +467,14 @@ struct GitInputScheme : InputScheme
|
||||||
url);
|
url);
|
||||||
}
|
}
|
||||||
repoInfo.location = std::filesystem::absolute(url.path);
|
repoInfo.location = std::filesystem::absolute(url.path);
|
||||||
} else
|
} else {
|
||||||
|
if (url.scheme == "file")
|
||||||
|
/* Query parameters are meaningless for file://, but
|
||||||
|
Git interprets them as part of the file name. So get
|
||||||
|
rid of them. */
|
||||||
|
url.query.clear();
|
||||||
repoInfo.location = url;
|
repoInfo.location = url;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a local directory and no ref or revision is
|
// If this is a local directory and no ref or revision is
|
||||||
// given, then allow the use of an unclean working tree.
|
// given, then allow the use of an unclean working tree.
|
||||||
|
@ -613,16 +619,16 @@ struct GitInputScheme : InputScheme
|
||||||
try {
|
try {
|
||||||
auto fetchRef =
|
auto fetchRef =
|
||||||
getAllRefsAttr(input)
|
getAllRefsAttr(input)
|
||||||
? "refs/*"
|
? "refs/*:refs/*"
|
||||||
: input.getRev()
|
: input.getRev()
|
||||||
? input.getRev()->gitRev()
|
? input.getRev()->gitRev()
|
||||||
: ref.compare(0, 5, "refs/") == 0
|
: ref.compare(0, 5, "refs/") == 0
|
||||||
? ref
|
? fmt("%1%:%1%", ref)
|
||||||
: ref == "HEAD"
|
: ref == "HEAD"
|
||||||
? ref
|
? ref
|
||||||
: "refs/heads/" + ref;
|
: fmt("%1%:%1%", "refs/heads/" + ref);
|
||||||
|
|
||||||
repo->fetch(repoUrl.to_string(), fmt("%s:%s", fetchRef, fetchRef), getShallowAttr(input));
|
repo->fetch(repoUrl.to_string(), fetchRef, getShallowAttr(input));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (!std::filesystem::exists(localRefFile)) throw;
|
if (!std::filesystem::exists(localRefFile)) throw;
|
||||||
logError(e.info());
|
logError(e.info());
|
||||||
|
|
|
@ -36,14 +36,6 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Goal::Co DerivationGoal::init() {
|
|
||||||
if (useDerivation) {
|
|
||||||
co_return getDerivation();
|
|
||||||
} else {
|
|
||||||
co_return haveDerivation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivationGoal::DerivationGoal(const StorePath & drvPath,
|
DerivationGoal::DerivationGoal(const StorePath & drvPath,
|
||||||
const OutputsSpec & wantedOutputs, Worker & worker, BuildMode buildMode)
|
const OutputsSpec & wantedOutputs, Worker & worker, BuildMode buildMode)
|
||||||
: Goal(worker, DerivedPath::Built { .drvPath = makeConstantStorePathRef(drvPath), .outputs = wantedOutputs })
|
: Goal(worker, DerivedPath::Built { .drvPath = makeConstantStorePathRef(drvPath), .outputs = wantedOutputs })
|
||||||
|
@ -141,26 +133,19 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::getDerivation()
|
Goal::Co DerivationGoal::init() {
|
||||||
{
|
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
|
if (useDerivation) {
|
||||||
/* The first thing to do is to make sure that the derivation
|
/* The first thing to do is to make sure that the derivation
|
||||||
exists. If it doesn't, it may be created through a
|
exists. If it doesn't, it may be created through a
|
||||||
substitute. */
|
substitute. */
|
||||||
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
|
|
||||||
co_return loadDerivation();
|
if (buildMode != bmNormal || !worker.evalStore.isValidPath(drvPath)) {
|
||||||
|
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(drvPath)));
|
||||||
|
co_await Suspend{};
|
||||||
}
|
}
|
||||||
|
|
||||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(drvPath)));
|
|
||||||
|
|
||||||
co_await Suspend{};
|
|
||||||
co_return loadDerivation();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::loadDerivation()
|
|
||||||
{
|
|
||||||
trace("loading derivation");
|
trace("loading derivation");
|
||||||
|
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
|
@ -185,6 +170,7 @@ Goal::Co DerivationGoal::loadDerivation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(drv);
|
assert(drv);
|
||||||
|
}
|
||||||
|
|
||||||
co_return haveDerivation();
|
co_return haveDerivation();
|
||||||
}
|
}
|
||||||
|
@ -235,6 +221,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{
|
||||||
/* Check what outputs paths are not already valid. */
|
/* Check what outputs paths are not already valid. */
|
||||||
auto [allValid, validOutputs] = checkPathValidity();
|
auto [allValid, validOutputs] = checkPathValidity();
|
||||||
|
|
||||||
|
@ -242,6 +229,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
||||||
if (allValid && buildMode == bmNormal) {
|
if (allValid && buildMode == bmNormal) {
|
||||||
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* We are first going to try to create the invalid output paths
|
/* We are first going to try to create the invalid output paths
|
||||||
through substitutes. If that doesn't work, we'll build
|
through substitutes. If that doesn't work, we'll build
|
||||||
|
@ -268,12 +256,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
||||||
co_return outputsSubstitutionTried();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::outputsSubstitutionTried()
|
|
||||||
{
|
|
||||||
trace("all outputs substituted (maybe)");
|
trace("all outputs substituted (maybe)");
|
||||||
|
|
||||||
assert(!drv->type().isImpure());
|
assert(!drv->type().isImpure());
|
||||||
|
@ -399,84 +382,7 @@ Goal::Co DerivationGoal::gaveUpOnSubstitution()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
if (!waitees.empty()) co_await Suspend{}; /* to prevent hang (no wake-up event) */
|
||||||
co_return inputsRealised();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::repairClosure()
|
|
||||||
{
|
|
||||||
assert(!drv->type().isImpure());
|
|
||||||
|
|
||||||
/* If we're repairing, we now know that our own outputs are valid.
|
|
||||||
Now check whether the other paths in the outputs closure are
|
|
||||||
good. If not, then start derivation goals for the derivations
|
|
||||||
that produced those outputs. */
|
|
||||||
|
|
||||||
/* Get the output closure. */
|
|
||||||
auto outputs = queryDerivationOutputMap();
|
|
||||||
StorePathSet outputClosure;
|
|
||||||
for (auto & i : outputs) {
|
|
||||||
if (!wantedOutputs.contains(i.first)) continue;
|
|
||||||
worker.store.computeFSClosure(i.second, outputClosure);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Filter out our own outputs (which we have already checked). */
|
|
||||||
for (auto & i : outputs)
|
|
||||||
outputClosure.erase(i.second);
|
|
||||||
|
|
||||||
/* Get all dependencies of this derivation so that we know which
|
|
||||||
derivation is responsible for which path in the output
|
|
||||||
closure. */
|
|
||||||
StorePathSet inputClosure;
|
|
||||||
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
|
|
||||||
std::map<StorePath, StorePath> outputsToDrv;
|
|
||||||
for (auto & i : inputClosure)
|
|
||||||
if (i.isDerivation()) {
|
|
||||||
auto depOutputs = worker.store.queryPartialDerivationOutputMap(i, &worker.evalStore);
|
|
||||||
for (auto & j : depOutputs)
|
|
||||||
if (j.second)
|
|
||||||
outputsToDrv.insert_or_assign(*j.second, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check each path (slow!). */
|
|
||||||
for (auto & i : outputClosure) {
|
|
||||||
if (worker.pathContentsGood(i)) continue;
|
|
||||||
printError(
|
|
||||||
"found corrupted or missing path '%s' in the output closure of '%s'",
|
|
||||||
worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
|
|
||||||
auto drvPath2 = outputsToDrv.find(i);
|
|
||||||
if (drvPath2 == outputsToDrv.end())
|
|
||||||
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i, Repair)));
|
|
||||||
else
|
|
||||||
addWaitee(worker.makeGoal(
|
|
||||||
DerivedPath::Built {
|
|
||||||
.drvPath = makeConstantStorePathRef(drvPath2->second),
|
|
||||||
.outputs = OutputsSpec::All { },
|
|
||||||
},
|
|
||||||
bmRepair));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitees.empty()) {
|
|
||||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
|
||||||
} else {
|
|
||||||
co_await Suspend{};
|
|
||||||
co_return closureRepaired();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::closureRepaired()
|
|
||||||
{
|
|
||||||
trace("closure repaired");
|
|
||||||
if (nrFailed > 0)
|
|
||||||
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
|
||||||
worker.store.printStorePath(drvPath));
|
|
||||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Goal::Co DerivationGoal::inputsRealised()
|
|
||||||
{
|
|
||||||
trace("all inputs realised");
|
trace("all inputs realised");
|
||||||
|
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
|
@ -766,6 +672,73 @@ Goal::Co DerivationGoal::tryLocalBuild() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Goal::Co DerivationGoal::repairClosure()
|
||||||
|
{
|
||||||
|
assert(!drv->type().isImpure());
|
||||||
|
|
||||||
|
/* If we're repairing, we now know that our own outputs are valid.
|
||||||
|
Now check whether the other paths in the outputs closure are
|
||||||
|
good. If not, then start derivation goals for the derivations
|
||||||
|
that produced those outputs. */
|
||||||
|
|
||||||
|
/* Get the output closure. */
|
||||||
|
auto outputs = queryDerivationOutputMap();
|
||||||
|
StorePathSet outputClosure;
|
||||||
|
for (auto & i : outputs) {
|
||||||
|
if (!wantedOutputs.contains(i.first)) continue;
|
||||||
|
worker.store.computeFSClosure(i.second, outputClosure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filter out our own outputs (which we have already checked). */
|
||||||
|
for (auto & i : outputs)
|
||||||
|
outputClosure.erase(i.second);
|
||||||
|
|
||||||
|
/* Get all dependencies of this derivation so that we know which
|
||||||
|
derivation is responsible for which path in the output
|
||||||
|
closure. */
|
||||||
|
StorePathSet inputClosure;
|
||||||
|
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
|
||||||
|
std::map<StorePath, StorePath> outputsToDrv;
|
||||||
|
for (auto & i : inputClosure)
|
||||||
|
if (i.isDerivation()) {
|
||||||
|
auto depOutputs = worker.store.queryPartialDerivationOutputMap(i, &worker.evalStore);
|
||||||
|
for (auto & j : depOutputs)
|
||||||
|
if (j.second)
|
||||||
|
outputsToDrv.insert_or_assign(*j.second, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check each path (slow!). */
|
||||||
|
for (auto & i : outputClosure) {
|
||||||
|
if (worker.pathContentsGood(i)) continue;
|
||||||
|
printError(
|
||||||
|
"found corrupted or missing path '%s' in the output closure of '%s'",
|
||||||
|
worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
|
||||||
|
auto drvPath2 = outputsToDrv.find(i);
|
||||||
|
if (drvPath2 == outputsToDrv.end())
|
||||||
|
addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i, Repair)));
|
||||||
|
else
|
||||||
|
addWaitee(worker.makeGoal(
|
||||||
|
DerivedPath::Built {
|
||||||
|
.drvPath = makeConstantStorePathRef(drvPath2->second),
|
||||||
|
.outputs = OutputsSpec::All { },
|
||||||
|
},
|
||||||
|
bmRepair));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitees.empty()) {
|
||||||
|
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||||
|
} else {
|
||||||
|
co_await Suspend{};
|
||||||
|
|
||||||
|
trace("closure repaired");
|
||||||
|
if (nrFailed > 0)
|
||||||
|
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
||||||
|
worker.store.printStorePath(drvPath));
|
||||||
|
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void chmod_(const Path & path, mode_t mode)
|
static void chmod_(const Path & path, mode_t mode)
|
||||||
{
|
{
|
||||||
if (chmod(path.c_str(), mode) == -1)
|
if (chmod(path.c_str(), mode) == -1)
|
||||||
|
@ -1249,7 +1222,7 @@ SingleDrvOutputs DerivationGoal::registerOutputs()
|
||||||
to do anything here.
|
to do anything here.
|
||||||
|
|
||||||
We can only early return when the outputs are known a priori. For
|
We can only early return when the outputs are known a priori. For
|
||||||
floating content-addressed derivations this isn't the case.
|
floating content-addressing derivations this isn't the case.
|
||||||
*/
|
*/
|
||||||
return assertPathValidity();
|
return assertPathValidity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct DerivationGoal : public Goal
|
||||||
/**
|
/**
|
||||||
* Mapping from input derivations + output names to actual store
|
* Mapping from input derivations + output names to actual store
|
||||||
* paths. This is filled in by waiteeDone() as each dependency
|
* paths. This is filled in by waiteeDone() as each dependency
|
||||||
* finishes, before inputsRealised() is reached.
|
* finishes, before `trace("all inputs realised")` is reached.
|
||||||
*/
|
*/
|
||||||
std::map<std::pair<StorePath, std::string>, StorePath> inputDrvOutputs;
|
std::map<std::pair<StorePath, std::string>, StorePath> inputDrvOutputs;
|
||||||
|
|
||||||
|
@ -233,13 +233,8 @@ struct DerivationGoal : public Goal
|
||||||
* The states.
|
* The states.
|
||||||
*/
|
*/
|
||||||
Co init() override;
|
Co init() override;
|
||||||
Co getDerivation();
|
|
||||||
Co loadDerivation();
|
|
||||||
Co haveDerivation();
|
Co haveDerivation();
|
||||||
Co outputsSubstitutionTried();
|
|
||||||
Co gaveUpOnSubstitution();
|
Co gaveUpOnSubstitution();
|
||||||
Co closureRepaired();
|
|
||||||
Co inputsRealised();
|
|
||||||
Co tryToBuild();
|
Co tryToBuild();
|
||||||
virtual Co tryLocalBuild();
|
virtual Co tryLocalBuild();
|
||||||
Co buildDone();
|
Co buildDone();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- Extension of the sql schema for content-addressed derivations.
|
-- Extension of the sql schema for content-addressing derivations.
|
||||||
-- Won't be loaded unless the experimental feature `ca-derivations`
|
-- Won't be loaded unless the experimental feature `ca-derivations`
|
||||||
-- is enabled
|
-- is enabled
|
||||||
|
|
||||||
|
|
|
@ -593,7 +593,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
|
|
||||||
auto drvType = drv.type();
|
auto drvType = drv.type();
|
||||||
|
|
||||||
/* Content-addressed derivations are trustless because their output paths
|
/* Content-addressing derivations are trustless because their output paths
|
||||||
are verified by their content alone, so any derivation is free to
|
are verified by their content alone, so any derivation is free to
|
||||||
try to produce such a path.
|
try to produce such a path.
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@ static DerivationOutput parseDerivationOutput(
|
||||||
} else {
|
} else {
|
||||||
xpSettings.require(Xp::CaDerivations);
|
xpSettings.require(Xp::CaDerivations);
|
||||||
if (pathS != "")
|
if (pathS != "")
|
||||||
throw FormatError("content-addressed derivation output should not specify output path");
|
throw FormatError("content-addressing derivation output should not specify output path");
|
||||||
return DerivationOutput::CAFloating {
|
return DerivationOutput::CAFloating {
|
||||||
.method = std::move(method),
|
.method = std::move(method),
|
||||||
.hashAlgo = std::move(hashAlgo),
|
.hashAlgo = std::move(hashAlgo),
|
||||||
|
|
|
@ -187,7 +187,7 @@ struct DerivationType {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content-addressed derivation types
|
* Content-addressing derivation types
|
||||||
*/
|
*/
|
||||||
struct ContentAddressed {
|
struct ContentAddressed {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -189,7 +189,7 @@ public:
|
||||||
this, SYSTEM, "system",
|
this, SYSTEM, "system",
|
||||||
R"(
|
R"(
|
||||||
The system type of the current Nix installation.
|
The system type of the current Nix installation.
|
||||||
Nix will only build a given [derivation](@docroot@/language/derivations.md) locally when its `system` attribute equals any of the values specified here or in [`extra-platforms`](#conf-extra-platforms).
|
Nix will only build a given [store derivation](@docroot@/glossary.md#gloss-store-derivation) locally when its `system` attribute equals any of the values specified here or in [`extra-platforms`](#conf-extra-platforms).
|
||||||
|
|
||||||
The default value is set when Nix itself is compiled for the system it will run on.
|
The default value is set when Nix itself is compiled for the system it will run on.
|
||||||
The following system types are widely used, as Nix is actively supported on these platforms:
|
The following system types are widely used, as Nix is actively supported on these platforms:
|
||||||
|
@ -825,7 +825,7 @@ public:
|
||||||
R"(
|
R"(
|
||||||
System types of executables that can be run on this machine.
|
System types of executables that can be run on this machine.
|
||||||
|
|
||||||
Nix will only build a given [derivation](@docroot@/language/derivations.md) locally when its `system` attribute equals any of the values specified here or in the [`system` option](#conf-system).
|
Nix will only build a given [store derivation](@docroot@/glossary.md#gloss-store-derivation) locally when its `system` attribute equals any of the values specified here or in the [`system` option](#conf-system).
|
||||||
|
|
||||||
Setting this can be useful to build derivations locally on compatible machines:
|
Setting this can be useful to build derivations locally on compatible machines:
|
||||||
- `i686-linux` executables can be run on `x86_64-linux` machines (set by default)
|
- `i686-linux` executables can be run on `x86_64-linux` machines (set by default)
|
||||||
|
|
|
@ -608,7 +608,7 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(conn->protoVersion) < 27) {
|
if (GET_PROTOCOL_MINOR(conn->protoVersion) < 27) {
|
||||||
warn("the daemon is too old to support content-addressed derivations, please upgrade it to 2.4");
|
warn("the daemon is too old to support content-addressing derivations, please upgrade it to 2.4");
|
||||||
return callback(nullptr);
|
return callback(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -715,7 +715,7 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a store path, return the realisation actually used in the realisation of this path:
|
* Given a store path, return the realisation actually used in the realisation of this path:
|
||||||
* - If the path is a content-addressed derivation, try to resolve it
|
* - If the path is a content-addressing derivation, try to resolve it
|
||||||
* - Otherwise, find one of its derivers
|
* - Otherwise, find one of its derivers
|
||||||
*/
|
*/
|
||||||
std::optional<StorePath> getBuildDerivationPath(const StorePath &);
|
std::optional<StorePath> getBuildDerivationPath(const StorePath &);
|
||||||
|
|
|
@ -800,7 +800,7 @@ void LocalDerivationGoal::startBuilder()
|
||||||
out. */
|
out. */
|
||||||
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
|
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
|
||||||
/* If the name isn't known a priori (i.e. floating
|
/* If the name isn't known a priori (i.e. floating
|
||||||
content-addressed derivation), the temporary location we use
|
content-addressing derivation), the temporary location we use
|
||||||
should be fresh. Freshness means it is impossible that the path
|
should be fresh. Freshness means it is impossible that the path
|
||||||
is already in the sandbox, so we don't need to worry about
|
is already in the sandbox, so we don't need to worry about
|
||||||
removing it. */
|
removing it. */
|
||||||
|
@ -2291,7 +2291,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
||||||
to do anything here.
|
to do anything here.
|
||||||
|
|
||||||
We can only early return when the outputs are known a priori. For
|
We can only early return when the outputs are known a priori. For
|
||||||
floating content-addressed derivations this isn't the case.
|
floating content-addressing derivations this isn't the case.
|
||||||
*/
|
*/
|
||||||
if (hook)
|
if (hook)
|
||||||
return DerivationGoal::registerOutputs();
|
return DerivationGoal::registerOutputs();
|
||||||
|
|
|
@ -130,7 +130,7 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||||
* rewrite after the build. Otherwise the regular predetermined paths are
|
* rewrite after the build. Otherwise the regular predetermined paths are
|
||||||
* put here.
|
* put here.
|
||||||
*
|
*
|
||||||
* - Floating content-addressed derivations do not know their final build
|
* - Floating content-addressing derivations do not know their final build
|
||||||
* output paths until the outputs are hashed, so random locations are
|
* output paths until the outputs are hashed, so random locations are
|
||||||
* used, and then renamed. The randomness helps guard against hidden
|
* used, and then renamed. The randomness helps guard against hidden
|
||||||
* self-references.
|
* self-references.
|
||||||
|
|
|
@ -6,10 +6,52 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
class BLAKE3HashTest : public virtual ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We set these in tests rather than the regular globals so we don't have
|
||||||
|
* to worry about race conditions if the tests run concurrently.
|
||||||
|
*/
|
||||||
|
ExperimentalFeatureSettings mockXpSettings;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
mockXpSettings.set("experimental-features", "blake3-hashes");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* hashString
|
* hashString
|
||||||
* --------------------------------------------------------------------------*/
|
* --------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes1) {
|
||||||
|
// values taken from: https://tools.ietf.org/html/rfc4634
|
||||||
|
auto s = "abc";
|
||||||
|
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
|
||||||
|
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||||
|
"blake3:6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes2) {
|
||||||
|
// values taken from: https://tools.ietf.org/html/rfc4634
|
||||||
|
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||||
|
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
|
||||||
|
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||||
|
"blake3:c19012cc2aaf0dc3d8e5c45a1b79114d2df42abb2a410bf54be09e891af06ff8");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes3) {
|
||||||
|
// values taken from: https://www.ietf.org/archive/id/draft-aumasson-blake3-00.txt
|
||||||
|
auto s = "IETF";
|
||||||
|
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
|
||||||
|
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
|
||||||
|
"blake3:83a2de1ee6f4e6ab686889248f4ec0cf4cc5709446a682ffd1cbb4d6165181e2");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(hashString, testKnownMD5Hashes1) {
|
TEST(hashString, testKnownMD5Hashes1) {
|
||||||
// values taken from: https://tools.ietf.org/html/rfc1321
|
// values taken from: https://tools.ietf.org/html/rfc1321
|
||||||
auto s1 = "";
|
auto s1 = "";
|
||||||
|
|
|
@ -24,7 +24,7 @@ struct ExperimentalFeatureDetails
|
||||||
* feature, we either have no issue at all if few features are not added
|
* feature, we either have no issue at all if few features are not added
|
||||||
* at the end of the list, or a proper merge conflict if they are.
|
* at the end of the list, or a proper merge conflict if they are.
|
||||||
*/
|
*/
|
||||||
constexpr size_t numXpFeatures = 1 + static_cast<size_t>(Xp::PipeOperators);
|
constexpr size_t numXpFeatures = 1 + static_cast<size_t>(Xp::BLAKE3Hashes);
|
||||||
|
|
||||||
constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails = {{
|
constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails = {{
|
||||||
{
|
{
|
||||||
|
@ -302,6 +302,14 @@ constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails
|
||||||
)",
|
)",
|
||||||
.trackingUrl = "https://github.com/NixOS/nix/milestone/55",
|
.trackingUrl = "https://github.com/NixOS/nix/milestone/55",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.tag = Xp::BLAKE3Hashes,
|
||||||
|
.name = "blake3-hashes",
|
||||||
|
.description = R"(
|
||||||
|
Enables support for BLAKE3 hashes.
|
||||||
|
)",
|
||||||
|
.trackingUrl = "",
|
||||||
|
},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum struct ExperimentalFeature
|
||||||
MountedSSHStore,
|
MountedSSHStore,
|
||||||
VerifiedFetches,
|
VerifiedFetches,
|
||||||
PipeOperators,
|
PipeOperators,
|
||||||
|
BLAKE3Hashes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <blake3.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
#include "args.hh"
|
#include "args.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
|
#include "config.hh"
|
||||||
#include "split.hh"
|
#include "split.hh"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -20,6 +22,7 @@ namespace nix {
|
||||||
|
|
||||||
static size_t regularHashSize(HashAlgorithm type) {
|
static size_t regularHashSize(HashAlgorithm type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case HashAlgorithm::BLAKE3: return blake3HashSize;
|
||||||
case HashAlgorithm::MD5: return md5HashSize;
|
case HashAlgorithm::MD5: return md5HashSize;
|
||||||
case HashAlgorithm::SHA1: return sha1HashSize;
|
case HashAlgorithm::SHA1: return sha1HashSize;
|
||||||
case HashAlgorithm::SHA256: return sha256HashSize;
|
case HashAlgorithm::SHA256: return sha256HashSize;
|
||||||
|
@ -29,12 +32,15 @@ static size_t regularHashSize(HashAlgorithm type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::set<std::string> hashAlgorithms = {"md5", "sha1", "sha256", "sha512" };
|
const std::set<std::string> hashAlgorithms = {"blake3", "md5", "sha1", "sha256", "sha512" };
|
||||||
|
|
||||||
const std::set<std::string> hashFormats = {"base64", "nix32", "base16", "sri" };
|
const std::set<std::string> hashFormats = {"base64", "nix32", "base16", "sri" };
|
||||||
|
|
||||||
Hash::Hash(HashAlgorithm algo) : algo(algo)
|
Hash::Hash(HashAlgorithm algo, const ExperimentalFeatureSettings & xpSettings) : algo(algo)
|
||||||
{
|
{
|
||||||
|
if (algo == HashAlgorithm::BLAKE3) {
|
||||||
|
xpSettings.require(Xp::BLAKE3Hashes);
|
||||||
|
}
|
||||||
hashSize = regularHashSize(algo);
|
hashSize = regularHashSize(algo);
|
||||||
assert(hashSize <= maxHashSize);
|
assert(hashSize <= maxHashSize);
|
||||||
memset(hash, 0, maxHashSize);
|
memset(hash, 0, maxHashSize);
|
||||||
|
@ -284,6 +290,7 @@ Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashAlgorithm> ha
|
||||||
|
|
||||||
union Ctx
|
union Ctx
|
||||||
{
|
{
|
||||||
|
blake3_hasher blake3;
|
||||||
MD5_CTX md5;
|
MD5_CTX md5;
|
||||||
SHA_CTX sha1;
|
SHA_CTX sha1;
|
||||||
SHA256_CTX sha256;
|
SHA256_CTX sha256;
|
||||||
|
@ -293,7 +300,8 @@ union Ctx
|
||||||
|
|
||||||
static void start(HashAlgorithm ha, Ctx & ctx)
|
static void start(HashAlgorithm ha, Ctx & ctx)
|
||||||
{
|
{
|
||||||
if (ha == HashAlgorithm::MD5) MD5_Init(&ctx.md5);
|
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_init(&ctx.blake3);
|
||||||
|
else if (ha == HashAlgorithm::MD5) MD5_Init(&ctx.md5);
|
||||||
else if (ha == HashAlgorithm::SHA1) SHA1_Init(&ctx.sha1);
|
else if (ha == HashAlgorithm::SHA1) SHA1_Init(&ctx.sha1);
|
||||||
else if (ha == HashAlgorithm::SHA256) SHA256_Init(&ctx.sha256);
|
else if (ha == HashAlgorithm::SHA256) SHA256_Init(&ctx.sha256);
|
||||||
else if (ha == HashAlgorithm::SHA512) SHA512_Init(&ctx.sha512);
|
else if (ha == HashAlgorithm::SHA512) SHA512_Init(&ctx.sha512);
|
||||||
|
@ -303,7 +311,8 @@ static void start(HashAlgorithm ha, Ctx & ctx)
|
||||||
static void update(HashAlgorithm ha, Ctx & ctx,
|
static void update(HashAlgorithm ha, Ctx & ctx,
|
||||||
std::string_view data)
|
std::string_view data)
|
||||||
{
|
{
|
||||||
if (ha == HashAlgorithm::MD5) MD5_Update(&ctx.md5, data.data(), data.size());
|
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_update(&ctx.blake3, data.data(), data.size());
|
||||||
|
else if (ha == HashAlgorithm::MD5) MD5_Update(&ctx.md5, data.data(), data.size());
|
||||||
else if (ha == HashAlgorithm::SHA1) SHA1_Update(&ctx.sha1, data.data(), data.size());
|
else if (ha == HashAlgorithm::SHA1) SHA1_Update(&ctx.sha1, data.data(), data.size());
|
||||||
else if (ha == HashAlgorithm::SHA256) SHA256_Update(&ctx.sha256, data.data(), data.size());
|
else if (ha == HashAlgorithm::SHA256) SHA256_Update(&ctx.sha256, data.data(), data.size());
|
||||||
else if (ha == HashAlgorithm::SHA512) SHA512_Update(&ctx.sha512, data.data(), data.size());
|
else if (ha == HashAlgorithm::SHA512) SHA512_Update(&ctx.sha512, data.data(), data.size());
|
||||||
|
@ -312,24 +321,24 @@ static void update(HashAlgorithm ha, Ctx & ctx,
|
||||||
|
|
||||||
static void finish(HashAlgorithm ha, Ctx & ctx, unsigned char * hash)
|
static void finish(HashAlgorithm ha, Ctx & ctx, unsigned char * hash)
|
||||||
{
|
{
|
||||||
if (ha == HashAlgorithm::MD5) MD5_Final(hash, &ctx.md5);
|
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_finalize(&ctx.blake3, hash, BLAKE3_OUT_LEN);
|
||||||
|
else if (ha == HashAlgorithm::MD5) MD5_Final(hash, &ctx.md5);
|
||||||
else if (ha == HashAlgorithm::SHA1) SHA1_Final(hash, &ctx.sha1);
|
else if (ha == HashAlgorithm::SHA1) SHA1_Final(hash, &ctx.sha1);
|
||||||
else if (ha == HashAlgorithm::SHA256) SHA256_Final(hash, &ctx.sha256);
|
else if (ha == HashAlgorithm::SHA256) SHA256_Final(hash, &ctx.sha256);
|
||||||
else if (ha == HashAlgorithm::SHA512) SHA512_Final(hash, &ctx.sha512);
|
else if (ha == HashAlgorithm::SHA512) SHA512_Final(hash, &ctx.sha512);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hash hashString(
|
||||||
Hash hashString(HashAlgorithm ha, std::string_view s)
|
HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings)
|
||||||
{
|
{
|
||||||
Ctx ctx;
|
Ctx ctx;
|
||||||
Hash hash(ha);
|
Hash hash(ha, xpSettings);
|
||||||
start(ha, ctx);
|
start(ha, ctx);
|
||||||
update(ha, ctx, s);
|
update(ha, ctx, s);
|
||||||
finish(ha, ctx, hash.hash);
|
finish(ha, ctx, hash.hash);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hash hashFile(HashAlgorithm ha, const Path & path)
|
Hash hashFile(HashAlgorithm ha, const Path & path)
|
||||||
{
|
{
|
||||||
HashSink sink(ha);
|
HashSink sink(ha);
|
||||||
|
@ -426,6 +435,7 @@ std::string_view printHashFormat(HashFormat HashFormat)
|
||||||
|
|
||||||
std::optional<HashAlgorithm> parseHashAlgoOpt(std::string_view s)
|
std::optional<HashAlgorithm> parseHashAlgoOpt(std::string_view s)
|
||||||
{
|
{
|
||||||
|
if (s == "blake3") return HashAlgorithm::BLAKE3;
|
||||||
if (s == "md5") return HashAlgorithm::MD5;
|
if (s == "md5") return HashAlgorithm::MD5;
|
||||||
if (s == "sha1") return HashAlgorithm::SHA1;
|
if (s == "sha1") return HashAlgorithm::SHA1;
|
||||||
if (s == "sha256") return HashAlgorithm::SHA256;
|
if (s == "sha256") return HashAlgorithm::SHA256;
|
||||||
|
@ -439,12 +449,13 @@ HashAlgorithm parseHashAlgo(std::string_view s)
|
||||||
if (opt_h)
|
if (opt_h)
|
||||||
return *opt_h;
|
return *opt_h;
|
||||||
else
|
else
|
||||||
throw UsageError("unknown hash algorithm '%1%', expect 'md5', 'sha1', 'sha256', or 'sha512'", s);
|
throw UsageError("unknown hash algorithm '%1%', expect 'blake3', 'md5', 'sha1', 'sha256', or 'sha512'", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view printHashAlgo(HashAlgorithm ha)
|
std::string_view printHashAlgo(HashAlgorithm ha)
|
||||||
{
|
{
|
||||||
switch (ha) {
|
switch (ha) {
|
||||||
|
case HashAlgorithm::BLAKE3: return "blake3";
|
||||||
case HashAlgorithm::MD5: return "md5";
|
case HashAlgorithm::MD5: return "md5";
|
||||||
case HashAlgorithm::SHA1: return "sha1";
|
case HashAlgorithm::SHA1: return "sha1";
|
||||||
case HashAlgorithm::SHA256: return "sha256";
|
case HashAlgorithm::SHA256: return "sha256";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
|
#include "config.hh"
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
#include "serialise.hh"
|
#include "serialise.hh"
|
||||||
#include "file-system.hh"
|
#include "file-system.hh"
|
||||||
|
@ -11,9 +12,9 @@ namespace nix {
|
||||||
MakeError(BadHash, Error);
|
MakeError(BadHash, Error);
|
||||||
|
|
||||||
|
|
||||||
enum struct HashAlgorithm : char { MD5 = 42, SHA1, SHA256, SHA512 };
|
enum struct HashAlgorithm : char { MD5 = 42, SHA1, SHA256, SHA512, BLAKE3 };
|
||||||
|
|
||||||
|
|
||||||
|
const int blake3HashSize = 32;
|
||||||
const int md5HashSize = 16;
|
const int md5HashSize = 16;
|
||||||
const int sha1HashSize = 20;
|
const int sha1HashSize = 20;
|
||||||
const int sha256HashSize = 32;
|
const int sha256HashSize = 32;
|
||||||
|
@ -52,7 +53,7 @@ struct Hash
|
||||||
/**
|
/**
|
||||||
* Create a zero-filled hash object.
|
* Create a zero-filled hash object.
|
||||||
*/
|
*/
|
||||||
explicit Hash(HashAlgorithm algo);
|
explicit Hash(HashAlgorithm algo, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the hash from a string representation in the format
|
* Parse the hash from a string representation in the format
|
||||||
|
@ -157,7 +158,7 @@ std::string printHash16or32(const Hash & hash);
|
||||||
/**
|
/**
|
||||||
* Compute the hash of the given string.
|
* Compute the hash of the given string.
|
||||||
*/
|
*/
|
||||||
Hash hashString(HashAlgorithm ha, std::string_view s);
|
Hash hashString(HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the hash of the given file, hashing its contents directly.
|
* Compute the hash of the given file, hashing its contents directly.
|
||||||
|
|
|
@ -62,6 +62,12 @@ elif host_machine.system() == 'sunos'
|
||||||
deps_other += [socket, network_service_library]
|
deps_other += [socket, network_service_library]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
blake3 = dependency(
|
||||||
|
'libblake3',
|
||||||
|
version: '>= 1.5.5',
|
||||||
|
)
|
||||||
|
deps_private += blake3
|
||||||
|
|
||||||
boost = dependency(
|
boost = dependency(
|
||||||
'boost',
|
'boost',
|
||||||
modules : ['context', 'coroutine'],
|
modules : ['context', 'coroutine'],
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
boost,
|
boost,
|
||||||
brotli,
|
brotli,
|
||||||
libarchive,
|
libarchive,
|
||||||
|
libblake3,
|
||||||
libcpuid,
|
libcpuid,
|
||||||
libsodium,
|
libsodium,
|
||||||
nlohmann_json,
|
nlohmann_json,
|
||||||
|
@ -42,6 +43,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
brotli
|
brotli
|
||||||
|
libblake3
|
||||||
libsodium
|
libsodium
|
||||||
openssl
|
openssl
|
||||||
] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid;
|
] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid;
|
||||||
|
|
|
@ -252,7 +252,7 @@ static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput,
|
||||||
return store->queryDerivationOutputs(storePath);
|
return store->queryDerivationOutputs(storePath);
|
||||||
for (auto & i : drv.outputsAndOptPaths(*store)) {
|
for (auto & i : drv.outputsAndOptPaths(*store)) {
|
||||||
if (!i.second.second)
|
if (!i.second.second)
|
||||||
throw UsageError("Cannot use output path of floating content-addressed derivation until we know what it is (e.g. by building it)");
|
throw UsageError("Cannot use output path of floating content-addressing derivation until we know what it is (e.g. by building it)");
|
||||||
outputs.insert(*i.second.second);
|
outputs.insert(*i.second.second);
|
||||||
}
|
}
|
||||||
return outputs;
|
return outputs;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// FIXME: integrate this with nix path-info?
|
// FIXME: integrate this with `nix path-info`?
|
||||||
// FIXME: rename to 'nix store derivation show' or 'nix debug derivation show'?
|
// FIXME: rename to 'nix store derivation show'?
|
||||||
|
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
|
|
|
@ -62,8 +62,8 @@ R""(
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
`nix search` searches [*installable*](./nix.md#installables) (which can be evaluated, that is, a
|
`nix search` searches [*installable*](./nix.md#installables) that can be evaluated, that is, a
|
||||||
flake or Nix expression, but not a store path or store derivation path) for packages whose name or description matches all of the
|
flake or Nix expression, but not a [store path] or [deriving path]) for packages whose name or description matches all of the
|
||||||
regular expressions *regex*. For each matching package, It prints the
|
regular expressions *regex*. For each matching package, It prints the
|
||||||
full attribute name (from the root of the [installable](./nix.md#installables)), the version
|
full attribute name (from the root of the [installable](./nix.md#installables)), the version
|
||||||
and the `meta.description` field, highlighting the substrings that
|
and the `meta.description` field, highlighting the substrings that
|
||||||
|
@ -75,6 +75,9 @@ it avoids highlighting the entire name and description of every package.
|
||||||
> Note that in this context, `^` is the regex character to match the beginning of a string, *not* the delimiter for
|
> Note that in this context, `^` is the regex character to match the beginning of a string, *not* the delimiter for
|
||||||
> [selecting a derivation output](@docroot@/command-ref/new-cli/nix.md#derivation-output-selection).
|
> [selecting a derivation output](@docroot@/command-ref/new-cli/nix.md#derivation-output-selection).
|
||||||
|
|
||||||
|
[store path]: @docroot@/glossary.md#gloss-store-path
|
||||||
|
[deriving path]: @docroot@/glossary.md#gloss-deriving-path
|
||||||
|
|
||||||
# Flake output attributes
|
# Flake output attributes
|
||||||
|
|
||||||
If no flake output attribute is given, `nix search` searches for
|
If no flake output attribute is given, `nix search` searches for
|
||||||
|
|
|
@ -16,7 +16,7 @@ in
|
||||||
{
|
{
|
||||||
seed ? 0,
|
seed ? 0,
|
||||||
}:
|
}:
|
||||||
# A simple content-addressed derivation.
|
# A simple content-addressing derivation.
|
||||||
# The derivation can be arbitrarily modified by passing a different `seed`,
|
# The derivation can be arbitrarily modified by passing a different `seed`,
|
||||||
# but the output will always be the same
|
# but the output will always be the same
|
||||||
rec {
|
rec {
|
||||||
|
|
|
@ -12,7 +12,7 @@ drvPath2=$(nix derivation add < "$TEST_HOME"/simple.json)
|
||||||
|
|
||||||
[[ "$drvPath" = "$drvPath2" ]]
|
[[ "$drvPath" = "$drvPath2" ]]
|
||||||
|
|
||||||
# Content-addressed derivations can be renamed.
|
# Content-addressing derivations can be renamed.
|
||||||
jq '.name = "foo"' < "$TEST_HOME"/simple.json > "$TEST_HOME"/foo.json
|
jq '.name = "foo"' < "$TEST_HOME"/simple.json > "$TEST_HOME"/foo.json
|
||||||
drvPath3=$(nix derivation add --dry-run < "$TEST_HOME"/foo.json)
|
drvPath3=$(nix derivation add --dry-run < "$TEST_HOME"/foo.json)
|
||||||
# With --dry-run nothing is actually written
|
# With --dry-run nothing is actually written
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
with import ./config.nix;
|
with import ./config.nix;
|
||||||
|
|
||||||
# A simple content-addressed derivation.
|
# A simple content-addressing derivation.
|
||||||
# The derivation can be arbitrarily modified by passing a different `seed`,
|
# The derivation can be arbitrarily modified by passing a different `seed`,
|
||||||
# but the output will always be the same
|
# but the output will always be the same
|
||||||
rec {
|
rec {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
with import ./config.nix;
|
with import ./config.nix;
|
||||||
|
|
||||||
# A simple content-addressed derivation.
|
# A simple content-addressing derivation.
|
||||||
# The derivation can be arbitrarily modified by passing a different `seed`,
|
# The derivation can be arbitrarily modified by passing a different `seed`,
|
||||||
# but the output will always be the same
|
# but the output will always be the same
|
||||||
rec {
|
rec {
|
||||||
|
|
|
@ -6,14 +6,14 @@ requireGit
|
||||||
|
|
||||||
create_flake() {
|
create_flake() {
|
||||||
local flakeDir="$1"
|
local flakeDir="$1"
|
||||||
createGitRepo $flakeDir
|
createGitRepo "$flakeDir"
|
||||||
cat > $flakeDir/flake.nix <<EOF
|
cat > "$flakeDir/flake.nix" <<EOF
|
||||||
{
|
{
|
||||||
outputs = { self }: { x = 2; };
|
outputs = { self }: { x = 2; };
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
git -C $flakeDir add flake.nix
|
git -C "$flakeDir" add flake.nix
|
||||||
git -C $flakeDir commit -m Initial
|
git -C "$flakeDir" commit -m Initial
|
||||||
}
|
}
|
||||||
|
|
||||||
test_symlink_points_to_flake() {
|
test_symlink_points_to_flake() {
|
||||||
|
@ -34,15 +34,15 @@ test_symlink_points_to_flake_in_subdir
|
||||||
|
|
||||||
test_symlink_points_to_dir_in_repo() {
|
test_symlink_points_to_dir_in_repo() {
|
||||||
local repoDir="$TEST_ROOT/flake1"
|
local repoDir="$TEST_ROOT/flake1"
|
||||||
createGitRepo $repoDir
|
createGitRepo "$repoDir"
|
||||||
mkdir -p "$repoDir/subdir"
|
mkdir -p "$repoDir/subdir"
|
||||||
cat > $repoDir/subdir/flake.nix <<EOF
|
cat > "$repoDir/subdir/flake.nix" <<EOF
|
||||||
{
|
{
|
||||||
outputs = { self }: { x = 2; };
|
outputs = { self }: { x = 2; };
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
git -C $repoDir add subdir/flake.nix
|
git -C "$repoDir" add subdir/flake.nix
|
||||||
git -C $repoDir commit -m Initial
|
git -C "$repoDir" commit -m Initial
|
||||||
ln -sn "$TEST_ROOT/flake1/subdir" "$TEST_ROOT/flake1_sym"
|
ln -sn "$TEST_ROOT/flake1/subdir" "$TEST_ROOT/flake1_sym"
|
||||||
[[ $(nix eval "$TEST_ROOT/flake1_sym#x") = 2 ]]
|
[[ $(nix eval "$TEST_ROOT/flake1_sym#x") = 2 ]]
|
||||||
rm -rf "$TEST_ROOT/flake1" "$TEST_ROOT/flake1_sym"
|
rm -rf "$TEST_ROOT/flake1" "$TEST_ROOT/flake1_sym"
|
||||||
|
@ -51,22 +51,22 @@ test_symlink_points_to_dir_in_repo
|
||||||
|
|
||||||
test_symlink_from_repo_to_another() {
|
test_symlink_from_repo_to_another() {
|
||||||
local repoDir="$TEST_ROOT/repo1"
|
local repoDir="$TEST_ROOT/repo1"
|
||||||
createGitRepo $repoDir
|
createGitRepo "$repoDir"
|
||||||
echo "Hello" > $repoDir/file
|
echo "Hello" > "$repoDir/file"
|
||||||
mkdir $repoDir/subdir
|
mkdir "$repoDir/subdir"
|
||||||
cat > $repoDir/subdir/flake.nix <<EOF
|
cat > "$repoDir/subdir/flake.nix" <<EOF
|
||||||
{
|
{
|
||||||
outputs = { self }: { x = builtins.readFile ../file; };
|
outputs = { self }: { x = builtins.readFile ../file; };
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
git -C $repoDir add subdir/flake.nix file
|
git -C "$repoDir" add subdir/flake.nix file
|
||||||
git -C $repoDir commit -m Initial
|
git -C "$repoDir" commit -m Initial
|
||||||
[[ $(nix eval "$TEST_ROOT/repo1/subdir#x") == \"Hello\\n\" ]]
|
[[ $(nix eval "$TEST_ROOT/repo1/subdir#x") == \"Hello\\n\" ]]
|
||||||
|
|
||||||
local repo2Dir="$TEST_ROOT/repo2"
|
local repo2Dir="$TEST_ROOT/repo2"
|
||||||
createGitRepo $repo2Dir
|
createGitRepo "$repo2Dir"
|
||||||
ln -sn "$repoDir/subdir" "$repo2Dir/flake1_sym"
|
ln -sn "$repoDir/subdir" "$repo2Dir/flake1_sym"
|
||||||
echo "World" > $repo2Dir/file
|
echo "World" > "$repo2Dir/file"
|
||||||
git -C "$repo2Dir" add flake1_sym file
|
git -C "$repo2Dir" add flake1_sym file
|
||||||
git -C "$repo2Dir" commit -m Initial
|
git -C "$repo2Dir" commit -m Initial
|
||||||
[[ $(nix eval "$repo2Dir/flake1_sym#x") == \"Hello\\n\" ]]
|
[[ $(nix eval "$repo2Dir/flake1_sym#x") == \"Hello\\n\" ]]
|
||||||
|
|
0
tests/functional/git-hashing/fixed.sh
Normal file → Executable file
0
tests/functional/git-hashing/fixed.sh
Normal file → Executable file
2
tests/functional/git-hashing/simple.sh
Normal file → Executable file
2
tests/functional/git-hashing/simple.sh
Normal file → Executable file
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
source common.sh
|
source common.sh
|
||||||
|
|
||||||
repo="$TEST_ROOT/scratch"
|
repo="$TEST_ROOT/scratch"
|
||||||
|
|
|
@ -25,7 +25,7 @@ done
|
||||||
|
|
||||||
# FIXME: we don't know whether we built the manpages, so we can't
|
# FIXME: we don't know whether we built the manpages, so we can't
|
||||||
# reliably test them here.
|
# reliably test them here.
|
||||||
if false; then
|
skipTest "we don't know whether we built the manpages, so we can't reliably test them here."
|
||||||
|
|
||||||
# test help output
|
# test help output
|
||||||
|
|
||||||
|
@ -74,5 +74,3 @@ nix-daemon --help
|
||||||
nix-hash --help
|
nix-hash --help
|
||||||
nix-instantiate --help
|
nix-instantiate --help
|
||||||
nix-prefetch-url --help
|
nix-prefetch-url --help
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue