mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-30 01:26:15 +02:00
Merge branch 'master' into read-only-local-store
This commit is contained in:
commit
32404292a3
79 changed files with 752 additions and 501 deletions
|
@ -48,13 +48,13 @@ If the build passes and is deterministic, Nix will exit with a status
|
||||||
code of 0:
|
code of 0:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A stable
|
$ nix-build ./deterministic.nix --attr stable
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
|
/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv
|
||||||
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
||||||
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
||||||
|
|
||||||
$ nix-build ./deterministic.nix -A stable --check
|
$ nix-build ./deterministic.nix --attr stable --check
|
||||||
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'...
|
||||||
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
/nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable
|
||||||
```
|
```
|
||||||
|
@ -63,13 +63,13 @@ If the build is not deterministic, Nix will exit with a status code of
|
||||||
1:
|
1:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A unstable
|
$ nix-build ./deterministic.nix --attr unstable
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
|
/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv
|
||||||
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
|
/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable
|
||||||
|
|
||||||
$ nix-build ./deterministic.nix -A unstable --check
|
$ nix-build ./deterministic.nix --attr unstable --check
|
||||||
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
||||||
not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
|
not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs
|
||||||
|
@ -89,7 +89,7 @@ Using `--check` with `--keep-failed` will cause Nix to keep the second
|
||||||
build's output in a special, `.check` path:
|
build's output in a special, `.check` path:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build ./deterministic.nix -A unstable --check --keep-failed
|
$ nix-build ./deterministic.nix --attr unstable --check --keep-failed
|
||||||
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'...
|
||||||
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
|
note: keeping build directory '/tmp/nix-build-unstable.drv-0'
|
||||||
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may
|
||||||
|
|
|
@ -90,7 +90,7 @@ Then, restart the `nix-daemon`.
|
||||||
Build any derivation, for example:
|
Build any derivation, for example:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -E '(import <nixpkgs> {}).writeText "example" (builtins.toString builtins.currentTime)'
|
$ nix-build --expr '(import <nixpkgs> {}).writeText "example" (builtins.toString builtins.currentTime)'
|
||||||
this derivation will be built:
|
this derivation will be built:
|
||||||
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
|
/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
|
||||||
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
|
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
|
||||||
|
|
|
@ -76,7 +76,7 @@ except for `--arg` and `--attr` / `-A` which are passed to `nix-instantiate`.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A firefox
|
$ nix-build '<nixpkgs>' --attr firefox
|
||||||
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
|
store derivation is /nix/store/qybprl8sz2lc...-firefox-1.5.0.7.drv
|
||||||
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
|
/nix/store/d18hyl92g30l...-firefox-1.5.0.7
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ If a derivation has multiple outputs, `nix-build` will build the default
|
||||||
(first) output. You can also build all outputs:
|
(first) output. You can also build all outputs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A openssl.all
|
$ nix-build '<nixpkgs>' --attr openssl.all
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a symlink for each output named `result-outputname`.
|
This will create a symlink for each output named `result-outputname`.
|
||||||
|
@ -101,7 +101,7 @@ outputs `out`, `bin` and `man`, `nix-build` will create symlinks
|
||||||
specific output:
|
specific output:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A openssl.man
|
$ nix-build '<nixpkgs>' --attr openssl.man
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a symlink `result-man`.
|
This will create a symlink `result-man`.
|
||||||
|
@ -109,7 +109,7 @@ This will create a symlink `result-man`.
|
||||||
Build a Nix expression given on the command line:
|
Build a Nix expression given on the command line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -E 'with import <nixpkgs> { }; runCommand "foo" { } "echo bar > $out"'
|
$ nix-build --expr 'with import <nixpkgs> { }; runCommand "foo" { } "echo bar > $out"'
|
||||||
$ cat ./result
|
$ cat ./result
|
||||||
bar
|
bar
|
||||||
```
|
```
|
||||||
|
@ -118,5 +118,5 @@ Build the GNU Hello package from the latest revision of the master
|
||||||
branch of Nixpkgs:
|
branch of Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz -A hello
|
$ nix-build https://github.com/NixOS/nixpkgs/archive/master.tar.gz --attr hello
|
||||||
```
|
```
|
||||||
|
|
|
@ -52,6 +52,12 @@ The list of subscribed channels is stored in `~/.nix-channels`.
|
||||||
|
|
||||||
{{#include ./env-common.md}}
|
{{#include ./env-common.md}}
|
||||||
|
|
||||||
|
# Files
|
||||||
|
|
||||||
|
`nix-channel` operates on the following files.
|
||||||
|
|
||||||
|
{{#include ./files/channels.md}}
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
||||||
|
@ -59,18 +65,18 @@ To subscribe to the Nixpkgs channel and install the GNU Hello package:
|
||||||
```console
|
```console
|
||||||
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
||||||
$ nix-channel --update
|
$ nix-channel --update
|
||||||
$ nix-env -iA nixpkgs.hello
|
$ nix-env --install --attr nixpkgs.hello
|
||||||
```
|
```
|
||||||
|
|
||||||
You can revert channel updates using `--rollback`:
|
You can revert channel updates using `--rollback`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
|
$ nix-instantiate --eval --expr '(import <nixpkgs> {}).lib.version'
|
||||||
"14.04.527.0e935f1"
|
"14.04.527.0e935f1"
|
||||||
|
|
||||||
$ nix-channel --rollback
|
$ nix-channel --rollback
|
||||||
switching from generation 483 to 482
|
switching from generation 483 to 482
|
||||||
|
|
||||||
$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
|
$ nix-instantiate --eval --expr '(import <nixpkgs> {}).lib.version'
|
||||||
"14.04.526.dbadfad"
|
"14.04.526.dbadfad"
|
||||||
```
|
```
|
||||||
|
|
|
@ -87,5 +87,5 @@ environment:
|
||||||
```console
|
```console
|
||||||
$ nix-copy-closure --from alice@itchy.labs \
|
$ nix-copy-closure --from alice@itchy.labs \
|
||||||
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||||
$ nix-env -i /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
$ nix-env --install /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||||
```
|
```
|
||||||
|
|
|
@ -49,7 +49,7 @@ These pages can be viewed offline:
|
||||||
|
|
||||||
# Selectors
|
# Selectors
|
||||||
|
|
||||||
Several commands, such as `nix-env -q` and `nix-env -i`, take a list of
|
Several commands, such as `nix-env --query ` and `nix-env --install `, take a list of
|
||||||
arguments that specify the packages on which to operate. These are
|
arguments that specify the packages on which to operate. These are
|
||||||
extended regular expressions that must match the entire name of the
|
extended regular expressions that must match the entire name of the
|
||||||
package. (For details on regular expressions, see **regex**(7).) The match is
|
package. (For details on regular expressions, see **regex**(7).) The match is
|
||||||
|
@ -83,6 +83,8 @@ match. Here are some examples:
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
|
|
||||||
|
`nix-env` operates on the following files.
|
||||||
|
|
||||||
{{#include ./files/default-nix-expression.md}}
|
{{#include ./files/default-nix-expression.md}}
|
||||||
|
|
||||||
{{#include ./files/profiles.md}}
|
{{#include ./files/profiles.md}}
|
||||||
|
|
|
@ -41,6 +41,6 @@ $ nix-env --delete-generations 30d
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -p other_profile --delete-generations old
|
$ nix-env --profile other_profile --delete-generations old
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ a number of possible ways:
|
||||||
then the derivation with the highest version will be installed.
|
then the derivation with the highest version will be installed.
|
||||||
|
|
||||||
You can force the installation of multiple derivations with the same
|
You can force the installation of multiple derivations with the same
|
||||||
name by being specific about the versions. For instance, `nix-env -i
|
name by being specific about the versions. For instance, `nix-env --install
|
||||||
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
|
gcc-3.3.6 gcc-4.1.1` will install both version of GCC (and will
|
||||||
probably cause a user environment conflict\!).
|
probably cause a user environment conflict\!).
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ a number of possible ways:
|
||||||
paths* that select attributes from the top-level Nix
|
paths* that select attributes from the top-level Nix
|
||||||
expression. This is faster than using derivation names and
|
expression. This is faster than using derivation names and
|
||||||
unambiguous. To find out the attribute paths of available
|
unambiguous. To find out the attribute paths of available
|
||||||
packages, use `nix-env -qaP`.
|
packages, use `nix-env --query --available --attr-path `.
|
||||||
|
|
||||||
- If `--from-profile` *path* is given, *args* is a set of names
|
- If `--from-profile` *path* is given, *args* is a set of names
|
||||||
denoting installed store paths in the profile *path*. This is an
|
denoting installed store paths in the profile *path*. This is an
|
||||||
|
@ -87,7 +87,7 @@ a number of possible ways:
|
||||||
|
|
||||||
- `--remove-all` / `-r`\
|
- `--remove-all` / `-r`\
|
||||||
Remove all previously installed packages first. This is equivalent
|
Remove all previously installed packages first. This is equivalent
|
||||||
to running `nix-env -e '.*'` first, except that everything happens
|
to running `nix-env --uninstall '.*'` first, except that everything happens
|
||||||
in a single transaction.
|
in a single transaction.
|
||||||
|
|
||||||
{{#include ./opt-common.md}}
|
{{#include ./opt-common.md}}
|
||||||
|
@ -103,9 +103,9 @@ a number of possible ways:
|
||||||
To install a package using a specific attribute path from the active Nix expression:
|
To install a package using a specific attribute path from the active Nix expression:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA gcc40mips
|
$ nix-env --install --attr gcc40mips
|
||||||
installing `gcc-4.0.2'
|
installing `gcc-4.0.2'
|
||||||
$ nix-env -iA xorg.xorgserver
|
$ nix-env --install --attr xorg.xorgserver
|
||||||
installing `xorg-server-1.2.0'
|
installing `xorg-server-1.2.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -133,32 +133,32 @@ installing `gcc-3.3.2'
|
||||||
To install all derivations in the Nix expression `foo.nix`:
|
To install all derivations in the Nix expression `foo.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ~/foo.nix -i '.*'
|
$ nix-env --file ~/foo.nix --install '.*'
|
||||||
```
|
```
|
||||||
|
|
||||||
To copy the store path with symbolic name `gcc` from another profile:
|
To copy the store path with symbolic name `gcc` from another profile:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i --from-profile /nix/var/nix/profiles/foo gcc
|
$ nix-env --install --from-profile /nix/var/nix/profiles/foo gcc
|
||||||
```
|
```
|
||||||
|
|
||||||
To install a specific [store derivation] (typically created by
|
To install a specific [store derivation] (typically created by
|
||||||
`nix-instantiate`):
|
`nix-instantiate`):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
|
$ nix-env --install /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
|
||||||
```
|
```
|
||||||
|
|
||||||
To install a specific output path:
|
To install a specific output path:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
|
$ nix-env --install /nix/store/y3cgx0xj1p4iv9x0pnnmdhr8iyg741vk-gcc-3.4.3
|
||||||
```
|
```
|
||||||
|
|
||||||
To install from a Nix expression specified on the command-line:
|
To install from a Nix expression specified on the command-line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ./foo.nix -i -E \
|
$ nix-env --file ./foo.nix --install --expr \
|
||||||
'f: (f {system = "i686-linux";}).subversionWithJava'
|
'f: (f {system = "i686-linux";}).subversionWithJava'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ function defined in `./foo.nix`.
|
||||||
A dry-run tells you which paths will be downloaded or built from source:
|
A dry-run tells you which paths will be downloaded or built from source:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f '<nixpkgs>' -iA hello --dry-run
|
$ nix-env --file '<nixpkgs>' --install --attr hello --dry-run
|
||||||
(dry run; not doing anything)
|
(dry run; not doing anything)
|
||||||
installing ‘hello-2.10’
|
installing ‘hello-2.10’
|
||||||
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
|
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
|
||||||
|
@ -182,6 +182,6 @@ To install Firefox from the latest revision in the Nixpkgs/NixOS 14.12
|
||||||
channel:
|
channel:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz -iA firefox
|
$ nix-env --file https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz --install --attr firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ derivation is shown unless `--no-name` is specified.
|
||||||
To show installed packages:
|
To show installed packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
bison-1.875c
|
bison-1.875c
|
||||||
docbook-xml-4.2
|
docbook-xml-4.2
|
||||||
firefox-1.0.4
|
firefox-1.0.4
|
||||||
|
@ -149,7 +149,7 @@ ORBit2-2.8.3
|
||||||
To show available packages:
|
To show available packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa
|
$ nix-env --query --available
|
||||||
firefox-1.0.7
|
firefox-1.0.7
|
||||||
GConf-2.4.0.1
|
GConf-2.4.0.1
|
||||||
MPlayer-1.0pre7
|
MPlayer-1.0pre7
|
||||||
|
@ -160,7 +160,7 @@ ORBit2-2.8.3
|
||||||
To show the status of available packages:
|
To show the status of available packages:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qas
|
$ nix-env --query --available --status
|
||||||
-P- firefox-1.0.7 (not installed but present)
|
-P- firefox-1.0.7 (not installed but present)
|
||||||
--S GConf-2.4.0.1 (not present, but there is a substitute for fast installation)
|
--S GConf-2.4.0.1 (not present, but there is a substitute for fast installation)
|
||||||
--S MPlayer-1.0pre3 (i.e., this is not the installed MPlayer, even though the version is the same!)
|
--S MPlayer-1.0pre3 (i.e., this is not the installed MPlayer, even though the version is the same!)
|
||||||
|
@ -171,14 +171,14 @@ IP- ORBit2-2.8.3 (installed and by definition present)
|
||||||
To show available packages in the Nix expression `foo.nix`:
|
To show available packages in the Nix expression `foo.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f ./foo.nix -qa
|
$ nix-env --file ./foo.nix --query --available
|
||||||
foo-1.2.3
|
foo-1.2.3
|
||||||
```
|
```
|
||||||
|
|
||||||
To compare installed versions to what’s available:
|
To compare installed versions to what’s available:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qc
|
$ nix-env --query --compare-versions
|
||||||
...
|
...
|
||||||
acrobat-reader-7.0 - ? (package is not available at all)
|
acrobat-reader-7.0 - ? (package is not available at all)
|
||||||
autoconf-2.59 = 2.59 (same version)
|
autoconf-2.59 = 2.59 (same version)
|
||||||
|
@ -189,7 +189,7 @@ firefox-1.0.4 < 1.0.7 (a more recent version is available)
|
||||||
To show all packages with “`zip`” in the name:
|
To show all packages with “`zip`” in the name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa '.*zip.*'
|
$ nix-env --query --available '.*zip.*'
|
||||||
bzip2-1.0.6
|
bzip2-1.0.6
|
||||||
gzip-1.6
|
gzip-1.6
|
||||||
zip-3.0
|
zip-3.0
|
||||||
|
@ -199,7 +199,7 @@ zip-3.0
|
||||||
To show all packages with “`firefox`” or “`chromium`” in the name:
|
To show all packages with “`firefox`” or “`chromium`” in the name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa '.*(firefox|chromium).*'
|
$ nix-env --query --available '.*(firefox|chromium).*'
|
||||||
chromium-37.0.2062.94
|
chromium-37.0.2062.94
|
||||||
chromium-beta-38.0.2125.24
|
chromium-beta-38.0.2125.24
|
||||||
firefox-32.0.3
|
firefox-32.0.3
|
||||||
|
@ -210,6 +210,6 @@ firefox-with-plugins-13.0.1
|
||||||
To show all packages in the latest revision of the Nixpkgs repository:
|
To show all packages in the latest revision of the Nixpkgs repository:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -f https://github.com/NixOS/nixpkgs/archive/master.tar.gz -qa
|
$ nix-env --file https://github.com/NixOS/nixpkgs/archive/master.tar.gz --query --available
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -46,16 +46,16 @@ To prevent the currently installed Firefox from being upgraded:
|
||||||
$ nix-env --set-flag keep true firefox
|
$ nix-env --set-flag keep true firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
After this, `nix-env -u` will ignore Firefox.
|
After this, `nix-env --upgrade ` will ignore Firefox.
|
||||||
|
|
||||||
To disable the currently installed Firefox, then install a new Firefox
|
To disable the currently installed Firefox, then install a new Firefox
|
||||||
while the old remains part of the profile:
|
while the old remains part of the profile:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
firefox-2.0.0.9 (the current one)
|
firefox-2.0.0.9 (the current one)
|
||||||
|
|
||||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
$ nix-env --preserve-installed --install firefox-2.0.0.11
|
||||||
installing `firefox-2.0.0.11'
|
installing `firefox-2.0.0.11'
|
||||||
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
||||||
collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
||||||
|
@ -65,10 +65,10 @@ collision between `/nix/store/...-firefox-2.0.0.11/bin/firefox'
|
||||||
$ nix-env --set-flag active false firefox
|
$ nix-env --set-flag active false firefox
|
||||||
setting flag on `firefox-2.0.0.9'
|
setting flag on `firefox-2.0.0.9'
|
||||||
|
|
||||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
$ nix-env --preserve-installed --install firefox-2.0.0.11
|
||||||
installing `firefox-2.0.0.11'
|
installing `firefox-2.0.0.11'
|
||||||
|
|
||||||
$ nix-env -q
|
$ nix-env --query
|
||||||
firefox-2.0.0.11 (the enabled one)
|
firefox-2.0.0.11 (the enabled one)
|
||||||
firefox-2.0.0.9 (the disabled one)
|
firefox-2.0.0.9 (the disabled one)
|
||||||
```
|
```
|
||||||
|
|
|
@ -25,6 +25,6 @@ The following updates a profile such that its current generation will
|
||||||
contain just Firefox:
|
contain just Firefox:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -p /nix/var/nix/profiles/browser --set firefox
|
$ nix-env --profile /nix/var/nix/profiles/browser --set firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ Switching will fail if the specified generation does not exist.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -G 42
|
$ nix-env --switch-generation 42
|
||||||
switching from generation 50 to 42
|
switching from generation 50 to 42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -22,5 +22,5 @@ the symlink `~/.nix-profile` is made to point to *path*.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -S ~/my-profile
|
$ nix-env --switch-profile ~/my-profile
|
||||||
```
|
```
|
||||||
|
|
|
@ -24,5 +24,5 @@ designated by the symbolic names *drvnames* are removed.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --uninstall gcc
|
$ nix-env --uninstall gcc
|
||||||
$ nix-env -e '.*' (remove everything)
|
$ nix-env --uninstall '.*' (remove everything)
|
||||||
```
|
```
|
||||||
|
|
|
@ -76,21 +76,21 @@ version is installed.
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.gcc
|
$ nix-env --upgrade --attr nixpkgs.gcc
|
||||||
upgrading `gcc-3.3.1' to `gcc-3.4'
|
upgrading `gcc-3.3.1' to `gcc-3.4'
|
||||||
```
|
```
|
||||||
|
|
||||||
When there are no updates available, nothing will happen:
|
When there are no updates available, nothing will happen:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.pan
|
$ nix-env --upgrade --attr nixpkgs.pan
|
||||||
```
|
```
|
||||||
|
|
||||||
Using `-A` is preferred when possible, as it is faster and unambiguous but
|
Using `-A` is preferred when possible, as it is faster and unambiguous but
|
||||||
it is also possible to upgrade to a specific version by matching the derivation name:
|
it is also possible to upgrade to a specific version by matching the derivation name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u gcc-3.3.2 --always
|
$ nix-env --upgrade gcc-3.3.2 --always
|
||||||
upgrading `gcc-3.4' to `gcc-3.3.2'
|
upgrading `gcc-3.4' to `gcc-3.3.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ To try to upgrade everything
|
||||||
(matching packages based on the part of the derivation name without version):
|
(matching packages based on the part of the derivation name without version):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
upgrading `hello-2.1.2' to `hello-2.1.3'
|
upgrading `hello-2.1.2' to `hello-2.1.3'
|
||||||
upgrading `mozilla-1.2' to `mozilla-1.4'
|
upgrading `mozilla-1.2' to `mozilla-1.4'
|
||||||
```
|
```
|
||||||
|
|
|
@ -88,7 +88,7 @@ Instantiate [store derivation]s from a Nix expression, and build them using `nix
|
||||||
$ nix-instantiate test.nix (instantiate)
|
$ nix-instantiate test.nix (instantiate)
|
||||||
/nix/store/cigxbmvy6dzix98dxxh9b6shg7ar5bvs-perl-BerkeleyDB-0.26.drv
|
/nix/store/cigxbmvy6dzix98dxxh9b6shg7ar5bvs-perl-BerkeleyDB-0.26.drv
|
||||||
|
|
||||||
$ nix-store -r $(nix-instantiate test.nix) (build)
|
$ nix-store --realise $(nix-instantiate test.nix) (build)
|
||||||
...
|
...
|
||||||
/nix/store/qhqk4n8ci095g3sdp93x7rgwyh9rdvgk-perl-BerkeleyDB-0.26 (output path)
|
/nix/store/qhqk4n8ci095g3sdp93x7rgwyh9rdvgk-perl-BerkeleyDB-0.26 (output path)
|
||||||
|
|
||||||
|
@ -100,30 +100,30 @@ dr-xr-xr-x 2 eelco users 4096 1970-01-01 01:00 lib
|
||||||
You can also give a Nix expression on the command line:
|
You can also give a Nix expression on the command line:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate -E 'with import <nixpkgs> { }; hello'
|
$ nix-instantiate --expr 'with import <nixpkgs> { }; hello'
|
||||||
/nix/store/j8s4zyv75a724q38cb0r87rlczaiag4y-hello-2.8.drv
|
/nix/store/j8s4zyv75a724q38cb0r87rlczaiag4y-hello-2.8.drv
|
||||||
```
|
```
|
||||||
|
|
||||||
This is equivalent to:
|
This is equivalent to:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate '<nixpkgs>' -A hello
|
$ nix-instantiate '<nixpkgs>' --attr hello
|
||||||
```
|
```
|
||||||
|
|
||||||
Parsing and evaluating Nix expressions:
|
Parsing and evaluating Nix expressions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --parse -E '1 + 2'
|
$ nix-instantiate --parse --expr '1 + 2'
|
||||||
1 + 2
|
1 + 2
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval -E '1 + 2'
|
$ nix-instantiate --eval --expr '1 + 2'
|
||||||
3
|
3
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml -E '1 + 2'
|
$ nix-instantiate --eval --xml --expr '1 + 2'
|
||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<expr>
|
<expr>
|
||||||
<int value="3" />
|
<int value="3" />
|
||||||
|
@ -133,7 +133,7 @@ $ nix-instantiate --eval --xml -E '1 + 2'
|
||||||
The difference between non-strict and strict evaluation:
|
The difference between non-strict and strict evaluation:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml -E 'rec { x = "foo"; y = x; }'
|
$ nix-instantiate --eval --xml --expr 'rec { x = "foo"; y = x; }'
|
||||||
...
|
...
|
||||||
<attr name="x">
|
<attr name="x">
|
||||||
<string value="foo" />
|
<string value="foo" />
|
||||||
|
@ -148,7 +148,7 @@ Note that `y` is left unevaluated (the XML representation doesn’t
|
||||||
attempt to show non-normal forms).
|
attempt to show non-normal forms).
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-instantiate --eval --xml --strict -E 'rec { x = "foo"; y = x; }'
|
$ nix-instantiate --eval --xml --strict --expr 'rec { x = "foo"; y = x; }'
|
||||||
...
|
...
|
||||||
<attr name="x">
|
<attr name="x">
|
||||||
<string value="foo" />
|
<string value="foo" />
|
||||||
|
|
|
@ -89,7 +89,7 @@ All options not listed here are passed to `nix-store
|
||||||
- `--packages` / `-p` *packages*…\
|
- `--packages` / `-p` *packages*…\
|
||||||
Set up an environment in which the specified packages are present.
|
Set up an environment in which the specified packages are present.
|
||||||
The command line arguments are interpreted as attribute names inside
|
The command line arguments are interpreted as attribute names inside
|
||||||
the Nix Packages collection. Thus, `nix-shell -p libjpeg openjdk`
|
the Nix Packages collection. Thus, `nix-shell --packages libjpeg openjdk`
|
||||||
will start a shell in which the packages denoted by the attribute
|
will start a shell in which the packages denoted by the attribute
|
||||||
names `libjpeg` and `openjdk` are present.
|
names `libjpeg` and `openjdk` are present.
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ To build the dependencies of the package Pan, and start an interactive
|
||||||
shell in which to build it:
|
shell in which to build it:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan
|
$ nix-shell '<nixpkgs>' --attr pan
|
||||||
[nix-shell]$ eval ${unpackPhase:-unpackPhase}
|
[nix-shell]$ eval ${unpackPhase:-unpackPhase}
|
||||||
[nix-shell]$ cd $sourceRoot
|
[nix-shell]$ cd $sourceRoot
|
||||||
[nix-shell]$ eval ${patchPhase:-patchPhase}
|
[nix-shell]$ eval ${patchPhase:-patchPhase}
|
||||||
|
@ -137,7 +137,7 @@ To clear the environment first, and do some additional automatic
|
||||||
initialisation of the interactive shell:
|
initialisation of the interactive shell:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan --pure \
|
$ nix-shell '<nixpkgs>' --attr pan --pure \
|
||||||
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
|
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -146,13 +146,13 @@ Nix expressions can also be given on the command line using the `-E` and
|
||||||
packages `sqlite` and `libX11`:
|
packages `sqlite` and `libX11`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -E 'with import <nixpkgs> { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
|
$ nix-shell --expr 'with import <nixpkgs> { }; runCommand "dummy" { buildInputs = [ sqlite xorg.libX11 ]; } ""'
|
||||||
```
|
```
|
||||||
|
|
||||||
A shorter way to do the same is:
|
A shorter way to do the same is:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p sqlite xorg.libX11
|
$ nix-shell --packages sqlite xorg.libX11
|
||||||
[nix-shell]$ echo $NIX_LDFLAGS
|
[nix-shell]$ echo $NIX_LDFLAGS
|
||||||
… -L/nix/store/j1zg5v…-sqlite-3.8.0.2/lib -L/nix/store/0gmcz9…-libX11-1.6.1/lib …
|
… -L/nix/store/j1zg5v…-sqlite-3.8.0.2/lib -L/nix/store/0gmcz9…-libX11-1.6.1/lib …
|
||||||
```
|
```
|
||||||
|
@ -162,7 +162,7 @@ the `buildInputs = [ ... ]` shown above, not only package names. So the
|
||||||
following is also legal:
|
following is also legal:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p sqlite 'git.override { withManual = false; }'
|
$ nix-shell --packages sqlite 'git.override { withManual = false; }'
|
||||||
```
|
```
|
||||||
|
|
||||||
The `-p` flag looks up Nixpkgs in the Nix search path. You can override
|
The `-p` flag looks up Nixpkgs in the Nix search path. You can override
|
||||||
|
@ -171,7 +171,7 @@ gives you a shell containing the Pan package from a specific revision of
|
||||||
Nixpkgs:
|
Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
|
$ nix-shell --packages pan -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/8a3eea054838b55aca962c3fbde9c83c102b8bf2.tar.gz
|
||||||
|
|
||||||
[nix-shell:~]$ pan --version
|
[nix-shell:~]$ pan --version
|
||||||
Pan 0.139
|
Pan 0.139
|
||||||
|
@ -185,7 +185,7 @@ done by starting the script with the following lines:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i real-interpreter -p packages
|
#! nix-shell -i real-interpreter --packages packages
|
||||||
```
|
```
|
||||||
|
|
||||||
where *real-interpreter* is the “real” script interpreter that will be
|
where *real-interpreter* is the “real” script interpreter that will be
|
||||||
|
@ -202,7 +202,7 @@ For example, here is a Python script that depends on Python and the
|
||||||
|
|
||||||
```python
|
```python
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i python -p python pythonPackages.prettytable
|
#! nix-shell -i python --packages python pythonPackages.prettytable
|
||||||
|
|
||||||
import prettytable
|
import prettytable
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ requires Perl and the `HTML::TokeParser::Simple` and `LWP` packages:
|
||||||
|
|
||||||
```perl
|
```perl
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i perl -p perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
|
#! nix-shell -i perl --packages perl perlPackages.HTMLTokeParserSimple perlPackages.LWP
|
||||||
|
|
||||||
use HTML::TokeParser::Simple;
|
use HTML::TokeParser::Simple;
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ package like Terraform:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i bash -p "terraform.withPlugins (plugins: [ plugins.openstack ])"
|
#! nix-shell -i bash --packages "terraform.withPlugins (plugins: [ plugins.openstack ])"
|
||||||
|
|
||||||
terraform apply
|
terraform apply
|
||||||
```
|
```
|
||||||
|
@ -251,7 +251,7 @@ branch):
|
||||||
|
|
||||||
```haskell
|
```haskell
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
|
#! nix-shell -i runghc --packages "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
|
||||||
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
|
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
|
||||||
|
|
||||||
import Network.Curl.Download
|
import Network.Curl.Download
|
||||||
|
|
|
@ -23,7 +23,7 @@ produce the same NAR archive. For instance, directory entries are
|
||||||
always sorted so that the actual on-disk order doesn’t influence the
|
always sorted so that the actual on-disk order doesn’t influence the
|
||||||
result. This means that the cryptographic hash of a NAR dump of a
|
result. This means that the cryptographic hash of a NAR dump of a
|
||||||
path is usable as a fingerprint of the contents of the path. Indeed,
|
path is usable as a fingerprint of the contents of the path. Indeed,
|
||||||
the hashes of store paths stored in Nix’s database (see `nix-store -q
|
the hashes of store paths stored in Nix’s database (see `nix-store --query
|
||||||
--hash`) are SHA-256 hashes of the NAR dump of each store path.
|
--hash`) are SHA-256 hashes of the NAR dump of each store path.
|
||||||
|
|
||||||
NAR archives support filenames of unlimited length and 64-bit file
|
NAR archives support filenames of unlimited length and 64-bit file
|
||||||
|
|
|
@ -31,7 +31,7 @@ To copy a whole closure, do something
|
||||||
like:
|
like:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --export $(nix-store -qR paths) > out
|
$ nix-store --export $(nix-store --query --requisites paths) > out
|
||||||
```
|
```
|
||||||
|
|
||||||
To import the whole closure again, run:
|
To import the whole closure again, run:
|
||||||
|
|
|
@ -11,7 +11,7 @@ The following options are allowed for all `nix-store` operations, but may not al
|
||||||
be created in `/nix/var/nix/gcroots/auto/`. For instance,
|
be created in `/nix/var/nix/gcroots/auto/`. For instance,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --add-root /home/eelco/bla/result -r ...
|
$ nix-store --add-root /home/eelco/bla/result --realise ...
|
||||||
|
|
||||||
$ ls -l /nix/var/nix/gcroots/auto
|
$ ls -l /nix/var/nix/gcroots/auto
|
||||||
lrwxrwxrwx 1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result
|
lrwxrwxrwx 1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result
|
||||||
|
|
|
@ -145,7 +145,7 @@ Print the closure (runtime dependencies) of the `svn` program in the
|
||||||
current user environment:
|
current user environment:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -qR $(which svn)
|
$ nix-store --query --requisites $(which svn)
|
||||||
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
||||||
/nix/store/9lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
|
/nix/store/9lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
|
||||||
...
|
...
|
||||||
|
@ -154,7 +154,7 @@ $ nix-store -qR $(which svn)
|
||||||
Print the build-time dependencies of `svn`:
|
Print the build-time dependencies of `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -qR $(nix-store -qd $(which svn))
|
$ nix-store --query --requisites $(nix-store --query --deriver $(which svn))
|
||||||
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
|
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
|
||||||
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
|
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
|
||||||
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
|
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
|
||||||
|
@ -168,7 +168,7 @@ the derivation (`-qd`), not the closure of the output path that contains
|
||||||
Show the build-time dependencies as a tree:
|
Show the build-time dependencies as a tree:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --tree $(nix-store -qd $(which svn))
|
$ nix-store --query --tree $(nix-store --query --deriver $(which svn))
|
||||||
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
|
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
|
||||||
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
|
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
|
||||||
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
|
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
|
||||||
|
@ -180,7 +180,7 @@ $ nix-store -q --tree $(nix-store -qd $(which svn))
|
||||||
Show all paths that depend on the same OpenSSL library as `svn`:
|
Show all paths that depend on the same OpenSSL library as `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --referrers $(nix-store -q --binding openssl $(nix-store -qd $(which svn)))
|
$ nix-store --query --referrers $(nix-store --query --binding openssl $(nix-store --query --deriver $(which svn)))
|
||||||
/nix/store/23ny9l9wixx21632y2wi4p585qhva1q8-sylpheed-1.0.0
|
/nix/store/23ny9l9wixx21632y2wi4p585qhva1q8-sylpheed-1.0.0
|
||||||
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
/nix/store/5mbglq5ldqld8sj57273aljwkfvj22mc-subversion-1.1.4
|
||||||
/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3
|
/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3
|
||||||
|
@ -191,7 +191,7 @@ Show all paths that directly or indirectly depend on the Glibc (C
|
||||||
library) used by `svn`:
|
library) used by `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
|
$ nix-store --query --referrers-closure $(ldd $(which svn) | grep /libc.so | awk '{print $3}')
|
||||||
/nix/store/034a6h4vpz9kds5r6kzb9lhh81mscw43-libgnomeprintui-2.8.2
|
/nix/store/034a6h4vpz9kds5r6kzb9lhh81mscw43-libgnomeprintui-2.8.2
|
||||||
/nix/store/15l3yi0d45prm7a82pcrknxdh6nzmxza-gawk-3.1.4
|
/nix/store/15l3yi0d45prm7a82pcrknxdh6nzmxza-gawk-3.1.4
|
||||||
...
|
...
|
||||||
|
@ -204,7 +204,7 @@ Make a picture of the runtime dependency graph of the current user
|
||||||
environment:
|
environment:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --graph ~/.nix-profile | dot -Tps > graph.ps
|
$ nix-store --query --graph ~/.nix-profile | dot -Tps > graph.ps
|
||||||
$ gv graph.ps
|
$ gv graph.ps
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ Show every garbage collector root that points to a store path that
|
||||||
depends on `svn`:
|
depends on `svn`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -q --roots $(which svn)
|
$ nix-store --query --roots $(which svn)
|
||||||
/nix/var/nix/profiles/default-81-link
|
/nix/var/nix/profiles/default-81-link
|
||||||
/nix/var/nix/profiles/default-82-link
|
/nix/var/nix/profiles/default-82-link
|
||||||
/home/eelco/.local/state/nix/profiles/profile-97-link
|
/home/eelco/.local/state/nix/profiles/profile-97-link
|
||||||
|
|
|
@ -27,7 +27,7 @@ substitute, then the log is unavailable.
|
||||||
# Example
|
# Example
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -l $(which ktorrent)
|
$ nix-store --read-log $(which ktorrent)
|
||||||
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
|
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
|
||||||
unpacking sources
|
unpacking sources
|
||||||
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
|
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
|
||||||
|
|
|
@ -99,7 +99,7 @@ This operation is typically used to build [store derivation]s produced by
|
||||||
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
[store derivation]: @docroot@/glossary.md#gloss-store-derivation
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -r $(nix-instantiate ./test.nix)
|
$ nix-store --realise $(nix-instantiate ./test.nix)
|
||||||
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
|
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ This is essentially what [`nix-build`](@docroot@/command-ref/nix-build.md) does.
|
||||||
To test whether a previously-built derivation is deterministic:
|
To test whether a previously-built derivation is deterministic:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build '<nixpkgs>' -A hello --check -K
|
$ nix-build '<nixpkgs>' --attr hello --check -K
|
||||||
```
|
```
|
||||||
|
|
||||||
Use [`nix-store --read-log`](./read-log.md) to show the stderr and stdout of a build:
|
Use [`nix-store --read-log`](./read-log.md) to show the stderr and stdout of a build:
|
||||||
|
|
|
@ -24,6 +24,6 @@ path has changed, and 1 otherwise.
|
||||||
To verify the integrity of the `svn` command and all its dependencies:
|
To verify the integrity of the `svn` command and all its dependencies:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --verify-path $(nix-store -qR $(which svn))
|
$ nix-store --verify-path $(nix-store --query --requisites $(which svn))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -162,11 +162,11 @@ Most Nix commands accept the following command-line options:
|
||||||
}: ...
|
}: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
So if you call this Nix expression (e.g., when you do `nix-env -iA
|
So if you call this Nix expression (e.g., when you do `nix-env --install --attr
|
||||||
pkgname`), the function will be called automatically using the
|
pkgname`), the function will be called automatically using the
|
||||||
value [`builtins.currentSystem`](@docroot@/language/builtins.md) for
|
value [`builtins.currentSystem`](@docroot@/language/builtins.md) for
|
||||||
the `system` argument. You can override this using `--arg`, e.g.,
|
the `system` argument. You can override this using `--arg`, e.g.,
|
||||||
`nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
|
`nix-env --install --attr pkgname --arg system \"i686-freebsd\"`. (Note that
|
||||||
since the argument is a Nix string literal, you have to escape the
|
since the argument is a Nix string literal, you have to escape the
|
||||||
quotes.)
|
quotes.)
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ Most Nix commands accept the following command-line options:
|
||||||
For `nix-shell`, this option is commonly used to give you a shell in
|
For `nix-shell`, this option is commonly used to give you a shell in
|
||||||
which you can build the packages returned by the expression. If you
|
which you can build the packages returned by the expression. If you
|
||||||
want to get a shell which contain the *built* packages ready for
|
want to get a shell which contain the *built* packages ready for
|
||||||
use, give your expression to the `nix-shell -p` convenience flag
|
use, give your expression to the `nix-shell --packages ` convenience flag
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
- <span id="opt-I">[`-I`](#opt-I)</span> *path*\
|
- <span id="opt-I">[`-I`](#opt-I)</span> *path*\
|
||||||
|
|
|
@ -77,7 +77,7 @@ $ nix-shell
|
||||||
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -A devShells.x86_64-linux.native-clang11StdenvPackages
|
$ nix-shell --attr devShells.x86_64-linux.native-clang11StdenvPackages
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
|
@ -139,7 +139,7 @@ $ nix build .#packages.aarch64-linux.default
|
||||||
for flake-enabled Nix, or
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -A packages.aarch64-linux.default
|
$ nix-build --attr packages.aarch64-linux.default
|
||||||
```
|
```
|
||||||
|
|
||||||
for classic Nix.
|
for classic Nix.
|
||||||
|
@ -166,7 +166,7 @@ $ nix build .#nix-ccacheStdenv
|
||||||
for flake-enabled Nix, or
|
for flake-enabled Nix, or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-build -A nix-ccacheStdenv
|
$ nix-build --attr nix-ccacheStdenv
|
||||||
```
|
```
|
||||||
|
|
||||||
for classic Nix.
|
for classic Nix.
|
||||||
|
|
|
@ -101,11 +101,8 @@
|
||||||
derivation.
|
derivation.
|
||||||
|
|
||||||
- [output-addressed store object]{#gloss-output-addressed-store-object}\
|
- [output-addressed store object]{#gloss-output-addressed-store-object}\
|
||||||
A store object whose store path hashes its content. This
|
A [store object] whose [store path] is determined by its contents.
|
||||||
includes derivations, the outputs of
|
This includes derivations, the outputs of [content-addressed derivations](#gloss-content-addressed-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
|
||||||
[content-addressed derivations](#gloss-content-addressed-derivation),
|
|
||||||
and the outputs of
|
|
||||||
[fixed-output derivations](#gloss-fixed-output-derivation).
|
|
||||||
|
|
||||||
- [substitute]{#gloss-substitute}\
|
- [substitute]{#gloss-substitute}\
|
||||||
A substitute is a command invocation stored in the [Nix database] that
|
A substitute is a command invocation stored in the [Nix database] that
|
||||||
|
@ -163,7 +160,7 @@
|
||||||
build-time dependencies, while the closure of its output path is
|
build-time dependencies, while the closure of its output path is
|
||||||
equivalent to its runtime dependencies. For correct deployment it
|
equivalent to its runtime dependencies. For correct deployment it
|
||||||
is necessary to deploy whole closures, since otherwise at runtime
|
is necessary to deploy whole closures, since otherwise at runtime
|
||||||
files could be missing. The command `nix-store -qR` prints out
|
files could be missing. The command `nix-store --query --requisites ` prints out
|
||||||
closures of store paths.
|
closures of store paths.
|
||||||
|
|
||||||
As an example, if the [store object] at path `P` contains a [reference]
|
As an example, if the [store object] at path `P` contains a [reference]
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
Multi-user Nix users on macOS can upgrade Nix by running: `sudo -i sh -c
|
Multi-user Nix users on macOS can upgrade Nix by running: `sudo -i sh -c
|
||||||
'nix-channel --update &&
|
'nix-channel --update &&
|
||||||
nix-env -iA nixpkgs.nix &&
|
nix-env --install --attr nixpkgs.nix &&
|
||||||
launchctl remove org.nixos.nix-daemon &&
|
launchctl remove org.nixos.nix-daemon &&
|
||||||
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'`
|
launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'`
|
||||||
|
|
||||||
Single-user installations of Nix should run this: `nix-channel --update;
|
Single-user installations of Nix should run this: `nix-channel --update;
|
||||||
nix-env -iA nixpkgs.nix nixpkgs.cacert`
|
nix-env --install --attr nixpkgs.nix nixpkgs.cacert`
|
||||||
|
|
||||||
Multi-user Nix users on Linux should run this with sudo: `nix-channel
|
Multi-user Nix users on Linux should run this with sudo: `nix-channel
|
||||||
--update; nix-env -iA nixpkgs.nix nixpkgs.cacert; systemctl
|
--update; nix-env --install --attr nixpkgs.nix nixpkgs.cacert; systemctl
|
||||||
daemon-reload; systemctl restart nix-daemon`
|
daemon-reload; systemctl restart nix-daemon`
|
||||||
|
|
|
@ -76,7 +76,7 @@ there after an upgrade. This means that you can _roll back_ to the
|
||||||
old version:
|
old version:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade -A nixpkgs.some-package
|
$ nix-env --upgrade --attr nixpkgs.some-package
|
||||||
$ nix-env --rollback
|
$ nix-env --rollback
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ Nix expressions generally describe how to build a package from
|
||||||
source, so an installation action like
|
source, so an installation action like
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --install -A nixpkgs.firefox
|
$ nix-env --install --attr nixpkgs.firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
_could_ cause quite a bit of build activity, as not only Firefox but
|
_could_ cause quite a bit of build activity, as not only Firefox but
|
||||||
|
@ -158,7 +158,7 @@ Pan newsreader, as described by [its
|
||||||
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
|
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell '<nixpkgs>' -A pan
|
$ nix-shell '<nixpkgs>' --attr pan
|
||||||
```
|
```
|
||||||
|
|
||||||
You’re then dropped into a shell where you can edit, build and test
|
You’re then dropped into a shell where you can edit, build and test
|
||||||
|
|
|
@ -47,7 +47,7 @@ $ nix-channel --update
|
||||||
You can view the set of available packages in Nixpkgs:
|
You can view the set of available packages in Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP
|
$ nix-env --query --available --attr-path
|
||||||
nixpkgs.aterm aterm-2.2
|
nixpkgs.aterm aterm-2.2
|
||||||
nixpkgs.bash bash-3.0
|
nixpkgs.bash bash-3.0
|
||||||
nixpkgs.binutils binutils-2.15
|
nixpkgs.binutils binutils-2.15
|
||||||
|
@ -65,7 +65,7 @@ If you downloaded Nixpkgs yourself, or if you checked it out from GitHub,
|
||||||
then you need to pass the path to your Nixpkgs tree using the `-f` flag:
|
then you need to pass the path to your Nixpkgs tree using the `-f` flag:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaPf /path/to/nixpkgs
|
$ nix-env --query --available --attr-path --file /path/to/nixpkgs
|
||||||
aterm aterm-2.2
|
aterm aterm-2.2
|
||||||
bash bash-3.0
|
bash bash-3.0
|
||||||
…
|
…
|
||||||
|
@ -77,7 +77,7 @@ Nixpkgs.
|
||||||
You can filter the packages by name:
|
You can filter the packages by name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP firefox
|
$ nix-env --query --available --attr-path firefox
|
||||||
nixpkgs.firefox-esr firefox-91.3.0esr
|
nixpkgs.firefox-esr firefox-91.3.0esr
|
||||||
nixpkgs.firefox firefox-94.0.1
|
nixpkgs.firefox firefox-94.0.1
|
||||||
```
|
```
|
||||||
|
@ -85,7 +85,7 @@ nixpkgs.firefox firefox-94.0.1
|
||||||
and using regular expressions:
|
and using regular expressions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaP 'firefox.*'
|
$ nix-env --query --available --attr-path 'firefox.*'
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to see the *status* of available packages, i.e.,
|
It is also possible to see the *status* of available packages, i.e.,
|
||||||
|
@ -93,7 +93,7 @@ whether they are installed into the user environment and/or present in
|
||||||
the system:
|
the system:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaPs
|
$ nix-env --query --available --attr-path --status
|
||||||
…
|
…
|
||||||
-PS nixpkgs.bash bash-3.0
|
-PS nixpkgs.bash bash-3.0
|
||||||
--S nixpkgs.binutils binutils-2.15
|
--S nixpkgs.binutils binutils-2.15
|
||||||
|
@ -110,10 +110,10 @@ which is Nix’s mechanism for doing binary deployment. It just means that
|
||||||
Nix knows that it can fetch a pre-built package from somewhere
|
Nix knows that it can fetch a pre-built package from somewhere
|
||||||
(typically a network server) instead of building it locally.
|
(typically a network server) instead of building it locally.
|
||||||
|
|
||||||
You can install a package using `nix-env -iA`. For instance,
|
You can install a package using `nix-env --install --attr `. For instance,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion
|
$ nix-env --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
|
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
|
||||||
|
@ -143,14 +143,14 @@ instead of the attribute path, as `nix-env` does not record which attribute
|
||||||
was used for installing:
|
was used for installing:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -e subversion
|
$ nix-env --uninstall subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
Upgrading to a new version is just as easy. If you have a new release of
|
Upgrading to a new version is just as easy. If you have a new release of
|
||||||
Nix Packages, you can do:
|
Nix Packages, you can do:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -uA nixpkgs.subversion
|
$ nix-env --upgrade --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
This will *only* upgrade Subversion if there is a “newer” version in the
|
This will *only* upgrade Subversion if there is a “newer” version in the
|
||||||
|
@ -163,15 +163,15 @@ whatever version is in the Nix expressions, use `-i` instead of `-u`;
|
||||||
You can also upgrade all packages for which there are newer versions:
|
You can also upgrade all packages for which there are newer versions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
Sometimes it’s useful to be able to ask what `nix-env` would do, without
|
Sometimes it’s useful to be able to ask what `nix-env` would do, without
|
||||||
actually doing it. For instance, to find out what packages would be
|
actually doing it. For instance, to find out what packages would be
|
||||||
upgraded by `nix-env -u`, you can do
|
upgraded by `nix-env --upgrade `, you can do
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u --dry-run
|
$ nix-env --upgrade --dry-run
|
||||||
(dry run; not doing anything)
|
(dry run; not doing anything)
|
||||||
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
|
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
|
||||||
upgrading `graphviz-1.10' to `graphviz-1.12'
|
upgrading `graphviz-1.10' to `graphviz-1.12'
|
||||||
|
|
|
@ -9,7 +9,7 @@ The daemon that handles binary cache requests via HTTP, `nix-serve`, is
|
||||||
not part of the Nix distribution, but you can install it from Nixpkgs:
|
not part of the Nix distribution, but you can install it from Nixpkgs:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.nix-serve
|
$ nix-env --install --attr nixpkgs.nix-serve
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then start the server, listening for HTTP connections on
|
You can then start the server, listening for HTTP connections on
|
||||||
|
@ -35,7 +35,7 @@ On the client side, you can tell Nix to use your binary cache using
|
||||||
`--substituters`, e.g.:
|
`--substituters`, e.g.:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.firefox --substituters http://avalon:8080/
|
$ nix-env --install --attr nixpkgs.firefox --substituters http://avalon:8080/
|
||||||
```
|
```
|
||||||
|
|
||||||
The option `substituters` tells Nix to use this binary cache in
|
The option `substituters` tells Nix to use this binary cache in
|
||||||
|
|
|
@ -43,7 +43,7 @@ operations (via the symlink `~/.nix-defexpr/channels`). Consequently,
|
||||||
you can then say
|
you can then say
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u
|
$ nix-env --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
to upgrade all packages in your profile to the latest versions available
|
to upgrade all packages in your profile to the latest versions available
|
||||||
|
|
|
@ -15,7 +15,7 @@ With `nix-store
|
||||||
path (that is, the path and all its dependencies) to a file, and then
|
path (that is, the path and all its dependencies) to a file, and then
|
||||||
unpack that file into another Nix store. For example,
|
unpack that file into another Nix store. For example,
|
||||||
|
|
||||||
$ nix-store --export $(nix-store -qR $(type -p firefox)) > firefox.closure
|
$ nix-store --export $(nix-store --query --requisites $(type -p firefox)) > firefox.closure
|
||||||
|
|
||||||
writes the closure of Firefox to a file. You can then copy this file to
|
writes the closure of Firefox to a file. You can then copy this file to
|
||||||
another machine and install the closure:
|
another machine and install the closure:
|
||||||
|
@ -27,7 +27,7 @@ store are ignored. It is also possible to pipe the export into another
|
||||||
command, e.g. to copy and install a closure directly to/on another
|
command, e.g. to copy and install a closure directly to/on another
|
||||||
machine:
|
machine:
|
||||||
|
|
||||||
$ nix-store --export $(nix-store -qR $(type -p firefox)) | bzip2 | \
|
$ nix-store --export $(nix-store --query --requisites $(type -p firefox)) | bzip2 | \
|
||||||
ssh alice@itchy.example.org "bunzip2 | nix-store --import"
|
ssh alice@itchy.example.org "bunzip2 | nix-store --import"
|
||||||
|
|
||||||
However, `nix-copy-closure` is generally more efficient because it only
|
However, `nix-copy-closure` is generally more efficient because it only
|
||||||
|
|
|
@ -39,7 +39,7 @@ just Subversion 1.1.2 (arrows in the figure indicate symlinks). This
|
||||||
would be what we would obtain if we had done
|
would be what we would obtain if we had done
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion
|
$ nix-env --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
on a set of Nix expressions that contained Subversion 1.1.2.
|
on a set of Nix expressions that contained Subversion 1.1.2.
|
||||||
|
@ -54,7 +54,7 @@ environment is generated based on the current one. For instance,
|
||||||
generation 43 was created from generation 42 when we did
|
generation 43 was created from generation 42 when we did
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.subversion nixpkgs.firefox
|
$ nix-env --install --attr nixpkgs.subversion nixpkgs.firefox
|
||||||
```
|
```
|
||||||
|
|
||||||
on a set of Nix expressions that contained Firefox and a new version of
|
on a set of Nix expressions that contained Firefox and a new version of
|
||||||
|
@ -127,7 +127,7 @@ All `nix-env` operations work on the profile pointed to by
|
||||||
(abbreviation `-p`):
|
(abbreviation `-p`):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -p /nix/var/nix/profiles/other-profile -iA nixpkgs.subversion
|
$ nix-env --profile /nix/var/nix/profiles/other-profile --install --attr nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
This will *not* change the `~/.nix-profile` symlink.
|
This will *not* change the `~/.nix-profile` symlink.
|
||||||
|
|
|
@ -6,7 +6,7 @@ automatically fetching any store paths in Firefox’s closure if they are
|
||||||
available on the server `avalon`:
|
available on the server `avalon`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -iA nixpkgs.firefox --substituters ssh://alice@avalon
|
$ nix-env --install --attr nixpkgs.firefox --substituters ssh://alice@avalon
|
||||||
```
|
```
|
||||||
|
|
||||||
This works similar to the binary cache substituter that Nix usually
|
This works similar to the binary cache substituter that Nix usually
|
||||||
|
@ -25,7 +25,7 @@ You can also copy the closure of some store path, without installing it
|
||||||
into your profile, e.g.
|
into your profile, e.g.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store -r /nix/store/m85bxg…-firefox-34.0.5 --substituters
|
$ nix-store --realise /nix/store/m85bxg…-firefox-34.0.5 --substituters
|
||||||
ssh://alice@avalon
|
ssh://alice@avalon
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
14
docker.nix
14
docker.nix
|
@ -190,6 +190,12 @@ let
|
||||||
cp -a ${rootEnv}/* $out/
|
cp -a ${rootEnv}/* $out/
|
||||||
ln -s ${manifest} $out/manifest.nix
|
ln -s ${manifest} $out/manifest.nix
|
||||||
'';
|
'';
|
||||||
|
flake-registry-path = if (flake-registry == null) then
|
||||||
|
null
|
||||||
|
else if (builtins.readFileType (toString flake-registry)) == "directory" then
|
||||||
|
"${flake-registry}/flake-registry.json"
|
||||||
|
else
|
||||||
|
flake-registry;
|
||||||
in
|
in
|
||||||
pkgs.runCommand "base-system"
|
pkgs.runCommand "base-system"
|
||||||
{
|
{
|
||||||
|
@ -202,7 +208,7 @@ let
|
||||||
];
|
];
|
||||||
allowSubstitutes = false;
|
allowSubstitutes = false;
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
} ''
|
} (''
|
||||||
env
|
env
|
||||||
set -x
|
set -x
|
||||||
mkdir -p $out/etc
|
mkdir -p $out/etc
|
||||||
|
@ -249,15 +255,15 @@ let
|
||||||
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
||||||
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
||||||
|
|
||||||
'' + (lib.optionalString (flake-registry != null) ''
|
'' + (lib.optionalString (flake-registry-path != null) ''
|
||||||
nixCacheDir="/root/.cache/nix"
|
nixCacheDir="/root/.cache/nix"
|
||||||
mkdir -p $out$nixCacheDir
|
mkdir -p $out$nixCacheDir
|
||||||
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
||||||
ln -s ${flake-registry}/flake-registry.json $out$globalFlakeRegistryPath
|
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
|
||||||
mkdir -p $out/nix/var/nix/gcroots/auto
|
mkdir -p $out/nix/var/nix/gcroots/auto
|
||||||
rootName=$(${pkgs.nix}/bin/nix --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
|
rootName=$(${pkgs.nix}/bin/nix --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
|
||||||
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
|
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
|
||||||
'');
|
''));
|
||||||
|
|
||||||
in
|
in
|
||||||
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "filetransfer.hh"
|
#include "filetransfer.hh"
|
||||||
|
@ -1058,7 +1059,7 @@ void EvalState::mkOutputString(
|
||||||
? store->printStorePath(*std::move(optOutputPath))
|
? store->printStorePath(*std::move(optOutputPath))
|
||||||
/* Downstream we would substitute this for an actual path once
|
/* Downstream we would substitute this for an actual path once
|
||||||
we build the floating CA derivation */
|
we build the floating CA derivation */
|
||||||
: downstreamPlaceholder(*store, drvPath, outputName),
|
: DownstreamPlaceholder::unknownCaOutput(drvPath, outputName).render(),
|
||||||
NixStringContext {
|
NixStringContext {
|
||||||
NixStringContextElem::Built {
|
NixStringContextElem::Built {
|
||||||
.drvPath = drvPath,
|
.drvPath = drvPath,
|
||||||
|
@ -2380,7 +2381,7 @@ DerivedPath EvalState::coerceToDerivedPath(const PosIdx pos, Value & v, std::str
|
||||||
// This is testing for the case of CA derivations
|
// This is testing for the case of CA derivations
|
||||||
auto sExpected = optOutputPath
|
auto sExpected = optOutputPath
|
||||||
? store->printStorePath(*optOutputPath)
|
? store->printStorePath(*optOutputPath)
|
||||||
: downstreamPlaceholder(*store, b.drvPath, output);
|
: DownstreamPlaceholder::unknownCaOutput(b.drvPath, output).render();
|
||||||
if (s != sExpected)
|
if (s != sExpected)
|
||||||
error(
|
error(
|
||||||
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
|
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
|
||||||
|
|
|
@ -483,7 +483,7 @@ public:
|
||||||
* Coerce to `DerivedPath`.
|
* Coerce to `DerivedPath`.
|
||||||
*
|
*
|
||||||
* Must be a string which is either a literal store path or a
|
* Must be a string which is either a literal store path or a
|
||||||
* "placeholder (see `downstreamPlaceholder()`).
|
* "placeholder (see `DownstreamPlaceholder`).
|
||||||
*
|
*
|
||||||
* Even more importantly, the string context must be exactly one
|
* Even more importantly, the string context must be exactly one
|
||||||
* element, which is either a `NixStringContextElem::Opaque` or
|
* element, which is either a `NixStringContextElem::Opaque` or
|
||||||
|
@ -622,7 +622,7 @@ public:
|
||||||
* @param optOutputPath Optional output path for that string. Must
|
* @param optOutputPath Optional output path for that string. Must
|
||||||
* be passed if and only if output store object is input-addressed.
|
* be passed if and only if output store object is input-addressed.
|
||||||
* Will be printed to form string if passed, otherwise a placeholder
|
* Will be printed to form string if passed, otherwise a placeholder
|
||||||
* will be used (see `downstreamPlaceholder()`).
|
* will be used (see `DownstreamPlaceholder`).
|
||||||
*/
|
*/
|
||||||
void mkOutputString(
|
void mkOutputString(
|
||||||
Value & value,
|
Value & value,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
@ -87,7 +88,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context)
|
||||||
auto outputs = resolveDerivedPath(*store, drv);
|
auto outputs = resolveDerivedPath(*store, drv);
|
||||||
for (auto & [outputName, outputPath] : outputs) {
|
for (auto & [outputName, outputPath] : outputs) {
|
||||||
res.insert_or_assign(
|
res.insert_or_assign(
|
||||||
downstreamPlaceholder(*store, drv.drvPath, outputName),
|
DownstreamPlaceholder::unknownCaOutput(drv.drvPath, outputName).render(),
|
||||||
store->printStorePath(outputPath)
|
store->printStorePath(outputPath)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ std::optional<std::string> readHead(const Path & path)
|
||||||
.program = "git",
|
.program = "git",
|
||||||
// FIXME: use 'HEAD' to avoid returning all refs
|
// FIXME: use 'HEAD' to avoid returning all refs
|
||||||
.args = {"ls-remote", "--symref", path},
|
.args = {"ls-remote", "--symref", path},
|
||||||
|
.isInteractive = true,
|
||||||
});
|
});
|
||||||
if (status != 0) return std::nullopt;
|
if (status != 0) return std::nullopt;
|
||||||
|
|
||||||
|
@ -350,7 +351,7 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
args.push_back(destDir);
|
args.push_back(destDir);
|
||||||
|
|
||||||
runProgram("git", true, args);
|
runProgram("git", true, args, {}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Path> getSourcePath(const Input & input) override
|
std::optional<Path> getSourcePath(const Input & input) override
|
||||||
|
@ -555,7 +556,7 @@ struct GitInputScheme : InputScheme
|
||||||
: ref == "HEAD"
|
: ref == "HEAD"
|
||||||
? *ref
|
? *ref
|
||||||
: "refs/heads/" + *ref;
|
: "refs/heads/" + *ref;
|
||||||
runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "fetch", "--quiet", "--force", "--", actualUrl, fmt("%s:%s", fetchRef, fetchRef) });
|
runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "fetch", "--quiet", "--force", "--", actualUrl, fmt("%s:%s", fetchRef, fetchRef) }, {}, true);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (!pathExists(localRefFile)) throw;
|
if (!pathExists(localRefFile)) throw;
|
||||||
warn("could not update local clone of Git repository '%s'; continuing with the most recent version", actualUrl);
|
warn("could not update local clone of Git repository '%s'; continuing with the most recent version", actualUrl);
|
||||||
|
@ -622,7 +623,7 @@ struct GitInputScheme : InputScheme
|
||||||
// everything to ensure we get the rev.
|
// everything to ensure we get the rev.
|
||||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("making temporary clone of '%s'", repoDir));
|
Activity act(*logger, lvlTalkative, actUnknown, fmt("making temporary clone of '%s'", repoDir));
|
||||||
runProgram("git", true, { "-C", tmpDir, "fetch", "--quiet", "--force",
|
runProgram("git", true, { "-C", tmpDir, "fetch", "--quiet", "--force",
|
||||||
"--update-head-ok", "--", repoDir, "refs/*:refs/*" });
|
"--update-head-ok", "--", repoDir, "refs/*:refs/*" }, {}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
runProgram("git", true, { "-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev() });
|
runProgram("git", true, { "-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev() });
|
||||||
|
@ -649,7 +650,7 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
{
|
{
|
||||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching submodules of '%s'", actualUrl));
|
Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching submodules of '%s'", actualUrl));
|
||||||
runProgram("git", true, { "-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive" });
|
runProgram("git", true, { "-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive" }, {}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = isNotDotGitDirectory;
|
filter = isNotDotGitDirectory;
|
||||||
|
|
|
@ -1152,7 +1152,7 @@ HookReply DerivationGoal::tryBuildHook()
|
||||||
|
|
||||||
/* Tell the hook all the inputs that have to be copied to the
|
/* Tell the hook all the inputs that have to be copied to the
|
||||||
remote system. */
|
remote system. */
|
||||||
worker_proto::write(worker.store, hook->sink, inputPaths);
|
workerProtoWrite(worker.store, hook->sink, inputPaths);
|
||||||
|
|
||||||
/* Tell the hooks the missing outputs that have to be copied back
|
/* Tell the hooks the missing outputs that have to be copied back
|
||||||
from the remote system. */
|
from the remote system. */
|
||||||
|
@ -1163,7 +1163,7 @@ HookReply DerivationGoal::tryBuildHook()
|
||||||
if (buildMode != bmCheck && status.known && status.known->isValid()) continue;
|
if (buildMode != bmCheck && status.known && status.known->isValid()) continue;
|
||||||
missingOutputs.insert(outputName);
|
missingOutputs.insert(outputName);
|
||||||
}
|
}
|
||||||
worker_proto::write(worker.store, hook->sink, missingOutputs);
|
workerProtoWrite(worker.store, hook->sink, missingOutputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
hook->sink = FdSink();
|
hook->sink = FdSink();
|
||||||
|
|
|
@ -110,7 +110,7 @@ void Store::ensurePath(const StorePath & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalStore::repairPath(const StorePath & path)
|
void Store::repairPath(const StorePath & path)
|
||||||
{
|
{
|
||||||
Worker worker(*this, *this);
|
Worker worker(*this, *this);
|
||||||
GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair);
|
GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair);
|
||||||
|
|
|
@ -1776,6 +1776,8 @@ void LocalDerivationGoal::runChild()
|
||||||
for (auto & path : { "/etc/resolv.conf", "/etc/services", "/etc/hosts" })
|
for (auto & path : { "/etc/resolv.conf", "/etc/services", "/etc/hosts" })
|
||||||
if (pathExists(path))
|
if (pathExists(path))
|
||||||
ss.push_back(path);
|
ss.push_back(path);
|
||||||
|
|
||||||
|
dirsInChroot.emplace(settings.caFile, "/etc/ssl/certs/ca-certificates.crt");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
||||||
|
|
|
@ -263,7 +263,7 @@ static std::vector<DerivedPath> readDerivedPaths(Store & store, unsigned int cli
|
||||||
{
|
{
|
||||||
std::vector<DerivedPath> reqs;
|
std::vector<DerivedPath> reqs;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 30) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 30) {
|
||||||
reqs = worker_proto::read(store, from, Phantom<std::vector<DerivedPath>> {});
|
reqs = WorkerProto<std::vector<DerivedPath>>::read(store, from);
|
||||||
} else {
|
} else {
|
||||||
for (auto & s : readStrings<Strings>(from))
|
for (auto & s : readStrings<Strings>(from))
|
||||||
reqs.push_back(parsePathWithOutputs(store, s).toDerivedPath());
|
reqs.push_back(parsePathWithOutputs(store, s).toDerivedPath());
|
||||||
|
@ -287,7 +287,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
}
|
}
|
||||||
|
|
||||||
case wopQueryValidPaths: {
|
case wopQueryValidPaths: {
|
||||||
auto paths = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
auto paths = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
|
|
||||||
SubstituteFlag substitute = NoSubstitute;
|
SubstituteFlag substitute = NoSubstitute;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 27) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 27) {
|
||||||
|
@ -300,7 +300,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
}
|
}
|
||||||
auto res = store->queryValidPaths(paths, substitute);
|
auto res = store->queryValidPaths(paths, substitute);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, res);
|
workerProtoWrite(*store, to, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,11 +316,11 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
}
|
}
|
||||||
|
|
||||||
case wopQuerySubstitutablePaths: {
|
case wopQuerySubstitutablePaths: {
|
||||||
auto paths = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
auto paths = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
auto res = store->querySubstitutablePaths(paths);
|
auto res = store->querySubstitutablePaths(paths);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, res);
|
workerProtoWrite(*store, to, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
paths = store->queryValidDerivers(path);
|
paths = store->queryValidDerivers(path);
|
||||||
else paths = store->queryDerivationOutputs(path);
|
else paths = store->queryDerivationOutputs(path);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, paths);
|
workerProtoWrite(*store, to, paths);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
auto outputs = store->queryPartialDerivationOutputMap(path);
|
auto outputs = store->queryPartialDerivationOutputMap(path);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, outputs);
|
workerProtoWrite(*store, to, outputs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 25) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 25) {
|
||||||
auto name = readString(from);
|
auto name = readString(from);
|
||||||
auto camStr = readString(from);
|
auto camStr = readString(from);
|
||||||
auto refs = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
auto refs = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
bool repairBool;
|
bool repairBool;
|
||||||
from >> repairBool;
|
from >> repairBool;
|
||||||
auto repair = RepairFlag{repairBool};
|
auto repair = RepairFlag{repairBool};
|
||||||
|
@ -495,7 +495,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
case wopAddTextToStore: {
|
case wopAddTextToStore: {
|
||||||
std::string suffix = readString(from);
|
std::string suffix = readString(from);
|
||||||
std::string s = readString(from);
|
std::string s = readString(from);
|
||||||
auto refs = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
auto refs = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
auto path = store->addTextToStore(suffix, s, refs, NoRepair);
|
auto path = store->addTextToStore(suffix, s, refs, NoRepair);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
|
@ -567,7 +567,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
auto results = store->buildPathsWithResults(drvs, mode);
|
auto results = store->buildPathsWithResults(drvs, mode);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
|
|
||||||
worker_proto::write(*store, to, results);
|
workerProtoWrite(*store, to, results);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -644,7 +644,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
DrvOutputs builtOutputs;
|
DrvOutputs builtOutputs;
|
||||||
for (auto & [output, realisation] : res.builtOutputs)
|
for (auto & [output, realisation] : res.builtOutputs)
|
||||||
builtOutputs.insert_or_assign(realisation.id, realisation);
|
builtOutputs.insert_or_assign(realisation.id, realisation);
|
||||||
worker_proto::write(*store, to, builtOutputs);
|
workerProtoWrite(*store, to, builtOutputs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -709,7 +709,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
case wopCollectGarbage: {
|
case wopCollectGarbage: {
|
||||||
GCOptions options;
|
GCOptions options;
|
||||||
options.action = (GCOptions::GCAction) readInt(from);
|
options.action = (GCOptions::GCAction) readInt(from);
|
||||||
options.pathsToDelete = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
options.pathsToDelete = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
from >> options.ignoreLiveness >> options.maxFreed;
|
from >> options.ignoreLiveness >> options.maxFreed;
|
||||||
// obsolete fields
|
// obsolete fields
|
||||||
readInt(from);
|
readInt(from);
|
||||||
|
@ -779,7 +779,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
else {
|
else {
|
||||||
to << 1
|
to << 1
|
||||||
<< (i->second.deriver ? store->printStorePath(*i->second.deriver) : "");
|
<< (i->second.deriver ? store->printStorePath(*i->second.deriver) : "");
|
||||||
worker_proto::write(*store, to, i->second.references);
|
workerProtoWrite(*store, to, i->second.references);
|
||||||
to << i->second.downloadSize
|
to << i->second.downloadSize
|
||||||
<< i->second.narSize;
|
<< i->second.narSize;
|
||||||
}
|
}
|
||||||
|
@ -790,11 +790,11 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
SubstitutablePathInfos infos;
|
SubstitutablePathInfos infos;
|
||||||
StorePathCAMap pathsMap = {};
|
StorePathCAMap pathsMap = {};
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) < 22) {
|
if (GET_PROTOCOL_MINOR(clientVersion) < 22) {
|
||||||
auto paths = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
auto paths = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
for (auto & path : paths)
|
for (auto & path : paths)
|
||||||
pathsMap.emplace(path, std::nullopt);
|
pathsMap.emplace(path, std::nullopt);
|
||||||
} else
|
} else
|
||||||
pathsMap = worker_proto::read(*store, from, Phantom<StorePathCAMap> {});
|
pathsMap = WorkerProto<StorePathCAMap>::read(*store, from);
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
store->querySubstitutablePathInfos(pathsMap, infos);
|
store->querySubstitutablePathInfos(pathsMap, infos);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
|
@ -802,7 +802,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
for (auto & i : infos) {
|
for (auto & i : infos) {
|
||||||
to << store->printStorePath(i.first)
|
to << store->printStorePath(i.first)
|
||||||
<< (i.second.deriver ? store->printStorePath(*i.second.deriver) : "");
|
<< (i.second.deriver ? store->printStorePath(*i.second.deriver) : "");
|
||||||
worker_proto::write(*store, to, i.second.references);
|
workerProtoWrite(*store, to, i.second.references);
|
||||||
to << i.second.downloadSize << i.second.narSize;
|
to << i.second.downloadSize << i.second.narSize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -812,7 +812,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
auto paths = store->queryAllValidPaths();
|
auto paths = store->queryAllValidPaths();
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, paths);
|
workerProtoWrite(*store, to, paths);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +884,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
ValidPathInfo info { path, narHash };
|
ValidPathInfo info { path, narHash };
|
||||||
if (deriver != "")
|
if (deriver != "")
|
||||||
info.deriver = store->parseStorePath(deriver);
|
info.deriver = store->parseStorePath(deriver);
|
||||||
info.references = worker_proto::read(*store, from, Phantom<StorePathSet> {});
|
info.references = WorkerProto<StorePathSet>::read(*store, from);
|
||||||
from >> info.registrationTime >> info.narSize >> info.ultimate;
|
from >> info.registrationTime >> info.narSize >> info.ultimate;
|
||||||
info.sigs = readStrings<StringSet>(from);
|
info.sigs = readStrings<StringSet>(from);
|
||||||
info.ca = ContentAddress::parseOpt(readString(from));
|
info.ca = ContentAddress::parseOpt(readString(from));
|
||||||
|
@ -935,9 +935,9 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
uint64_t downloadSize, narSize;
|
uint64_t downloadSize, narSize;
|
||||||
store->queryMissing(targets, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
store->queryMissing(targets, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
worker_proto::write(*store, to, willBuild);
|
workerProtoWrite(*store, to, willBuild);
|
||||||
worker_proto::write(*store, to, willSubstitute);
|
workerProtoWrite(*store, to, willSubstitute);
|
||||||
worker_proto::write(*store, to, unknown);
|
workerProtoWrite(*store, to, unknown);
|
||||||
to << downloadSize << narSize;
|
to << downloadSize << narSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -950,7 +950,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
store->registerDrvOutput(Realisation{
|
store->registerDrvOutput(Realisation{
|
||||||
.id = outputId, .outPath = outputPath});
|
.id = outputId, .outPath = outputPath});
|
||||||
} else {
|
} else {
|
||||||
auto realisation = worker_proto::read(*store, from, Phantom<Realisation>());
|
auto realisation = WorkerProto<Realisation>::read(*store, from);
|
||||||
store->registerDrvOutput(realisation);
|
store->registerDrvOutput(realisation);
|
||||||
}
|
}
|
||||||
logger->stopWork();
|
logger->stopWork();
|
||||||
|
@ -965,11 +965,11 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) < 31) {
|
if (GET_PROTOCOL_MINOR(clientVersion) < 31) {
|
||||||
std::set<StorePath> outPaths;
|
std::set<StorePath> outPaths;
|
||||||
if (info) outPaths.insert(info->outPath);
|
if (info) outPaths.insert(info->outPath);
|
||||||
worker_proto::write(*store, to, outPaths);
|
workerProtoWrite(*store, to, outPaths);
|
||||||
} else {
|
} else {
|
||||||
std::set<Realisation> realisations;
|
std::set<Realisation> realisations;
|
||||||
if (info) realisations.insert(*info);
|
if (info) realisations.insert(*info);
|
||||||
worker_proto::write(*store, to, realisations);
|
workerProtoWrite(*store, to, realisations);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1045,7 +1045,7 @@ void processConnection(
|
||||||
auto temp = trusted
|
auto temp = trusted
|
||||||
? store->isTrustedClient()
|
? store->isTrustedClient()
|
||||||
: std::optional { NotTrusted };
|
: std::optional { NotTrusted };
|
||||||
worker_proto::write(*store, to, temp);
|
workerProtoWrite(*store, to, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send startup error messages to the client. */
|
/* Send startup error messages to the client. */
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
@ -748,7 +749,7 @@ Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv,
|
||||||
drv.outputs.emplace(std::move(name), std::move(output));
|
drv.outputs.emplace(std::move(name), std::move(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
drv.inputSrcs = worker_proto::read(store, in, Phantom<StorePathSet> {});
|
drv.inputSrcs = WorkerProto<StorePathSet>::read(store, in);
|
||||||
in >> drv.platform >> drv.builder;
|
in >> drv.platform >> drv.builder;
|
||||||
drv.args = readStrings<Strings>(in);
|
drv.args = readStrings<Strings>(in);
|
||||||
|
|
||||||
|
@ -796,7 +797,7 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
},
|
},
|
||||||
}, i.second.raw());
|
}, i.second.raw());
|
||||||
}
|
}
|
||||||
worker_proto::write(store, out, drv.inputSrcs);
|
workerProtoWrite(store, out, drv.inputSrcs);
|
||||||
out << drv.platform << drv.builder << drv.args;
|
out << drv.platform << drv.builder << drv.args;
|
||||||
out << drv.env.size();
|
out << drv.env.size();
|
||||||
for (auto & i : drv.env)
|
for (auto & i : drv.env)
|
||||||
|
@ -810,13 +811,7 @@ std::string hashPlaceholder(const std::string_view outputName)
|
||||||
return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(Base32, false);
|
return "/" + hashString(htSHA256, concatStrings("nix-output:", outputName)).to_string(Base32, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName)
|
|
||||||
{
|
|
||||||
auto drvNameWithExtension = drvPath.name();
|
|
||||||
auto drvName = drvNameWithExtension.substr(0, drvNameWithExtension.size() - 4);
|
|
||||||
auto clearText = "nix-upstream-output:" + std::string { drvPath.hashPart() } + ":" + outputPathName(drvName, outputName);
|
|
||||||
return "/" + hashString(htSHA256, clearText).to_string(Base32, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void rewriteDerivation(Store & store, BasicDerivation & drv, const StringMap & rewrites)
|
static void rewriteDerivation(Store & store, BasicDerivation & drv, const StringMap & rewrites)
|
||||||
|
@ -880,7 +875,7 @@ std::optional<BasicDerivation> Derivation::tryResolve(
|
||||||
for (auto & outputName : inputOutputs) {
|
for (auto & outputName : inputOutputs) {
|
||||||
if (auto actualPath = get(inputDrvOutputs, { inputDrv, outputName })) {
|
if (auto actualPath = get(inputDrvOutputs, { inputDrv, outputName })) {
|
||||||
inputRewrites.emplace(
|
inputRewrites.emplace(
|
||||||
downstreamPlaceholder(store, inputDrv, outputName),
|
DownstreamPlaceholder::unknownCaOutput(inputDrv, outputName).render(),
|
||||||
store.printStorePath(*actualPath));
|
store.printStorePath(*actualPath));
|
||||||
resolved.inputSrcs.insert(*actualPath);
|
resolved.inputSrcs.insert(*actualPath);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "content-address.hh"
|
#include "content-address.hh"
|
||||||
#include "repair-flag.hh"
|
#include "repair-flag.hh"
|
||||||
|
#include "derived-path.hh"
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
#include "comparator.hh"
|
#include "comparator.hh"
|
||||||
|
|
||||||
|
@ -495,17 +496,6 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
*/
|
*/
|
||||||
std::string hashPlaceholder(const std::string_view outputName);
|
std::string hashPlaceholder(const std::string_view outputName);
|
||||||
|
|
||||||
/**
|
|
||||||
* This creates an opaque and almost certainly unique string
|
|
||||||
* deterministically from a derivation path and output name.
|
|
||||||
*
|
|
||||||
* It is used as a placeholder to allow derivations to refer to
|
|
||||||
* content-addressed paths whose content --- and thus the path
|
|
||||||
* themselves --- isn't yet known. This occurs when a derivation has a
|
|
||||||
* dependency which is a CA derivation.
|
|
||||||
*/
|
|
||||||
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName);
|
|
||||||
|
|
||||||
extern const Hash impureOutputHash;
|
extern const Hash impureOutputHash;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
39
src/libstore/downstream-placeholder.cc
Normal file
39
src/libstore/downstream-placeholder.cc
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::string DownstreamPlaceholder::render() const
|
||||||
|
{
|
||||||
|
return "/" + hash.to_string(Base32, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownstreamPlaceholder DownstreamPlaceholder::unknownCaOutput(
|
||||||
|
const StorePath & drvPath,
|
||||||
|
std::string_view outputName)
|
||||||
|
{
|
||||||
|
auto drvNameWithExtension = drvPath.name();
|
||||||
|
auto drvName = drvNameWithExtension.substr(0, drvNameWithExtension.size() - 4);
|
||||||
|
auto clearText = "nix-upstream-output:" + std::string { drvPath.hashPart() } + ":" + outputPathName(drvName, outputName);
|
||||||
|
return DownstreamPlaceholder {
|
||||||
|
hashString(htSHA256, clearText)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DownstreamPlaceholder DownstreamPlaceholder::unknownDerivation(
|
||||||
|
const DownstreamPlaceholder & placeholder,
|
||||||
|
std::string_view outputName,
|
||||||
|
const ExperimentalFeatureSettings & xpSettings)
|
||||||
|
{
|
||||||
|
xpSettings.require(Xp::DynamicDerivations);
|
||||||
|
auto compressed = compressHash(placeholder.hash, 20);
|
||||||
|
auto clearText = "nix-computed-output:"
|
||||||
|
+ compressed.to_string(Base32, false)
|
||||||
|
+ ":" + std::string { outputName };
|
||||||
|
return DownstreamPlaceholder {
|
||||||
|
hashString(htSHA256, clearText)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
src/libstore/downstream-placeholder.hh
Normal file
75
src/libstore/downstream-placeholder.hh
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include "hash.hh"
|
||||||
|
#include "path.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downstream Placeholders are opaque and almost certainly unique values
|
||||||
|
* used to allow derivations to refer to store objects which are yet to
|
||||||
|
* be built and for we do not yet have store paths for.
|
||||||
|
*
|
||||||
|
* They correspond to `DerivedPaths` that are not `DerivedPath::Opaque`,
|
||||||
|
* except for the cases involving input addressing or fixed outputs
|
||||||
|
* where we do know a store path for the derivation output in advance.
|
||||||
|
*
|
||||||
|
* Unlike `DerivationPath`, however, `DownstreamPlaceholder` is
|
||||||
|
* purposefully opaque and obfuscated. This is so they are hard to
|
||||||
|
* create by accident, and so substituting them (once we know what the
|
||||||
|
* path to store object is) is unlikely to capture other stuff it
|
||||||
|
* shouldn't.
|
||||||
|
*
|
||||||
|
* We use them with `Derivation`: the `render()` method is called to
|
||||||
|
* render an opaque string which can be used in the derivation, and the
|
||||||
|
* resolving logic can substitute those strings for store paths when
|
||||||
|
* resolving `Derivation.inputDrvs` to `BasicDerivation.inputSrcs`.
|
||||||
|
*/
|
||||||
|
class DownstreamPlaceholder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* `DownstreamPlaceholder` is just a newtype of `Hash`.
|
||||||
|
* This its only field.
|
||||||
|
*/
|
||||||
|
Hash hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Newtype constructor
|
||||||
|
*/
|
||||||
|
DownstreamPlaceholder(Hash hash) : hash(hash) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* This creates an opaque and almost certainly unique string
|
||||||
|
* deterministically from the placeholder.
|
||||||
|
*/
|
||||||
|
std::string render() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a placeholder for an unknown output of a content-addressed
|
||||||
|
* derivation.
|
||||||
|
*
|
||||||
|
* The derivation itself is known (we have a store path for it), but
|
||||||
|
* the output doesn't yet have a known store path.
|
||||||
|
*/
|
||||||
|
static DownstreamPlaceholder unknownCaOutput(
|
||||||
|
const StorePath & drvPath,
|
||||||
|
std::string_view outputName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a placehold for the output of an unknown derivation.
|
||||||
|
*
|
||||||
|
* The derivation is not yet known because it is a dynamic
|
||||||
|
* derivaiton --- it is itself an output of another derivation ---
|
||||||
|
* and we just have (another) placeholder for it.
|
||||||
|
*
|
||||||
|
* @param xpSettings Stop-gap to avoid globals during unit tests.
|
||||||
|
*/
|
||||||
|
static DownstreamPlaceholder unknownDerivation(
|
||||||
|
const DownstreamPlaceholder & drvPlaceholder,
|
||||||
|
std::string_view outputName,
|
||||||
|
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ void Store::exportPath(const StorePath & path, Sink & sink)
|
||||||
teeSink
|
teeSink
|
||||||
<< exportMagic
|
<< exportMagic
|
||||||
<< printStorePath(path);
|
<< printStorePath(path);
|
||||||
worker_proto::write(*this, teeSink, info->references);
|
workerProtoWrite(*this, teeSink, info->references);
|
||||||
teeSink
|
teeSink
|
||||||
<< (info->deriver ? printStorePath(*info->deriver) : "")
|
<< (info->deriver ? printStorePath(*info->deriver) : "")
|
||||||
<< 0;
|
<< 0;
|
||||||
|
@ -73,7 +73,7 @@ StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs)
|
||||||
|
|
||||||
//Activity act(*logger, lvlInfo, "importing path '%s'", info.path);
|
//Activity act(*logger, lvlInfo, "importing path '%s'", info.path);
|
||||||
|
|
||||||
auto references = worker_proto::read(*this, source, Phantom<StorePathSet> {});
|
auto references = WorkerProto<StorePathSet>::read(*this, source);
|
||||||
auto deriver = readString(source);
|
auto deriver = readString(source);
|
||||||
auto narHash = hashString(htSHA256, saved.s);
|
auto narHash = hashString(htSHA256, saved.s);
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
||||||
auto deriver = readString(conn->from);
|
auto deriver = readString(conn->from);
|
||||||
if (deriver != "")
|
if (deriver != "")
|
||||||
info->deriver = parseStorePath(deriver);
|
info->deriver = parseStorePath(deriver);
|
||||||
info->references = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
info->references = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
readLongLong(conn->from); // download size
|
readLongLong(conn->from); // download size
|
||||||
info->narSize = readLongLong(conn->from);
|
info->narSize = readLongLong(conn->from);
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
||||||
<< printStorePath(info.path)
|
<< printStorePath(info.path)
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< info.narHash.to_string(Base16, false);
|
<< info.narHash.to_string(Base16, false);
|
||||||
worker_proto::write(*this, conn->to, info.references);
|
workerProtoWrite(*this, conn->to, info.references);
|
||||||
conn->to
|
conn->to
|
||||||
<< info.registrationTime
|
<< info.registrationTime
|
||||||
<< info.narSize
|
<< info.narSize
|
||||||
|
@ -209,7 +209,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
||||||
conn->to
|
conn->to
|
||||||
<< exportMagic
|
<< exportMagic
|
||||||
<< printStorePath(info.path);
|
<< printStorePath(info.path);
|
||||||
worker_proto::write(*this, conn->to, info.references);
|
workerProtoWrite(*this, conn->to, info.references);
|
||||||
conn->to
|
conn->to
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< 0
|
<< 0
|
||||||
|
@ -294,7 +294,7 @@ public:
|
||||||
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
|
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
|
||||||
conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime;
|
conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime;
|
||||||
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 6) {
|
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 6) {
|
||||||
auto builtOutputs = worker_proto::read(*this, conn->from, Phantom<DrvOutputs> {});
|
auto builtOutputs = WorkerProto<DrvOutputs>::read(*this, conn->from);
|
||||||
for (auto && [output, realisation] : builtOutputs)
|
for (auto && [output, realisation] : builtOutputs)
|
||||||
status.builtOutputs.insert_or_assign(
|
status.builtOutputs.insert_or_assign(
|
||||||
std::move(output.outputName),
|
std::move(output.outputName),
|
||||||
|
@ -344,6 +344,17 @@ public:
|
||||||
virtual ref<FSAccessor> getFSAccessor() override
|
virtual ref<FSAccessor> getFSAccessor() override
|
||||||
{ unsupported("getFSAccessor"); }
|
{ unsupported("getFSAccessor"); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default instance would schedule the work on the client side, but
|
||||||
|
* for consistency with `buildPaths` and `buildDerivation` it should happen
|
||||||
|
* on the remote side.
|
||||||
|
*
|
||||||
|
* We make this fail for now so we can add implement this properly later
|
||||||
|
* without it being a breaking change.
|
||||||
|
*/
|
||||||
|
void repairPath(const StorePath & path) override
|
||||||
|
{ unsupported("repairPath"); }
|
||||||
|
|
||||||
void computeFSClosure(const StorePathSet & paths,
|
void computeFSClosure(const StorePathSet & paths,
|
||||||
StorePathSet & out, bool flipDirection = false,
|
StorePathSet & out, bool flipDirection = false,
|
||||||
bool includeOutputs = false, bool includeDerivers = false) override
|
bool includeOutputs = false, bool includeDerivers = false) override
|
||||||
|
@ -358,10 +369,10 @@ public:
|
||||||
conn->to
|
conn->to
|
||||||
<< cmdQueryClosure
|
<< cmdQueryClosure
|
||||||
<< includeOutputs;
|
<< includeOutputs;
|
||||||
worker_proto::write(*this, conn->to, paths);
|
workerProtoWrite(*this, conn->to, paths);
|
||||||
conn->to.flush();
|
conn->to.flush();
|
||||||
|
|
||||||
for (auto & i : worker_proto::read(*this, conn->from, Phantom<StorePathSet> {}))
|
for (auto & i : WorkerProto<StorePathSet>::read(*this, conn->from))
|
||||||
out.insert(i);
|
out.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,10 +385,10 @@ public:
|
||||||
<< cmdQueryValidPaths
|
<< cmdQueryValidPaths
|
||||||
<< false // lock
|
<< false // lock
|
||||||
<< maybeSubstitute;
|
<< maybeSubstitute;
|
||||||
worker_proto::write(*this, conn->to, paths);
|
workerProtoWrite(*this, conn->to, paths);
|
||||||
conn->to.flush();
|
conn->to.flush();
|
||||||
|
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect() override
|
void connect() override
|
||||||
|
|
|
@ -256,8 +256,6 @@ public:
|
||||||
|
|
||||||
void vacuumDB();
|
void vacuumDB();
|
||||||
|
|
||||||
void repairPath(const StorePath & path) override;
|
|
||||||
|
|
||||||
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "path-info.hh"
|
#include "path-info.hh"
|
||||||
#include "worker-protocol.hh"
|
#include "worker-protocol.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -131,7 +132,7 @@ ValidPathInfo ValidPathInfo::read(Source & source, const Store & store, unsigned
|
||||||
auto narHash = Hash::parseAny(readString(source), htSHA256);
|
auto narHash = Hash::parseAny(readString(source), htSHA256);
|
||||||
ValidPathInfo info(path, narHash);
|
ValidPathInfo info(path, narHash);
|
||||||
if (deriver != "") info.deriver = store.parseStorePath(deriver);
|
if (deriver != "") info.deriver = store.parseStorePath(deriver);
|
||||||
info.references = worker_proto::read(store, source, Phantom<StorePathSet> {});
|
info.references = WorkerProto<StorePathSet>::read(store, source);
|
||||||
source >> info.registrationTime >> info.narSize;
|
source >> info.registrationTime >> info.narSize;
|
||||||
if (format >= 16) {
|
if (format >= 16) {
|
||||||
source >> info.ultimate;
|
source >> info.ultimate;
|
||||||
|
@ -152,7 +153,7 @@ void ValidPathInfo::write(
|
||||||
sink << store.printStorePath(path);
|
sink << store.printStorePath(path);
|
||||||
sink << (deriver ? store.printStorePath(*deriver) : "")
|
sink << (deriver ? store.printStorePath(*deriver) : "")
|
||||||
<< narHash.to_string(Base16, false);
|
<< narHash.to_string(Base16, false);
|
||||||
worker_proto::write(store, sink, references);
|
workerProtoWrite(store, sink, references);
|
||||||
sink << registrationTime << narSize;
|
sink << registrationTime << narSize;
|
||||||
if (format >= 16) {
|
if (format >= 16) {
|
||||||
sink << ultimate
|
sink << ultimate
|
||||||
|
|
|
@ -18,189 +18,6 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
namespace worker_proto {
|
|
||||||
|
|
||||||
std::string read(const Store & store, Source & from, Phantom<std::string> _)
|
|
||||||
{
|
|
||||||
return readString(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const std::string & str)
|
|
||||||
{
|
|
||||||
out << str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
StorePath read(const Store & store, Source & from, Phantom<StorePath> _)
|
|
||||||
{
|
|
||||||
return store.parseStorePath(readString(from));
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const StorePath & storePath)
|
|
||||||
{
|
|
||||||
out << store.printStorePath(storePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<TrustedFlag> read(const Store & store, Source & from, Phantom<std::optional<TrustedFlag>> _)
|
|
||||||
{
|
|
||||||
auto temp = readNum<uint8_t>(from);
|
|
||||||
switch (temp) {
|
|
||||||
case 0:
|
|
||||||
return std::nullopt;
|
|
||||||
case 1:
|
|
||||||
return { Trusted };
|
|
||||||
case 2:
|
|
||||||
return { NotTrusted };
|
|
||||||
default:
|
|
||||||
throw Error("Invalid trusted status from remote");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const std::optional<TrustedFlag> & optTrusted)
|
|
||||||
{
|
|
||||||
if (!optTrusted)
|
|
||||||
out << (uint8_t)0;
|
|
||||||
else {
|
|
||||||
switch (*optTrusted) {
|
|
||||||
case Trusted:
|
|
||||||
out << (uint8_t)1;
|
|
||||||
break;
|
|
||||||
case NotTrusted:
|
|
||||||
out << (uint8_t)2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ContentAddress read(const Store & store, Source & from, Phantom<ContentAddress> _)
|
|
||||||
{
|
|
||||||
return ContentAddress::parse(readString(from));
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const ContentAddress & ca)
|
|
||||||
{
|
|
||||||
out << renderContentAddress(ca);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DerivedPath read(const Store & store, Source & from, Phantom<DerivedPath> _)
|
|
||||||
{
|
|
||||||
auto s = readString(from);
|
|
||||||
return DerivedPath::parseLegacy(store, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const DerivedPath & req)
|
|
||||||
{
|
|
||||||
out << req.to_string_legacy(store);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Realisation read(const Store & store, Source & from, Phantom<Realisation> _)
|
|
||||||
{
|
|
||||||
std::string rawInput = readString(from);
|
|
||||||
return Realisation::fromJSON(
|
|
||||||
nlohmann::json::parse(rawInput),
|
|
||||||
"remote-protocol"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const Realisation & realisation)
|
|
||||||
{
|
|
||||||
out << realisation.toJSON().dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DrvOutput read(const Store & store, Source & from, Phantom<DrvOutput> _)
|
|
||||||
{
|
|
||||||
return DrvOutput::parse(readString(from));
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const DrvOutput & drvOutput)
|
|
||||||
{
|
|
||||||
out << drvOutput.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
KeyedBuildResult read(const Store & store, Source & from, Phantom<KeyedBuildResult> _)
|
|
||||||
{
|
|
||||||
auto path = worker_proto::read(store, from, Phantom<DerivedPath> {});
|
|
||||||
auto br = worker_proto::read(store, from, Phantom<BuildResult> {});
|
|
||||||
return KeyedBuildResult {
|
|
||||||
std::move(br),
|
|
||||||
/* .path = */ std::move(path),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & to, const KeyedBuildResult & res)
|
|
||||||
{
|
|
||||||
worker_proto::write(store, to, res.path);
|
|
||||||
worker_proto::write(store, to, static_cast<const BuildResult &>(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BuildResult read(const Store & store, Source & from, Phantom<BuildResult> _)
|
|
||||||
{
|
|
||||||
BuildResult res;
|
|
||||||
res.status = (BuildResult::Status) readInt(from);
|
|
||||||
from
|
|
||||||
>> res.errorMsg
|
|
||||||
>> res.timesBuilt
|
|
||||||
>> res.isNonDeterministic
|
|
||||||
>> res.startTime
|
|
||||||
>> res.stopTime;
|
|
||||||
auto builtOutputs = worker_proto::read(store, from, Phantom<DrvOutputs> {});
|
|
||||||
for (auto && [output, realisation] : builtOutputs)
|
|
||||||
res.builtOutputs.insert_or_assign(
|
|
||||||
std::move(output.outputName),
|
|
||||||
std::move(realisation));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & to, const BuildResult & res)
|
|
||||||
{
|
|
||||||
to
|
|
||||||
<< res.status
|
|
||||||
<< res.errorMsg
|
|
||||||
<< res.timesBuilt
|
|
||||||
<< res.isNonDeterministic
|
|
||||||
<< res.startTime
|
|
||||||
<< res.stopTime;
|
|
||||||
DrvOutputs builtOutputs;
|
|
||||||
for (auto & [output, realisation] : res.builtOutputs)
|
|
||||||
builtOutputs.insert_or_assign(realisation.id, realisation);
|
|
||||||
worker_proto::write(store, to, builtOutputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<StorePath> read(const Store & store, Source & from, Phantom<std::optional<StorePath>> _)
|
|
||||||
{
|
|
||||||
auto s = readString(from);
|
|
||||||
return s == "" ? std::optional<StorePath> {} : store.parseStorePath(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const std::optional<StorePath> & storePathOpt)
|
|
||||||
{
|
|
||||||
out << (storePathOpt ? store.printStorePath(*storePathOpt) : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<ContentAddress> read(const Store & store, Source & from, Phantom<std::optional<ContentAddress>> _)
|
|
||||||
{
|
|
||||||
return ContentAddress::parseOpt(readString(from));
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const Store & store, Sink & out, const std::optional<ContentAddress> & caOpt)
|
|
||||||
{
|
|
||||||
out << (caOpt ? renderContentAddress(*caOpt) : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Separate these store impls into different files, give them better names */
|
/* TODO: Separate these store impls into different files, give them better names */
|
||||||
RemoteStore::RemoteStore(const Params & params)
|
RemoteStore::RemoteStore(const Params & params)
|
||||||
: RemoteStoreConfig(params)
|
: RemoteStoreConfig(params)
|
||||||
|
@ -283,7 +100,7 @@ void RemoteStore::initConnection(Connection & conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 35) {
|
if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 35) {
|
||||||
conn.remoteTrustsUs = worker_proto::read(*this, conn.from, Phantom<std::optional<TrustedFlag>> {});
|
conn.remoteTrustsUs = WorkerProto<std::optional<TrustedFlag>>::read(*this, conn.from);
|
||||||
} else {
|
} else {
|
||||||
// We don't know the answer; protocol to old.
|
// We don't know the answer; protocol to old.
|
||||||
conn.remoteTrustsUs = std::nullopt;
|
conn.remoteTrustsUs = std::nullopt;
|
||||||
|
@ -410,12 +227,12 @@ StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, Substitute
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
conn->to << wopQueryValidPaths;
|
conn->to << wopQueryValidPaths;
|
||||||
worker_proto::write(*this, conn->to, paths);
|
workerProtoWrite(*this, conn->to, paths);
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 27) {
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 27) {
|
||||||
conn->to << (settings.buildersUseSubstitutes ? 1 : 0);
|
conn->to << (settings.buildersUseSubstitutes ? 1 : 0);
|
||||||
}
|
}
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +242,7 @@ StorePathSet RemoteStore::queryAllValidPaths()
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
conn->to << wopQueryAllValidPaths;
|
conn->to << wopQueryAllValidPaths;
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -442,9 +259,9 @@ StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths)
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
conn->to << wopQuerySubstitutablePaths;
|
conn->to << wopQuerySubstitutablePaths;
|
||||||
worker_proto::write(*this, conn->to, paths);
|
workerProtoWrite(*this, conn->to, paths);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +283,7 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
|
||||||
auto deriver = readString(conn->from);
|
auto deriver = readString(conn->from);
|
||||||
if (deriver != "")
|
if (deriver != "")
|
||||||
info.deriver = parseStorePath(deriver);
|
info.deriver = parseStorePath(deriver);
|
||||||
info.references = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
info.references = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
info.downloadSize = readLongLong(conn->from);
|
info.downloadSize = readLongLong(conn->from);
|
||||||
info.narSize = readLongLong(conn->from);
|
info.narSize = readLongLong(conn->from);
|
||||||
infos.insert_or_assign(i.first, std::move(info));
|
infos.insert_or_assign(i.first, std::move(info));
|
||||||
|
@ -479,9 +296,9 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
|
||||||
StorePathSet paths;
|
StorePathSet paths;
|
||||||
for (auto & path : pathsMap)
|
for (auto & path : pathsMap)
|
||||||
paths.insert(path.first);
|
paths.insert(path.first);
|
||||||
worker_proto::write(*this, conn->to, paths);
|
workerProtoWrite(*this, conn->to, paths);
|
||||||
} else
|
} else
|
||||||
worker_proto::write(*this, conn->to, pathsMap);
|
workerProtoWrite(*this, conn->to, pathsMap);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
size_t count = readNum<size_t>(conn->from);
|
size_t count = readNum<size_t>(conn->from);
|
||||||
for (size_t n = 0; n < count; n++) {
|
for (size_t n = 0; n < count; n++) {
|
||||||
|
@ -489,7 +306,7 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
|
||||||
auto deriver = readString(conn->from);
|
auto deriver = readString(conn->from);
|
||||||
if (deriver != "")
|
if (deriver != "")
|
||||||
info.deriver = parseStorePath(deriver);
|
info.deriver = parseStorePath(deriver);
|
||||||
info.references = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
info.references = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
info.downloadSize = readLongLong(conn->from);
|
info.downloadSize = readLongLong(conn->from);
|
||||||
info.narSize = readLongLong(conn->from);
|
info.narSize = readLongLong(conn->from);
|
||||||
}
|
}
|
||||||
|
@ -532,7 +349,7 @@ void RemoteStore::queryReferrers(const StorePath & path,
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
conn->to << wopQueryReferrers << printStorePath(path);
|
conn->to << wopQueryReferrers << printStorePath(path);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
for (auto & i : worker_proto::read(*this, conn->from, Phantom<StorePathSet> {}))
|
for (auto & i : WorkerProto<StorePathSet>::read(*this, conn->from))
|
||||||
referrers.insert(i);
|
referrers.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +359,7 @@ StorePathSet RemoteStore::queryValidDerivers(const StorePath & path)
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
conn->to << wopQueryValidDerivers << printStorePath(path);
|
conn->to << wopQueryValidDerivers << printStorePath(path);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,7 +371,7 @@ StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path)
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
conn->to << wopQueryDerivationOutputs << printStorePath(path);
|
conn->to << wopQueryDerivationOutputs << printStorePath(path);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
return WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -564,7 +381,7 @@ std::map<std::string, std::optional<StorePath>> RemoteStore::queryPartialDerivat
|
||||||
auto conn(getConnection());
|
auto conn(getConnection());
|
||||||
conn->to << wopQueryDerivationOutputMap << printStorePath(path);
|
conn->to << wopQueryDerivationOutputMap << printStorePath(path);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<std::map<std::string, std::optional<StorePath>>> {});
|
return WorkerProto<std::map<std::string, std::optional<StorePath>>>::read(*this, conn->from);
|
||||||
} else {
|
} else {
|
||||||
// Fallback for old daemon versions.
|
// Fallback for old daemon versions.
|
||||||
// For floating-CA derivations (and their co-dependencies) this is an
|
// For floating-CA derivations (and their co-dependencies) this is an
|
||||||
|
@ -610,7 +427,7 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
|
||||||
<< wopAddToStore
|
<< wopAddToStore
|
||||||
<< name
|
<< name
|
||||||
<< caMethod.render(hashType);
|
<< caMethod.render(hashType);
|
||||||
worker_proto::write(*this, conn->to, references);
|
workerProtoWrite(*this, conn->to, references);
|
||||||
conn->to << repair;
|
conn->to << repair;
|
||||||
|
|
||||||
// The dump source may invoke the store, so we need to make some room.
|
// The dump source may invoke the store, so we need to make some room.
|
||||||
|
@ -635,7 +452,7 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
|
||||||
name, printHashType(hashType));
|
name, printHashType(hashType));
|
||||||
std::string s = dump.drain();
|
std::string s = dump.drain();
|
||||||
conn->to << wopAddTextToStore << name << s;
|
conn->to << wopAddTextToStore << name << s;
|
||||||
worker_proto::write(*this, conn->to, references);
|
workerProtoWrite(*this, conn->to, references);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
},
|
},
|
||||||
[&](const FileIngestionMethod & fim) -> void {
|
[&](const FileIngestionMethod & fim) -> void {
|
||||||
|
@ -701,7 +518,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
sink
|
sink
|
||||||
<< exportMagic
|
<< exportMagic
|
||||||
<< printStorePath(info.path);
|
<< printStorePath(info.path);
|
||||||
worker_proto::write(*this, sink, info.references);
|
workerProtoWrite(*this, sink, info.references);
|
||||||
sink
|
sink
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< 0 // == no legacy signature
|
<< 0 // == no legacy signature
|
||||||
|
@ -711,7 +528,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
|
|
||||||
conn.processStderr(0, source2.get());
|
conn.processStderr(0, source2.get());
|
||||||
|
|
||||||
auto importedPaths = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
auto importedPaths = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
assert(importedPaths.size() <= 1);
|
assert(importedPaths.size() <= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,7 +537,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
<< printStorePath(info.path)
|
<< printStorePath(info.path)
|
||||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||||
<< info.narHash.to_string(Base16, false);
|
<< info.narHash.to_string(Base16, false);
|
||||||
worker_proto::write(*this, conn->to, info.references);
|
workerProtoWrite(*this, conn->to, info.references);
|
||||||
conn->to << info.registrationTime << info.narSize
|
conn->to << info.registrationTime << info.narSize
|
||||||
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
|
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
|
||||||
<< repair << !checkSigs;
|
<< repair << !checkSigs;
|
||||||
|
@ -793,7 +610,7 @@ void RemoteStore::registerDrvOutput(const Realisation & info)
|
||||||
conn->to << info.id.to_string();
|
conn->to << info.id.to_string();
|
||||||
conn->to << std::string(info.outPath.to_string());
|
conn->to << std::string(info.outPath.to_string());
|
||||||
} else {
|
} else {
|
||||||
worker_proto::write(*this, conn->to, info);
|
workerProtoWrite(*this, conn->to, info);
|
||||||
}
|
}
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
}
|
}
|
||||||
|
@ -815,14 +632,14 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
||||||
|
|
||||||
auto real = [&]() -> std::shared_ptr<const Realisation> {
|
auto real = [&]() -> std::shared_ptr<const Realisation> {
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) {
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) {
|
||||||
auto outPaths = worker_proto::read(
|
auto outPaths = WorkerProto<std::set<StorePath>>::read(
|
||||||
*this, conn->from, Phantom<std::set<StorePath>> {});
|
*this, conn->from);
|
||||||
if (outPaths.empty())
|
if (outPaths.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::make_shared<const Realisation>(Realisation { .id = id, .outPath = *outPaths.begin() });
|
return std::make_shared<const Realisation>(Realisation { .id = id, .outPath = *outPaths.begin() });
|
||||||
} else {
|
} else {
|
||||||
auto realisations = worker_proto::read(
|
auto realisations = WorkerProto<std::set<Realisation>>::read(
|
||||||
*this, conn->from, Phantom<std::set<Realisation>> {});
|
*this, conn->from);
|
||||||
if (realisations.empty())
|
if (realisations.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::make_shared<const Realisation>(*realisations.begin());
|
return std::make_shared<const Realisation>(*realisations.begin());
|
||||||
|
@ -836,7 +653,7 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id,
|
||||||
static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, const std::vector<DerivedPath> & reqs)
|
static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, const std::vector<DerivedPath> & reqs)
|
||||||
{
|
{
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 30) {
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 30) {
|
||||||
worker_proto::write(store, conn->to, reqs);
|
workerProtoWrite(store, conn->to, reqs);
|
||||||
} else {
|
} else {
|
||||||
Strings ss;
|
Strings ss;
|
||||||
for (auto & p : reqs) {
|
for (auto & p : reqs) {
|
||||||
|
@ -906,7 +723,7 @@ std::vector<KeyedBuildResult> RemoteStore::buildPathsWithResults(
|
||||||
writeDerivedPaths(*this, conn, paths);
|
writeDerivedPaths(*this, conn, paths);
|
||||||
conn->to << buildMode;
|
conn->to << buildMode;
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
return worker_proto::read(*this, conn->from, Phantom<std::vector<KeyedBuildResult>> {});
|
return WorkerProto<std::vector<KeyedBuildResult>>::read(*this, conn->from);
|
||||||
} else {
|
} else {
|
||||||
// Avoid deadlock.
|
// Avoid deadlock.
|
||||||
conn_.reset();
|
conn_.reset();
|
||||||
|
@ -989,7 +806,7 @@ BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicD
|
||||||
conn->from >> res.timesBuilt >> res.isNonDeterministic >> res.startTime >> res.stopTime;
|
conn->from >> res.timesBuilt >> res.isNonDeterministic >> res.startTime >> res.stopTime;
|
||||||
}
|
}
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 28) {
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 28) {
|
||||||
auto builtOutputs = worker_proto::read(*this, conn->from, Phantom<DrvOutputs> {});
|
auto builtOutputs = WorkerProto<DrvOutputs>::read(*this, conn->from);
|
||||||
for (auto && [output, realisation] : builtOutputs)
|
for (auto && [output, realisation] : builtOutputs)
|
||||||
res.builtOutputs.insert_or_assign(
|
res.builtOutputs.insert_or_assign(
|
||||||
std::move(output.outputName),
|
std::move(output.outputName),
|
||||||
|
@ -1048,7 +865,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||||
|
|
||||||
conn->to
|
conn->to
|
||||||
<< wopCollectGarbage << options.action;
|
<< wopCollectGarbage << options.action;
|
||||||
worker_proto::write(*this, conn->to, options.pathsToDelete);
|
workerProtoWrite(*this, conn->to, options.pathsToDelete);
|
||||||
conn->to << options.ignoreLiveness
|
conn->to << options.ignoreLiveness
|
||||||
<< options.maxFreed
|
<< options.maxFreed
|
||||||
/* removed options */
|
/* removed options */
|
||||||
|
@ -1107,9 +924,9 @@ void RemoteStore::queryMissing(const std::vector<DerivedPath> & targets,
|
||||||
conn->to << wopQueryMissing;
|
conn->to << wopQueryMissing;
|
||||||
writeDerivedPaths(*this, conn, targets);
|
writeDerivedPaths(*this, conn, targets);
|
||||||
conn.processStderr();
|
conn.processStderr();
|
||||||
willBuild = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
willBuild = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
willSubstitute = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
willSubstitute = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
unknown = worker_proto::read(*this, conn->from, Phantom<StorePathSet> {});
|
unknown = WorkerProto<StorePathSet>::read(*this, conn->from);
|
||||||
conn->from >> downloadSize >> narSize;
|
conn->from >> downloadSize >> narSize;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,17 @@ public:
|
||||||
|
|
||||||
bool verifyStore(bool checkContents, RepairFlag repair) override;
|
bool verifyStore(bool checkContents, RepairFlag repair) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default instance would schedule the work on the client side, but
|
||||||
|
* for consistency with `buildPaths` and `buildDerivation` it should happen
|
||||||
|
* on the remote side.
|
||||||
|
*
|
||||||
|
* We make this fail for now so we can add implement this properly later
|
||||||
|
* without it being a breaking change.
|
||||||
|
*/
|
||||||
|
void repairPath(const StorePath & path) override
|
||||||
|
{ unsupported("repairPath"); }
|
||||||
|
|
||||||
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
||||||
|
|
||||||
void queryMissing(const std::vector<DerivedPath> & targets,
|
void queryMissing(const std::vector<DerivedPath> & targets,
|
||||||
|
|
|
@ -41,6 +41,11 @@ void SSHMaster::addCommonSSHOpts(Strings & args)
|
||||||
args.push_back("-oLocalCommand=echo started");
|
args.push_back("-oLocalCommand=echo started");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SSHMaster::isMasterRunning() {
|
||||||
|
auto res = runProgram(RunOptions {.program = "ssh", .args = {"-O", "check", host}, .mergeStderrToStdout = true});
|
||||||
|
return res.first == 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
|
std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
|
||||||
{
|
{
|
||||||
Path socketPath = startMaster();
|
Path socketPath = startMaster();
|
||||||
|
@ -97,7 +102,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
|
||||||
|
|
||||||
// Wait for the SSH connection to be established,
|
// Wait for the SSH connection to be established,
|
||||||
// So that we don't overwrite the password prompt with our progress bar.
|
// So that we don't overwrite the password prompt with our progress bar.
|
||||||
if (!fakeSSH && !useMaster) {
|
if (!fakeSSH && !useMaster && !isMasterRunning()) {
|
||||||
std::string reply;
|
std::string reply;
|
||||||
try {
|
try {
|
||||||
reply = readLine(out.readSide.get());
|
reply = readLine(out.readSide.get());
|
||||||
|
@ -133,6 +138,8 @@ Path SSHMaster::startMaster()
|
||||||
logger->pause();
|
logger->pause();
|
||||||
Finally cleanup = [&]() { logger->resume(); };
|
Finally cleanup = [&]() { logger->resume(); };
|
||||||
|
|
||||||
|
bool wasMasterRunning = isMasterRunning();
|
||||||
|
|
||||||
state->sshMaster = startProcess([&]() {
|
state->sshMaster = startProcess([&]() {
|
||||||
restoreProcessContext();
|
restoreProcessContext();
|
||||||
|
|
||||||
|
@ -152,13 +159,15 @@ Path SSHMaster::startMaster()
|
||||||
|
|
||||||
out.writeSide = -1;
|
out.writeSide = -1;
|
||||||
|
|
||||||
std::string reply;
|
if (!wasMasterRunning) {
|
||||||
try {
|
std::string reply;
|
||||||
reply = readLine(out.readSide.get());
|
try {
|
||||||
} catch (EndOfFile & e) { }
|
reply = readLine(out.readSide.get());
|
||||||
|
} catch (EndOfFile & e) { }
|
||||||
|
|
||||||
if (reply != "started")
|
if (reply != "started")
|
||||||
throw Error("failed to start SSH master connection to '%s'", host);
|
throw Error("failed to start SSH master connection to '%s'", host);
|
||||||
|
}
|
||||||
|
|
||||||
return state->socketPath;
|
return state->socketPath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ private:
|
||||||
Sync<State> state_;
|
Sync<State> state_;
|
||||||
|
|
||||||
void addCommonSSHOpts(Strings & args);
|
void addCommonSSHOpts(Strings & args);
|
||||||
|
bool isMasterRunning();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -679,8 +679,7 @@ public:
|
||||||
* Repair the contents of the given path by redownloading it using
|
* Repair the contents of the given path by redownloading it using
|
||||||
* a substituter (if available).
|
* a substituter (if available).
|
||||||
*/
|
*/
|
||||||
virtual void repairPath(const StorePath & path)
|
virtual void repairPath(const StorePath & path);
|
||||||
{ unsupported("repairPath"); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add signatures to the specified store path. The signatures are
|
* Add signatures to the specified store path. The signatures are
|
||||||
|
|
33
src/libstore/tests/downstream-placeholder.cc
Normal file
33
src/libstore/tests/downstream-placeholder.cc
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
TEST(DownstreamPlaceholder, unknownCaOutput) {
|
||||||
|
ASSERT_EQ(
|
||||||
|
DownstreamPlaceholder::unknownCaOutput(
|
||||||
|
StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv" },
|
||||||
|
"out").render(),
|
||||||
|
"/0c6rn30q4frawknapgwq386zq358m8r6msvywcvc89n6m5p2dgbz");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DownstreamPlaceholder, unknownDerivation) {
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations");
|
||||||
|
|
||||||
|
ASSERT_EQ(
|
||||||
|
DownstreamPlaceholder::unknownDerivation(
|
||||||
|
DownstreamPlaceholder::unknownCaOutput(
|
||||||
|
StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv.drv" },
|
||||||
|
"out"),
|
||||||
|
"out",
|
||||||
|
mockXpSettings).render(),
|
||||||
|
"/0gn6agqxjyyalf0dpihgyf49xq5hqxgw100f0wydnj6yqrhqsb3w");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
192
src/libstore/worker-protocol.cc
Normal file
192
src/libstore/worker-protocol.cc
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#include "serialise.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "path-with-outputs.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
#include "build-result.hh"
|
||||||
|
#include "worker-protocol.hh"
|
||||||
|
#include "archive.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::string WorkerProto<std::string>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
return readString(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<std::string>::write(const Store & store, Sink & out, const std::string & str)
|
||||||
|
{
|
||||||
|
out << str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StorePath WorkerProto<StorePath>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
return store.parseStorePath(readString(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<StorePath>::write(const Store & store, Sink & out, const StorePath & storePath)
|
||||||
|
{
|
||||||
|
out << store.printStorePath(storePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<TrustedFlag> WorkerProto<std::optional<TrustedFlag>>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
auto temp = readNum<uint8_t>(from);
|
||||||
|
switch (temp) {
|
||||||
|
case 0:
|
||||||
|
return std::nullopt;
|
||||||
|
case 1:
|
||||||
|
return { Trusted };
|
||||||
|
case 2:
|
||||||
|
return { NotTrusted };
|
||||||
|
default:
|
||||||
|
throw Error("Invalid trusted status from remote");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<std::optional<TrustedFlag>>::write(const Store & store, Sink & out, const std::optional<TrustedFlag> & optTrusted)
|
||||||
|
{
|
||||||
|
if (!optTrusted)
|
||||||
|
out << (uint8_t)0;
|
||||||
|
else {
|
||||||
|
switch (*optTrusted) {
|
||||||
|
case Trusted:
|
||||||
|
out << (uint8_t)1;
|
||||||
|
break;
|
||||||
|
case NotTrusted:
|
||||||
|
out << (uint8_t)2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ContentAddress WorkerProto<ContentAddress>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
return ContentAddress::parse(readString(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<ContentAddress>::write(const Store & store, Sink & out, const ContentAddress & ca)
|
||||||
|
{
|
||||||
|
out << renderContentAddress(ca);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DerivedPath WorkerProto<DerivedPath>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
auto s = readString(from);
|
||||||
|
return DerivedPath::parseLegacy(store, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<DerivedPath>::write(const Store & store, Sink & out, const DerivedPath & req)
|
||||||
|
{
|
||||||
|
out << req.to_string_legacy(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Realisation WorkerProto<Realisation>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
std::string rawInput = readString(from);
|
||||||
|
return Realisation::fromJSON(
|
||||||
|
nlohmann::json::parse(rawInput),
|
||||||
|
"remote-protocol"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<Realisation>::write(const Store & store, Sink & out, const Realisation & realisation)
|
||||||
|
{
|
||||||
|
out << realisation.toJSON().dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DrvOutput WorkerProto<DrvOutput>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
return DrvOutput::parse(readString(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<DrvOutput>::write(const Store & store, Sink & out, const DrvOutput & drvOutput)
|
||||||
|
{
|
||||||
|
out << drvOutput.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeyedBuildResult WorkerProto<KeyedBuildResult>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
auto path = WorkerProto<DerivedPath>::read(store, from);
|
||||||
|
auto br = WorkerProto<BuildResult>::read(store, from);
|
||||||
|
return KeyedBuildResult {
|
||||||
|
std::move(br),
|
||||||
|
/* .path = */ std::move(path),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<KeyedBuildResult>::write(const Store & store, Sink & to, const KeyedBuildResult & res)
|
||||||
|
{
|
||||||
|
workerProtoWrite(store, to, res.path);
|
||||||
|
workerProtoWrite(store, to, static_cast<const BuildResult &>(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BuildResult WorkerProto<BuildResult>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
BuildResult res;
|
||||||
|
res.status = (BuildResult::Status) readInt(from);
|
||||||
|
from
|
||||||
|
>> res.errorMsg
|
||||||
|
>> res.timesBuilt
|
||||||
|
>> res.isNonDeterministic
|
||||||
|
>> res.startTime
|
||||||
|
>> res.stopTime;
|
||||||
|
auto builtOutputs = WorkerProto<DrvOutputs>::read(store, from);
|
||||||
|
for (auto && [output, realisation] : builtOutputs)
|
||||||
|
res.builtOutputs.insert_or_assign(
|
||||||
|
std::move(output.outputName),
|
||||||
|
std::move(realisation));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<BuildResult>::write(const Store & store, Sink & to, const BuildResult & res)
|
||||||
|
{
|
||||||
|
to
|
||||||
|
<< res.status
|
||||||
|
<< res.errorMsg
|
||||||
|
<< res.timesBuilt
|
||||||
|
<< res.isNonDeterministic
|
||||||
|
<< res.startTime
|
||||||
|
<< res.stopTime;
|
||||||
|
DrvOutputs builtOutputs;
|
||||||
|
for (auto & [output, realisation] : res.builtOutputs)
|
||||||
|
builtOutputs.insert_or_assign(realisation.id, realisation);
|
||||||
|
workerProtoWrite(store, to, builtOutputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<StorePath> WorkerProto<std::optional<StorePath>>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
auto s = readString(from);
|
||||||
|
return s == "" ? std::optional<StorePath> {} : store.parseStorePath(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<std::optional<StorePath>>::write(const Store & store, Sink & out, const std::optional<StorePath> & storePathOpt)
|
||||||
|
{
|
||||||
|
out << (storePathOpt ? store.printStorePath(*storePathOpt) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<ContentAddress> WorkerProto<std::optional<ContentAddress>>::read(const Store & store, Source & from)
|
||||||
|
{
|
||||||
|
return ContentAddress::parseOpt(readString(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorkerProto<std::optional<ContentAddress>>::write(const Store & store, Sink & out, const std::optional<ContentAddress> & caOpt)
|
||||||
|
{
|
||||||
|
out << (caOpt ? renderContentAddress(*caOpt) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "store-api.hh"
|
|
||||||
#include "serialise.hh"
|
#include "serialise.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -79,41 +78,81 @@ typedef enum {
|
||||||
class Store;
|
class Store;
|
||||||
struct Source;
|
struct Source;
|
||||||
|
|
||||||
|
// items being serialized
|
||||||
|
struct DerivedPath;
|
||||||
|
struct DrvOutput;
|
||||||
|
struct Realisation;
|
||||||
|
struct BuildResult;
|
||||||
|
struct KeyedBuildResult;
|
||||||
|
enum TrustedFlag : bool;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to guide overloading
|
* Data type for canonical pairs of serializers for the worker protocol.
|
||||||
*
|
*
|
||||||
* See https://en.cppreference.com/w/cpp/language/adl for the broader
|
* See https://en.cppreference.com/w/cpp/language/adl for the broader
|
||||||
* concept of what is going on here.
|
* concept of what is going on here.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Phantom {};
|
struct WorkerProto {
|
||||||
|
static T read(const Store & store, Source & from);
|
||||||
|
static void write(const Store & store, Sink & out, const T & t);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper function around `WorkerProto<T>::write` that allows us to
|
||||||
|
* infer the type instead of having to write it down explicitly.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
void workerProtoWrite(const Store & store, Sink & out, const T & t)
|
||||||
|
{
|
||||||
|
WorkerProto<T>::write(store, out, t);
|
||||||
|
}
|
||||||
|
|
||||||
namespace worker_proto {
|
/**
|
||||||
/* FIXME maybe move more stuff inside here */
|
* Declare a canonical serializer pair for the worker protocol.
|
||||||
|
*
|
||||||
|
* We specialize the struct merely to indicate that we are implementing
|
||||||
|
* the function for the given type.
|
||||||
|
*
|
||||||
|
* Some sort of `template<...>` must be used with the caller for this to
|
||||||
|
* be legal specialization syntax. See below for what that looks like in
|
||||||
|
* practice.
|
||||||
|
*/
|
||||||
|
#define MAKE_WORKER_PROTO(T) \
|
||||||
|
struct WorkerProto< T > { \
|
||||||
|
static T read(const Store & store, Source & from); \
|
||||||
|
static void write(const Store & store, Sink & out, const T & t); \
|
||||||
|
};
|
||||||
|
|
||||||
#define MAKE_WORKER_PROTO(TEMPLATE, T) \
|
template<>
|
||||||
TEMPLATE T read(const Store & store, Source & from, Phantom< T > _); \
|
MAKE_WORKER_PROTO(std::string);
|
||||||
TEMPLATE void write(const Store & store, Sink & out, const T & str)
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(StorePath);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(ContentAddress);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(DerivedPath);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(Realisation);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(DrvOutput);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(BuildResult);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(KeyedBuildResult);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(std::optional<TrustedFlag>);
|
||||||
|
|
||||||
MAKE_WORKER_PROTO(, std::string);
|
template<typename T>
|
||||||
MAKE_WORKER_PROTO(, StorePath);
|
MAKE_WORKER_PROTO(std::vector<T>);
|
||||||
MAKE_WORKER_PROTO(, ContentAddress);
|
template<typename T>
|
||||||
MAKE_WORKER_PROTO(, DerivedPath);
|
MAKE_WORKER_PROTO(std::set<T>);
|
||||||
MAKE_WORKER_PROTO(, Realisation);
|
|
||||||
MAKE_WORKER_PROTO(, DrvOutput);
|
|
||||||
MAKE_WORKER_PROTO(, BuildResult);
|
|
||||||
MAKE_WORKER_PROTO(, KeyedBuildResult);
|
|
||||||
MAKE_WORKER_PROTO(, std::optional<TrustedFlag>);
|
|
||||||
|
|
||||||
MAKE_WORKER_PROTO(template<typename T>, std::vector<T>);
|
template<typename K, typename V>
|
||||||
MAKE_WORKER_PROTO(template<typename T>, std::set<T>);
|
#define X_ std::map<K, V>
|
||||||
|
MAKE_WORKER_PROTO(X_);
|
||||||
#define X_ template<typename K, typename V>
|
|
||||||
#define Y_ std::map<K, V>
|
|
||||||
MAKE_WORKER_PROTO(X_, Y_);
|
|
||||||
#undef X_
|
#undef X_
|
||||||
#undef Y_
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These use the empty string for the null case, relying on the fact
|
* These use the empty string for the null case, relying on the fact
|
||||||
|
@ -129,72 +168,72 @@ MAKE_WORKER_PROTO(X_, Y_);
|
||||||
* worker protocol harder to implement in other languages where such
|
* worker protocol harder to implement in other languages where such
|
||||||
* specializations may not be allowed.
|
* specializations may not be allowed.
|
||||||
*/
|
*/
|
||||||
MAKE_WORKER_PROTO(, std::optional<StorePath>);
|
template<>
|
||||||
MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
|
MAKE_WORKER_PROTO(std::optional<StorePath>);
|
||||||
|
template<>
|
||||||
|
MAKE_WORKER_PROTO(std::optional<ContentAddress>);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::vector<T> read(const Store & store, Source & from, Phantom<std::vector<T>> _)
|
std::vector<T> WorkerProto<std::vector<T>>::read(const Store & store, Source & from)
|
||||||
{
|
{
|
||||||
std::vector<T> resSet;
|
std::vector<T> resSet;
|
||||||
auto size = readNum<size_t>(from);
|
auto size = readNum<size_t>(from);
|
||||||
while (size--) {
|
while (size--) {
|
||||||
resSet.push_back(read(store, from, Phantom<T> {}));
|
resSet.push_back(WorkerProto<T>::read(store, from));
|
||||||
}
|
}
|
||||||
return resSet;
|
return resSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void write(const Store & store, Sink & out, const std::vector<T> & resSet)
|
void WorkerProto<std::vector<T>>::write(const Store & store, Sink & out, const std::vector<T> & resSet)
|
||||||
{
|
{
|
||||||
out << resSet.size();
|
out << resSet.size();
|
||||||
for (auto & key : resSet) {
|
for (auto & key : resSet) {
|
||||||
write(store, out, key);
|
WorkerProto<T>::write(store, out, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::set<T> read(const Store & store, Source & from, Phantom<std::set<T>> _)
|
std::set<T> WorkerProto<std::set<T>>::read(const Store & store, Source & from)
|
||||||
{
|
{
|
||||||
std::set<T> resSet;
|
std::set<T> resSet;
|
||||||
auto size = readNum<size_t>(from);
|
auto size = readNum<size_t>(from);
|
||||||
while (size--) {
|
while (size--) {
|
||||||
resSet.insert(read(store, from, Phantom<T> {}));
|
resSet.insert(WorkerProto<T>::read(store, from));
|
||||||
}
|
}
|
||||||
return resSet;
|
return resSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void write(const Store & store, Sink & out, const std::set<T> & resSet)
|
void WorkerProto<std::set<T>>::write(const Store & store, Sink & out, const std::set<T> & resSet)
|
||||||
{
|
{
|
||||||
out << resSet.size();
|
out << resSet.size();
|
||||||
for (auto & key : resSet) {
|
for (auto & key : resSet) {
|
||||||
write(store, out, key);
|
WorkerProto<T>::write(store, out, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename V>
|
template<typename K, typename V>
|
||||||
std::map<K, V> read(const Store & store, Source & from, Phantom<std::map<K, V>> _)
|
std::map<K, V> WorkerProto<std::map<K, V>>::read(const Store & store, Source & from)
|
||||||
{
|
{
|
||||||
std::map<K, V> resMap;
|
std::map<K, V> resMap;
|
||||||
auto size = readNum<size_t>(from);
|
auto size = readNum<size_t>(from);
|
||||||
while (size--) {
|
while (size--) {
|
||||||
auto k = read(store, from, Phantom<K> {});
|
auto k = WorkerProto<K>::read(store, from);
|
||||||
auto v = read(store, from, Phantom<V> {});
|
auto v = WorkerProto<V>::read(store, from);
|
||||||
resMap.insert_or_assign(std::move(k), std::move(v));
|
resMap.insert_or_assign(std::move(k), std::move(v));
|
||||||
}
|
}
|
||||||
return resMap;
|
return resMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename V>
|
template<typename K, typename V>
|
||||||
void write(const Store & store, Sink & out, const std::map<K, V> & resMap)
|
void WorkerProto<std::map<K, V>>::write(const Store & store, Sink & out, const std::map<K, V> & resMap)
|
||||||
{
|
{
|
||||||
out << resMap.size();
|
out << resMap.size();
|
||||||
for (auto & i : resMap) {
|
for (auto & i : resMap) {
|
||||||
write(store, out, i.first);
|
WorkerProto<K>::write(store, out, i.first);
|
||||||
write(store, out, i.second);
|
WorkerProto<V>::write(store, out, i.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -207,6 +207,9 @@ constexpr std::array<ExperimentalFeatureDetails, 14> xpFeatureDetails = {{
|
||||||
|
|
||||||
- "text hashing" derivation outputs, so we can build .drv
|
- "text hashing" derivation outputs, so we can build .drv
|
||||||
files.
|
files.
|
||||||
|
|
||||||
|
- dependencies in derivations on the outputs of
|
||||||
|
derivations that are themselves derivations outputs.
|
||||||
)",
|
)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1141,9 +1141,9 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string runProgram(Path program, bool searchPath, const Strings & args,
|
std::string runProgram(Path program, bool searchPath, const Strings & args,
|
||||||
const std::optional<std::string> & input)
|
const std::optional<std::string> & input, bool isInteractive)
|
||||||
{
|
{
|
||||||
auto res = runProgram(RunOptions {.program = program, .searchPath = searchPath, .args = args, .input = input});
|
auto res = runProgram(RunOptions {.program = program, .searchPath = searchPath, .args = args, .input = input, .isInteractive = isInteractive});
|
||||||
|
|
||||||
if (!statusOk(res.first))
|
if (!statusOk(res.first))
|
||||||
throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
|
throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
|
||||||
|
@ -1193,6 +1193,16 @@ void runProgram2(const RunOptions & options)
|
||||||
// case), so we can't use it if we alter the environment
|
// case), so we can't use it if we alter the environment
|
||||||
processOptions.allowVfork = !options.environment;
|
processOptions.allowVfork = !options.environment;
|
||||||
|
|
||||||
|
std::optional<Finally<std::function<void()>>> resumeLoggerDefer;
|
||||||
|
if (options.isInteractive) {
|
||||||
|
logger->pause();
|
||||||
|
resumeLoggerDefer.emplace(
|
||||||
|
[]() {
|
||||||
|
logger->resume();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* Fork. */
|
/* Fork. */
|
||||||
Pid pid = startProcess([&]() {
|
Pid pid = startProcess([&]() {
|
||||||
if (options.environment)
|
if (options.environment)
|
||||||
|
|
|
@ -415,7 +415,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
|
||||||
*/
|
*/
|
||||||
std::string runProgram(Path program, bool searchPath = false,
|
std::string runProgram(Path program, bool searchPath = false,
|
||||||
const Strings & args = Strings(),
|
const Strings & args = Strings(),
|
||||||
const std::optional<std::string> & input = {});
|
const std::optional<std::string> & input = {}, bool isInteractive = false);
|
||||||
|
|
||||||
struct RunOptions
|
struct RunOptions
|
||||||
{
|
{
|
||||||
|
@ -430,6 +430,7 @@ struct RunOptions
|
||||||
Source * standardIn = nullptr;
|
Source * standardIn = nullptr;
|
||||||
Sink * standardOut = nullptr;
|
Sink * standardOut = nullptr;
|
||||||
bool mergeStderrToStdout = false;
|
bool mergeStderrToStdout = false;
|
||||||
|
bool isInteractive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::pair<int, std::string> runProgram(RunOptions && options);
|
std::pair<int, std::string> runProgram(RunOptions && options);
|
||||||
|
|
|
@ -849,7 +849,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
case cmdQueryValidPaths: {
|
case cmdQueryValidPaths: {
|
||||||
bool lock = readInt(in);
|
bool lock = readInt(in);
|
||||||
bool substitute = readInt(in);
|
bool substitute = readInt(in);
|
||||||
auto paths = worker_proto::read(*store, in, Phantom<StorePathSet> {});
|
auto paths = WorkerProto<StorePathSet>::read(*store, in);
|
||||||
if (lock && writeAllowed)
|
if (lock && writeAllowed)
|
||||||
for (auto & path : paths)
|
for (auto & path : paths)
|
||||||
store->addTempRoot(path);
|
store->addTempRoot(path);
|
||||||
|
@ -858,19 +858,19 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
store->substitutePaths(paths);
|
store->substitutePaths(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
worker_proto::write(*store, out, store->queryValidPaths(paths));
|
workerProtoWrite(*store, out, store->queryValidPaths(paths));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case cmdQueryPathInfos: {
|
case cmdQueryPathInfos: {
|
||||||
auto paths = worker_proto::read(*store, in, Phantom<StorePathSet> {});
|
auto paths = WorkerProto<StorePathSet>::read(*store, in);
|
||||||
// !!! Maybe we want a queryPathInfos?
|
// !!! Maybe we want a queryPathInfos?
|
||||||
for (auto & i : paths) {
|
for (auto & i : paths) {
|
||||||
try {
|
try {
|
||||||
auto info = store->queryPathInfo(i);
|
auto info = store->queryPathInfo(i);
|
||||||
out << store->printStorePath(info->path)
|
out << store->printStorePath(info->path)
|
||||||
<< (info->deriver ? store->printStorePath(*info->deriver) : "");
|
<< (info->deriver ? store->printStorePath(*info->deriver) : "");
|
||||||
worker_proto::write(*store, out, info->references);
|
workerProtoWrite(*store, out, info->references);
|
||||||
// !!! Maybe we want compression?
|
// !!! Maybe we want compression?
|
||||||
out << info->narSize // downloadSize
|
out << info->narSize // downloadSize
|
||||||
<< info->narSize;
|
<< info->narSize;
|
||||||
|
@ -898,7 +898,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
|
|
||||||
case cmdExportPaths: {
|
case cmdExportPaths: {
|
||||||
readInt(in); // obsolete
|
readInt(in); // obsolete
|
||||||
store->exportPaths(worker_proto::read(*store, in, Phantom<StorePathSet> {}), out);
|
store->exportPaths(WorkerProto<StorePathSet>::read(*store, in), out);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,7 +944,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
DrvOutputs builtOutputs;
|
DrvOutputs builtOutputs;
|
||||||
for (auto & [output, realisation] : status.builtOutputs)
|
for (auto & [output, realisation] : status.builtOutputs)
|
||||||
builtOutputs.insert_or_assign(realisation.id, realisation);
|
builtOutputs.insert_or_assign(realisation.id, realisation);
|
||||||
worker_proto::write(*store, out, builtOutputs);
|
workerProtoWrite(*store, out, builtOutputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -953,9 +953,9 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
case cmdQueryClosure: {
|
case cmdQueryClosure: {
|
||||||
bool includeOutputs = readInt(in);
|
bool includeOutputs = readInt(in);
|
||||||
StorePathSet closure;
|
StorePathSet closure;
|
||||||
store->computeFSClosure(worker_proto::read(*store, in, Phantom<StorePathSet> {}),
|
store->computeFSClosure(WorkerProto<StorePathSet>::read(*store, in),
|
||||||
closure, false, includeOutputs);
|
closure, false, includeOutputs);
|
||||||
worker_proto::write(*store, out, closure);
|
workerProtoWrite(*store, out, closure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,7 +970,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
};
|
};
|
||||||
if (deriver != "")
|
if (deriver != "")
|
||||||
info.deriver = store->parseStorePath(deriver);
|
info.deriver = store->parseStorePath(deriver);
|
||||||
info.references = worker_proto::read(*store, in, Phantom<StorePathSet> {});
|
info.references = WorkerProto<StorePathSet>::read(*store, in);
|
||||||
in >> info.registrationTime >> info.narSize >> info.ultimate;
|
in >> info.registrationTime >> info.narSize >> info.ultimate;
|
||||||
info.sigs = readStrings<StringSet>(in);
|
info.sigs = readStrings<StringSet>(in);
|
||||||
info.ca = ContentAddress::parseOpt(readString(in));
|
info.ca = ContentAddress::parseOpt(readString(in));
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
|
#include "downstream-placeholder.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ StringPairs resolveRewrites(
|
||||||
if (auto drvDep = std::get_if<BuiltPathBuilt>(&dep.path))
|
if (auto drvDep = std::get_if<BuiltPathBuilt>(&dep.path))
|
||||||
for (auto & [ outputName, outputPath ] : drvDep->outputs)
|
for (auto & [ outputName, outputPath ] : drvDep->outputs)
|
||||||
res.emplace(
|
res.emplace(
|
||||||
downstreamPlaceholder(store, drvDep->drvPath, outputName),
|
DownstreamPlaceholder::unknownCaOutput(drvDep->drvPath, outputName).render(),
|
||||||
store.printStorePath(outputPath)
|
store.printStorePath(outputPath)
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -44,7 +44,7 @@ R""(
|
||||||
`release.nix`:
|
`release.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix build -f release.nix build.x86_64-linux
|
# nix build --file release.nix build.x86_64-linux
|
||||||
```
|
```
|
||||||
|
|
||||||
* Build a NixOS system configuration from a flake, and make a profile
|
* Build a NixOS system configuration from a flake, and make a profile
|
||||||
|
|
|
@ -15,7 +15,7 @@ R""(
|
||||||
SSH:
|
SSH:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix copy -s --to ssh://server /run/current-system
|
# nix copy --substitute-on-destination --to ssh://server /run/current-system
|
||||||
```
|
```
|
||||||
|
|
||||||
The `-s` flag causes the remote machine to try to substitute missing
|
The `-s` flag causes the remote machine to try to substitute missing
|
||||||
|
|
|
@ -69,7 +69,7 @@ R""(
|
||||||
* Run a series of script commands:
|
* Run a series of script commands:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix develop --command bash -c "mkdir build && cmake .. && make"
|
# nix develop --command bash --command "mkdir build && cmake .. && make"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
|
@ -18,7 +18,7 @@ R""(
|
||||||
* Evaluate a Nix expression from a file:
|
* Evaluate a Nix expression from a file:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix eval -f ./my-nixpkgs hello.name
|
# nix eval --file ./my-nixpkgs hello.name
|
||||||
```
|
```
|
||||||
|
|
||||||
* Get the current version of the `nixpkgs` flake:
|
* Get the current version of the `nixpkgs` flake:
|
||||||
|
|
|
@ -68,6 +68,6 @@ The following flake output attributes must be
|
||||||
In addition, the `hydraJobs` output is evaluated in the same way as
|
In addition, the `hydraJobs` output is evaluated in the same way as
|
||||||
Hydra's `hydra-eval-jobs` (i.e. as a arbitrarily deeply nested
|
Hydra's `hydra-eval-jobs` (i.e. as a arbitrarily deeply nested
|
||||||
attribute set of derivations). Similarly, the
|
attribute set of derivations). Similarly, the
|
||||||
`legacyPackages`.*system* output is evaluated like `nix-env -qa`.
|
`legacyPackages`.*system* output is evaluated like `nix-env --query --available `.
|
||||||
|
|
||||||
)""
|
)""
|
||||||
|
|
|
@ -5,7 +5,7 @@ R""(
|
||||||
* To list a specific file in a NAR:
|
* To list a specific file in a NAR:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix nar ls -l ./hello.nar /bin/hello
|
# nix nar ls --long ./hello.nar /bin/hello
|
||||||
-r-xr-xr-x 38184 hello
|
-r-xr-xr-x 38184 hello
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ R""(
|
||||||
format:
|
format:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix nar ls --json -R ./hello.nar /bin
|
# nix nar ls --json --recursive ./hello.nar /bin
|
||||||
{"type":"directory","entries":{"hello":{"type":"regular","size":38184,"executable":true,"narOffset":400}}}
|
{"type":"directory","entries":{"hello":{"type":"regular","size":38184,"executable":true,"narOffset":400}}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,7 @@ operate are determined as follows:
|
||||||
of all outputs of the `glibc` package in the binary cache:
|
of all outputs of the `glibc` package in the binary cache:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info -S --eval-store auto --store https://cache.nixos.org 'nixpkgs#glibc^*'
|
# nix path-info --closure-size --eval-store auto --store https://cache.nixos.org 'nixpkgs#glibc^*'
|
||||||
/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123 33208200
|
/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123 33208200
|
||||||
/nix/store/851dp95qqiisjifi639r0zzg5l465ny4-glibc-2.33-123-bin 36142896
|
/nix/store/851dp95qqiisjifi639r0zzg5l465ny4-glibc-2.33-123-bin 36142896
|
||||||
/nix/store/kdgs3q6r7xdff1p7a9hnjr43xw2404z7-glibc-2.33-123-debug 155787312
|
/nix/store/kdgs3q6r7xdff1p7a9hnjr43xw2404z7-glibc-2.33-123-debug 155787312
|
||||||
|
@ -208,7 +208,7 @@ operate are determined as follows:
|
||||||
and likewise, using a store path to a "drv" file to specify the derivation:
|
and likewise, using a store path to a "drv" file to specify the derivation:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info -S '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*'
|
# nix path-info --closure-size '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*'
|
||||||
…
|
…
|
||||||
```
|
```
|
||||||
* If you didn't specify the desired outputs, but the derivation has an
|
* If you didn't specify the desired outputs, but the derivation has an
|
||||||
|
|
|
@ -13,7 +13,7 @@ R""(
|
||||||
closure, sorted by size:
|
closure, sorted by size:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info -rS /run/current-system | sort -nk2
|
# nix path-info --recursive --closure-size /run/current-system | sort -nk2
|
||||||
/nix/store/hl5xwp9kdrd1zkm0idm3kkby9q66z404-empty 96
|
/nix/store/hl5xwp9kdrd1zkm0idm3kkby9q66z404-empty 96
|
||||||
/nix/store/27324qvqhnxj3rncazmxc4mwy79kz8ha-nameservers 112
|
/nix/store/27324qvqhnxj3rncazmxc4mwy79kz8ha-nameservers 112
|
||||||
…
|
…
|
||||||
|
@ -25,7 +25,7 @@ R""(
|
||||||
readable sizes:
|
readable sizes:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info -rsSh nixpkgs#rustc
|
# nix path-info --recursive --size --closure-size --human-readable nixpkgs#rustc
|
||||||
/nix/store/01rrgsg5zk3cds0xgdsq40zpk6g51dz9-ncurses-6.2-dev 386.7K 69.1M
|
/nix/store/01rrgsg5zk3cds0xgdsq40zpk6g51dz9-ncurses-6.2-dev 386.7K 69.1M
|
||||||
/nix/store/0q783wnvixpqz6dxjp16nw296avgczam-libpfm-4.11.0 5.9M 37.4M
|
/nix/store/0q783wnvixpqz6dxjp16nw296avgczam-libpfm-4.11.0 5.9M 37.4M
|
||||||
…
|
…
|
||||||
|
@ -34,7 +34,7 @@ R""(
|
||||||
* Check the existence of a path in a binary cache:
|
* Check the existence of a path in a binary cache:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info -r /nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1 --store https://cache.nixos.org/
|
# nix path-info --recursive /nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1 --store https://cache.nixos.org/
|
||||||
path '/nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1' is not valid
|
path '/nix/store/blzxgyvrk32ki6xga10phr4sby2xf25q-geeqie-1.5.1' is not valid
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -57,7 +57,7 @@ R""(
|
||||||
size:
|
size:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix path-info --json --all -S \
|
# nix path-info --json --all --closure-size \
|
||||||
| jq 'map(select(.closureSize > 1e9)) | sort_by(.closureSize) | map([.path, .closureSize])'
|
| jq 'map(select(.closureSize > 1e9)) | sort_by(.closureSize) | map([.path, .closureSize])'
|
||||||
[
|
[
|
||||||
…,
|
…,
|
||||||
|
|
|
@ -52,12 +52,12 @@ R""(
|
||||||
* Search for packages containing `neovim` but hide ones containing either `gui` or `python`:
|
* Search for packages containing `neovim` but hide ones containing either `gui` or `python`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix search nixpkgs neovim -e 'python|gui'
|
# nix search nixpkgs neovim --exclude 'python|gui'
|
||||||
```
|
```
|
||||||
or
|
or
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix search nixpkgs neovim -e 'python' -e 'gui'
|
# nix search nixpkgs neovim --exclude 'python' --exclude 'gui'
|
||||||
```
|
```
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
|
@ -19,26 +19,26 @@ R""(
|
||||||
* Run GNU Hello:
|
* Run GNU Hello:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix shell nixpkgs#hello -c hello --greeting 'Hi everybody!'
|
# nix shell nixpkgs#hello --command hello --greeting 'Hi everybody!'
|
||||||
Hi everybody!
|
Hi everybody!
|
||||||
```
|
```
|
||||||
|
|
||||||
* Run multiple commands in a shell environment:
|
* Run multiple commands in a shell environment:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix shell nixpkgs#gnumake -c sh -c "cd src && make"
|
# nix shell nixpkgs#gnumake --command sh --command "cd src && make"
|
||||||
```
|
```
|
||||||
|
|
||||||
* Run GNU Hello in a chroot store:
|
* Run GNU Hello in a chroot store:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix shell --store ~/my-nix nixpkgs#hello -c hello
|
# nix shell --store ~/my-nix nixpkgs#hello --command hello
|
||||||
```
|
```
|
||||||
|
|
||||||
* Start a shell providing GNU Hello in a chroot store:
|
* Start a shell providing GNU Hello in a chroot store:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix shell --store ~/my-nix nixpkgs#hello nixpkgs#bashInteractive -c bash
|
# nix shell --store ~/my-nix nixpkgs#hello nixpkgs#bashInteractive --command bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that it's necessary to specify `bash` explicitly because your
|
Note that it's necessary to specify `bash` explicitly because your
|
||||||
|
|
|
@ -5,7 +5,7 @@ R""(
|
||||||
* To list the contents of a store path in a binary cache:
|
* To list the contents of a store path in a binary cache:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix store ls --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
|
# nix store ls --store https://cache.nixos.org/ --long --recursive /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
|
||||||
dr-xr-xr-x 0 ./bin
|
dr-xr-xr-x 0 ./bin
|
||||||
-r-xr-xr-x 38184 ./bin/hello
|
-r-xr-xr-x 38184 ./bin/hello
|
||||||
dr-xr-xr-x 0 ./share
|
dr-xr-xr-x 0 ./share
|
||||||
|
@ -15,7 +15,7 @@ R""(
|
||||||
* To show information about a specific file in a binary cache:
|
* To show information about a specific file in a binary cache:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix store ls --store https://cache.nixos.org/ -l /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10/bin/hello
|
# nix store ls --store https://cache.nixos.org/ --long /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10/bin/hello
|
||||||
-r-xr-xr-x 38184 hello
|
-r-xr-xr-x 38184 hello
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ R""(
|
||||||
* Upgrade Nix in a specific profile:
|
* Upgrade Nix in a specific profile:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix upgrade-nix -p ~alice/.local/state/nix/profiles/profile
|
# nix upgrade-nix --profile ~alice/.local/state/nix/profiles/profile
|
||||||
```
|
```
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
|
@ -12,7 +12,7 @@ R""(
|
||||||
signatures:
|
signatures:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix store verify -r -n2 --no-contents $(type -p firefox)
|
# nix store verify --recursive --sigs-needed 2 --no-contents $(type -p firefox)
|
||||||
```
|
```
|
||||||
|
|
||||||
* Verify a store path in the binary cache `https://cache.nixos.org/`:
|
* Verify a store path in the binary cache `https://cache.nixos.org/`:
|
||||||
|
|
|
@ -23,6 +23,12 @@ in {
|
||||||
nix.settings.substituters = lib.mkForce [ ];
|
nix.settings.substituters = lib.mkForce [ ];
|
||||||
nix.settings.experimental-features = [ "nix-command" ];
|
nix.settings.experimental-features = [ "nix-command" ];
|
||||||
services.getty.autologinUser = "root";
|
services.getty.autologinUser = "root";
|
||||||
|
programs.ssh.extraConfig = ''
|
||||||
|
Host *
|
||||||
|
ControlMaster auto
|
||||||
|
ControlPath ~/.ssh/master-%h:%r@%n:%p
|
||||||
|
ControlPersist 15m
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
server =
|
server =
|
||||||
|
@ -62,6 +68,10 @@ in {
|
||||||
client.wait_for_text("done")
|
client.wait_for_text("done")
|
||||||
server.succeed("nix-store --check-validity ${pkgA}")
|
server.succeed("nix-store --check-validity ${pkgA}")
|
||||||
|
|
||||||
|
# Check that ControlMaster is working
|
||||||
|
client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo done\n")
|
||||||
|
client.wait_for_text("done")
|
||||||
|
|
||||||
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
client.copy_from_host("key", "/root/.ssh/id_ed25519")
|
||||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue