mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-10 08:16:15 +02:00
Merge branch 'read-only-local-store' into overlayfs-store
This commit is contained in:
commit
b852bdb3f8
37 changed files with 360 additions and 154 deletions
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
# should be kept in sync with `version`
|
# should be kept in sync with `version`
|
||||||
uses: zeebe-io/backport-action@v1.2.0
|
uses: zeebe-io/backport-action@v1.3.0
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -19,7 +19,10 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v21
|
||||||
|
with:
|
||||||
|
# The sandbox would otherwise be disabled by default on Darwin
|
||||||
|
extra_nix_config: "sandbox = true"
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/cachix-action@v12
|
- uses: cachix/cachix-action@v12
|
||||||
if: needs.check_secrets.outputs.cachix == 'true'
|
if: needs.check_secrets.outputs.cachix == 'true'
|
||||||
|
@ -58,7 +61,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v21
|
||||||
with:
|
with:
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||||
- uses: cachix/cachix-action@v12
|
- uses: cachix/cachix-action@v12
|
||||||
|
@ -79,7 +82,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v21
|
||||||
with:
|
with:
|
||||||
install_url: '${{needs.installer.outputs.installerURL}}'
|
install_url: '${{needs.installer.outputs.installerURL}}'
|
||||||
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
||||||
|
@ -106,7 +109,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v20
|
- uses: cachix/install-nix-action@v21
|
||||||
with:
|
with:
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||||
|
|
2
.version
2
.version
|
@ -1 +1 @@
|
||||||
2.16.0
|
2.17.0
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
- [CLI guideline](contributing/cli-guideline.md)
|
- [CLI guideline](contributing/cli-guideline.md)
|
||||||
- [Release Notes](release-notes/release-notes.md)
|
- [Release Notes](release-notes/release-notes.md)
|
||||||
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
||||||
|
- [Release 2.16 (2023-05-31)](release-notes/rl-2.16.md)
|
||||||
- [Release 2.15 (2023-04-11)](release-notes/rl-2.15.md)
|
- [Release 2.15 (2023-04-11)](release-notes/rl-2.15.md)
|
||||||
- [Release 2.14 (2023-02-28)](release-notes/rl-2.14.md)
|
- [Release 2.14 (2023-02-28)](release-notes/rl-2.14.md)
|
||||||
- [Release 2.13 (2023-01-17)](release-notes/rl-2.13.md)
|
- [Release 2.13 (2023-01-17)](release-notes/rl-2.13.md)
|
||||||
|
|
|
@ -38,11 +38,9 @@ contains Nix.
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
> If you are building via the Nix daemon, it is the Nix daemon user
|
> If you are building via the Nix daemon, it is the Nix daemon user account (that is, `root`) that should have SSH access to a user (not necessarily `root`) on the remote machine.
|
||||||
> account (that is, `root`) that should have SSH access to the remote
|
>
|
||||||
> machine. If you can’t or don’t want to configure `root` to be able to
|
> If you can’t or don’t want to configure `root` to be able to access the remote machine, you can use a private Nix store instead by passing e.g. `--store ~/my-nix` when running a Nix command from the local machine.
|
||||||
> access to remote machine, you can use a private Nix store instead by
|
|
||||||
> passing e.g. `--store ~/my-nix`.
|
|
||||||
|
|
||||||
The list of remote machines can be specified on the command line or in
|
The list of remote machines can be specified on the command line or in
|
||||||
the Nix configuration file. The former is convenient for testing. For
|
the Nix configuration file. The former is convenient for testing. For
|
||||||
|
|
|
@ -17,3 +17,27 @@ These constants are built into the Nix language evaluator:
|
||||||
The built-in value `currentSystem` evaluates to the Nix platform
|
The built-in value `currentSystem` evaluates to the Nix platform
|
||||||
identifier for the Nix installation on which the expression is being
|
identifier for the Nix installation on which the expression is being
|
||||||
evaluated, such as `"i686-linux"` or `"x86_64-darwin"`.
|
evaluated, such as `"i686-linux"` or `"x86_64-darwin"`.
|
||||||
|
|
||||||
|
Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
|
||||||
|
- [`builtins.currentTime`]{#builtins-currentTime} (integer)
|
||||||
|
|
||||||
|
Return the [Unix time](https://en.wikipedia.org/wiki/Unix_time) at first evaluation.
|
||||||
|
Repeated references to that name will re-use the initially obtained value.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix repl
|
||||||
|
Welcome to Nix 2.15.1 Type :? for help.
|
||||||
|
|
||||||
|
nix-repl> builtins.currentTime
|
||||||
|
1683705525
|
||||||
|
|
||||||
|
nix-repl> builtins.currentTime
|
||||||
|
1683705525
|
||||||
|
```
|
||||||
|
|
||||||
|
The [store path](@docroot@/glossary.md#gloss-store-path) of a derivation depending on `currentTime` will differ for each evaluation.
|
||||||
|
|
||||||
|
Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
## Recursive sets
|
## Recursive sets
|
||||||
|
|
||||||
Recursive sets are just normal sets, but the attributes can refer to
|
Recursive sets are like normal [attribute sets](./values.md#attribute-set), but the attributes can refer to each other.
|
||||||
each other. For example,
|
|
||||||
|
> *rec-attrset* = `rec {` [ *name* `=` *expr* `;` `]`... `}`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
rec {
|
rec {
|
||||||
|
@ -12,7 +15,9 @@ rec {
|
||||||
}.x
|
}.x
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `123`. Note that without `rec` the binding `x = y;` would
|
This evaluates to `123`.
|
||||||
|
|
||||||
|
Note that without `rec` the binding `x = y;` would
|
||||||
refer to the variable `y` in the surrounding scope, if one exists, and
|
refer to the variable `y` in the surrounding scope, if one exists, and
|
||||||
would be invalid if no such variable exists. That is, in a normal
|
would be invalid if no such variable exists. That is, in a normal
|
||||||
(non-recursive) set, attributes are not added to the lexical scope; in a
|
(non-recursive) set, attributes are not added to the lexical scope; in a
|
||||||
|
@ -33,7 +38,10 @@ will crash with an `infinite recursion encountered` error message.
|
||||||
## Let-expressions
|
## Let-expressions
|
||||||
|
|
||||||
A let-expression allows you to define local variables for an expression.
|
A let-expression allows you to define local variables for an expression.
|
||||||
For instance,
|
|
||||||
|
> *let-in* = `let` [ *identifier* = *expr* ]... `in` *expr*
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let
|
let
|
||||||
|
@ -42,18 +50,19 @@ let
|
||||||
in x + y
|
in x + y
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `"foobar"`.
|
This evaluates to `"foobar"`.
|
||||||
|
|
||||||
## Inheriting attributes
|
## Inheriting attributes
|
||||||
|
|
||||||
When defining a set or in a let-expression it is often convenient to
|
When defining an [attribute set](./values.md#attribute-set) or in a [let-expression](#let-expressions) it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes).
|
||||||
copy variables from the surrounding lexical scope (e.g., when you want
|
This can be shortened using the `inherit` keyword.
|
||||||
to propagate attributes). This can be shortened using the `inherit`
|
|
||||||
keyword. For instance,
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let x = 123; in
|
let x = 123; in
|
||||||
{ inherit x;
|
{
|
||||||
|
inherit x;
|
||||||
y = 456;
|
y = 456;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -62,15 +71,23 @@ is equivalent to
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let x = 123; in
|
let x = 123; in
|
||||||
{ x = x;
|
{
|
||||||
|
x = x;
|
||||||
y = 456;
|
y = 456;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
and both evaluate to `{ x = 123; y = 456; }`. (Note that this works
|
and both evaluate to `{ x = 123; y = 456; }`.
|
||||||
because `x` is added to the lexical scope by the `let` construct.) It is
|
|
||||||
also possible to inherit attributes from another set. For instance, in
|
> **Note**
|
||||||
this fragment from `all-packages.nix`,
|
>
|
||||||
|
> This works because `x` is added to the lexical scope by the `let` construct.
|
||||||
|
|
||||||
|
It is also possible to inherit attributes from another attribute set.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
In this fragment from `all-packages.nix`,
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
graphviz = (import ../tools/graphics/graphviz) {
|
graphviz = (import ../tools/graphics/graphviz) {
|
||||||
|
|
|
@ -35,17 +35,14 @@
|
||||||
|
|
||||||
## Attribute selection
|
## Attribute selection
|
||||||
|
|
||||||
|
> *attrset* `.` *attrpath* \[ `or` *expr* \]
|
||||||
|
|
||||||
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
|
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
|
||||||
If the attribute doesn’t exist, return the *expr* after `or` if provided, otherwise abort evaluation.
|
If the attribute doesn’t exist, return the *expr* after `or` if provided, otherwise abort evaluation.
|
||||||
|
|
||||||
<!-- FIXME: the following should to into its own language syntax section, but that needs more work to fit in well -->
|
An attribute path is a dot-separated list of [attribute names](./values.md#attribute-set).
|
||||||
|
|
||||||
An attribute path is a dot-separated list of attribute names.
|
> *attrpath* = *name* [ `.` *name* ]...
|
||||||
An attribute name can be an identifier or a string.
|
|
||||||
|
|
||||||
> *attrpath* = *name* [ `.` *name* ]... \
|
|
||||||
> *name* = *identifier* | *string* \
|
|
||||||
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
|
|
||||||
|
|
||||||
[Attribute selection]: #attribute-selection
|
[Attribute selection]: #attribute-selection
|
||||||
|
|
||||||
|
|
|
@ -164,9 +164,17 @@ Note that lists are only lazy in values, and they are strict in length.
|
||||||
|
|
||||||
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
|
||||||
|
|
||||||
|
An attribute name can be an identifier or a [string](#string).
|
||||||
|
An identifier must start with a letter (`a-z`, `A-Z`) or underscore (`_`), and can otherwise contain letters (`a-z`, `A-Z`), numbers (`0-9`), underscores (`_`), apostrophes (`'`), or dashes (`-`).
|
||||||
|
|
||||||
|
> *name* = *identifier* | *string* \
|
||||||
|
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
|
||||||
|
|
||||||
Names and values are separated by an equal sign (`=`).
|
Names and values are separated by an equal sign (`=`).
|
||||||
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
Each value is an arbitrary expression terminated by a semicolon (`;`).
|
||||||
|
|
||||||
|
> *attrset* = `{` [ *name* `=` *expr* `;` `]`... `}`
|
||||||
|
|
||||||
Attributes can appear in any order.
|
Attributes can appear in any order.
|
||||||
An attribute name may only occur once.
|
An attribute name may only occur once.
|
||||||
|
|
||||||
|
@ -182,15 +190,19 @@ Example:
|
||||||
|
|
||||||
This defines a set with attributes named `x`, `text`, `y`.
|
This defines a set with attributes named `x`, `text`, `y`.
|
||||||
|
|
||||||
Attributes can be selected from a set using the `.` operator. For
|
Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection).
|
||||||
instance,
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ a = "Foo"; b = "Bar"; }.a
|
{ a = "Foo"; b = "Bar"; }.a
|
||||||
```
|
```
|
||||||
|
|
||||||
evaluates to `"Foo"`. It is possible to provide a default value in an
|
This evaluates to `"Foo"`.
|
||||||
attribute selection using the `or` keyword:
|
|
||||||
|
It is possible to provide a default value in an attribute selection using the `or` keyword.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy"
|
||||||
|
|
8
doc/manual/src/release-notes/rl-2.16.md
Normal file
8
doc/manual/src/release-notes/rl-2.16.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Release 2.16 (2023-05-31)
|
||||||
|
|
||||||
|
* Speed-up of downloads from binary caches.
|
||||||
|
The number of parallel downloads (also known as substitutions) has been separated from the [`--max-jobs` setting](../command-ref/conf-file.md#conf-max-jobs).
|
||||||
|
The new setting is called [`max-substitution-jobs`](../command-ref/conf-file.md#conf-max-substitution-jobs).
|
||||||
|
The number of parallel downloads is now set to 16 by default (previously, the default was 1 due to the coupling to build jobs).
|
||||||
|
|
||||||
|
* The function [`builtins.replaceStrings`](@docroot@/language/builtins.md#builtins-replaceStrings) is now lazy in the value of its second argument `to`. That is, `to` is only evaluated when its corresponding pattern in `from` is matched in the string `s`.
|
|
@ -1,6 +1,2 @@
|
||||||
# Release X.Y (202?-??-??)
|
# Release X.Y (202?-??-??)
|
||||||
|
|
||||||
- Speed-up of downloads from binary caches.
|
|
||||||
The number of parallel downloads (also known as substitutions) has been separated from the [`--max-jobs` setting](../command-ref/conf-file.md#conf-max-jobs).
|
|
||||||
The new setting is called [`max-substitution-jobs`](../command-ref/conf-file.md#conf-max-substitution-jobs).
|
|
||||||
The number of parallel downloads is now set to 16 by default (previously, the default was 1 due to the coupling to build jobs).
|
|
||||||
|
|
|
@ -119,8 +119,7 @@ release:
|
||||||
TODO: This script requires the right AWS credentials. Document.
|
TODO: This script requires the right AWS credentials. Document.
|
||||||
|
|
||||||
TODO: This script currently requires a
|
TODO: This script currently requires a
|
||||||
`/home/eelco/Dev/nix-pristine` and
|
`/home/eelco/Dev/nix-pristine`.
|
||||||
`/home/eelco/Dev/nixpkgs-pristine`.
|
|
||||||
|
|
||||||
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
|
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
|
||||||
|
|
||||||
|
@ -141,7 +140,7 @@ release:
|
||||||
$ git checkout master
|
$ git checkout master
|
||||||
$ git pull
|
$ git pull
|
||||||
$ NEW_VERSION=2.13.0
|
$ NEW_VERSION=2.13.0
|
||||||
$ echo -n $NEW_VERSION > .version
|
$ echo $NEW_VERSION > .version
|
||||||
$ git checkout -b bump-$NEW_VERSION
|
$ git checkout -b bump-$NEW_VERSION
|
||||||
$ git commit -a -m 'Bump version'
|
$ git commit -a -m 'Bump version'
|
||||||
$ git push --set-upstream origin bump-$NEW_VERSION
|
$ git push --set-upstream origin bump-$NEW_VERSION
|
||||||
|
|
|
@ -15,7 +15,6 @@ my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n";
|
||||||
|
|
||||||
my $releasesBucketName = "nix-releases";
|
my $releasesBucketName = "nix-releases";
|
||||||
my $channelsBucketName = "nix-channels";
|
my $channelsBucketName = "nix-channels";
|
||||||
my $nixpkgsDir = "/home/eelco/Dev/nixpkgs-pristine";
|
|
||||||
|
|
||||||
my $TMPDIR = $ENV{'TMPDIR'} // "/tmp";
|
my $TMPDIR = $ENV{'TMPDIR'} // "/tmp";
|
||||||
|
|
||||||
|
@ -200,26 +199,22 @@ for my $fn (glob "$tmpDir/*") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update nix-fallback-paths.nix.
|
# Print new nix-fallback-paths.nix.
|
||||||
if ($isLatest) {
|
if ($isLatest) {
|
||||||
system("cd $nixpkgsDir && git pull") == 0 or die;
|
|
||||||
|
|
||||||
sub getStorePath {
|
sub getStorePath {
|
||||||
my ($jobName) = @_;
|
my ($jobName) = @_;
|
||||||
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
|
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
|
||||||
return $buildInfo->{buildoutputs}->{out}->{path} or die "cannot get store path for '$jobName'";
|
return $buildInfo->{buildoutputs}->{out}->{path} or die "cannot get store path for '$jobName'";
|
||||||
}
|
}
|
||||||
|
|
||||||
write_file("$nixpkgsDir/nixos/modules/installer/tools/nix-fallback-paths.nix",
|
print STDERR "nixos/modules/installer/tools/nix-fallback-paths.nix:\n" .
|
||||||
"{\n" .
|
"{\n" .
|
||||||
" x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
|
" x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" .
|
||||||
" i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
|
" i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" .
|
||||||
" aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
|
" aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" .
|
||||||
" x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
|
" x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" .
|
||||||
" aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
|
" aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" .
|
||||||
"}\n");
|
"}\n";
|
||||||
|
|
||||||
system("cd $nixpkgsDir && git commit -a -m 'nix-fallback-paths.nix: Update to $version'") == 0 or die;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update the "latest" symlink.
|
# Update the "latest" symlink.
|
||||||
|
|
|
@ -246,8 +246,15 @@ printf -v _OLD_LINE_FMT "%b" $'\033[1;7;31m-'"$ESC ${RED}%L${ESC}"
|
||||||
printf -v _NEW_LINE_FMT "%b" $'\033[1;7;32m+'"$ESC ${GREEN}%L${ESC}"
|
printf -v _NEW_LINE_FMT "%b" $'\033[1;7;32m+'"$ESC ${GREEN}%L${ESC}"
|
||||||
|
|
||||||
_diff() {
|
_diff() {
|
||||||
|
# macOS Ventura doesn't ship with GNU diff. Print similar output except
|
||||||
|
# without +/- markers or dimming
|
||||||
|
if diff --version | grep -q "Apple diff"; then
|
||||||
|
printf -v CHANGED_GROUP_FORMAT "%b" "${GREEN}%>${RED}%<${ESC}"
|
||||||
|
diff --changed-group-format="$CHANGED_GROUP_FORMAT" "$@"
|
||||||
|
else
|
||||||
# simple colorized diff comatible w/ pre `--color` versions
|
# simple colorized diff comatible w/ pre `--color` versions
|
||||||
diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
|
diff --unchanged-group-format="$_UNCHANGED_GRP_FMT" --old-line-format="$_OLD_LINE_FMT" --new-line-format="$_NEW_LINE_FMT" --unchanged-line-format=" %L" "$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm_rm() {
|
confirm_rm() {
|
||||||
|
|
|
@ -2620,7 +2620,7 @@ Strings EvalSettings::getDefaultNixPath()
|
||||||
{
|
{
|
||||||
Strings res;
|
Strings res;
|
||||||
auto add = [&](const Path & p, const std::string & s = std::string()) {
|
auto add = [&](const Path & p, const std::string & s = std::string()) {
|
||||||
if (pathExists(p)) {
|
if (pathAccessible(p)) {
|
||||||
if (s.empty()) {
|
if (s.empty()) {
|
||||||
res.push_back(p);
|
res.push_back(p);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -745,7 +745,13 @@ struct EvalSettings : Config
|
||||||
)"};
|
)"};
|
||||||
|
|
||||||
Setting<bool> pureEval{this, false, "pure-eval",
|
Setting<bool> pureEval{this, false, "pure-eval",
|
||||||
"Whether to restrict file system and network access to files specified by cryptographic hash."};
|
R"(
|
||||||
|
Pure evaluation mode ensures that the result of Nix expressions is fully determined by explicitly declared inputs, and not influenced by external state:
|
||||||
|
|
||||||
|
- Restrict file system and network access to files specified by cryptographic hash
|
||||||
|
- Disable [`bultins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem) and [`builtins.currentTime`](@docroot@/language/builtin-constants.md#builtins-currentTime)
|
||||||
|
)"
|
||||||
|
};
|
||||||
|
|
||||||
Setting<bool> enableImportFromDerivation{
|
Setting<bool> enableImportFromDerivation{
|
||||||
this, true, "allow-import-from-derivation",
|
this, true, "allow-import-from-derivation",
|
||||||
|
|
|
@ -1152,16 +1152,14 @@ drvName, Bindings * attrs, Value & v)
|
||||||
if (i->value->type() == nNull) continue;
|
if (i->value->type() == nNull) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->name == state.sContentAddressed) {
|
if (i->name == state.sContentAddressed && state.forceBool(*i->value, noPos, context_below)) {
|
||||||
contentAddressed = state.forceBool(*i->value, noPos, context_below);
|
contentAddressed = true;
|
||||||
if (contentAddressed)
|
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (i->name == state.sImpure) {
|
else if (i->name == state.sImpure && state.forceBool(*i->value, noPos, context_below)) {
|
||||||
isImpure = state.forceBool(*i->value, noPos, context_below);
|
isImpure = true;
|
||||||
if (isImpure)
|
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
||||||
experimentalFeatureSettings.require(Xp::ImpureDerivations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The `args' attribute is special: it supplies the
|
/* The `args' attribute is special: it supplies the
|
||||||
|
@ -1503,7 +1501,7 @@ static RegisterPrimOp primop_storePath({
|
||||||
causes the path to be *copied* again to the Nix store, resulting
|
causes the path to be *copied* again to the Nix store, resulting
|
||||||
in a new path (e.g. `/nix/store/ld01dnzc…-source-source`).
|
in a new path (e.g. `/nix/store/ld01dnzc…-source-source`).
|
||||||
|
|
||||||
This function is not available in pure evaluation mode.
|
Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
)",
|
)",
|
||||||
.fun = prim_storePath,
|
.fun = prim_storePath,
|
||||||
});
|
});
|
||||||
|
@ -3910,13 +3908,8 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
for (auto elem : args[0]->listItems())
|
for (auto elem : args[0]->listItems())
|
||||||
from.emplace_back(state.forceString(*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
from.emplace_back(state.forceString(*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
||||||
|
|
||||||
std::vector<std::pair<std::string, NixStringContext>> to;
|
std::unordered_map<size_t, std::string> cache;
|
||||||
to.reserve(args[1]->listSize());
|
auto to = args[1]->listItems();
|
||||||
for (auto elem : args[1]->listItems()) {
|
|
||||||
NixStringContext ctx;
|
|
||||||
auto s = state.forceString(*elem, ctx, pos, "while evaluating one of the replacement strings passed to builtins.replaceStrings");
|
|
||||||
to.emplace_back(s, std::move(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
auto s = state.forceString(*args[2], context, pos, "while evaluating the third argument passed to builtins.replaceStrings");
|
||||||
|
@ -3927,10 +3920,19 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
bool found = false;
|
bool found = false;
|
||||||
auto i = from.begin();
|
auto i = from.begin();
|
||||||
auto j = to.begin();
|
auto j = to.begin();
|
||||||
for (; i != from.end(); ++i, ++j)
|
size_t j_index = 0;
|
||||||
|
for (; i != from.end(); ++i, ++j, ++j_index)
|
||||||
if (s.compare(p, i->size(), *i) == 0) {
|
if (s.compare(p, i->size(), *i) == 0) {
|
||||||
found = true;
|
found = true;
|
||||||
res += j->first;
|
auto v = cache.find(j_index);
|
||||||
|
if (v == cache.end()) {
|
||||||
|
NixStringContext ctx;
|
||||||
|
auto ts = state.forceString(**j, ctx, pos, "while evaluating one of the replacement strings passed to builtins.replaceStrings");
|
||||||
|
v = (cache.emplace(j_index, ts)).first;
|
||||||
|
for (auto& path : ctx)
|
||||||
|
context.insert(path);
|
||||||
|
}
|
||||||
|
res += v->second;
|
||||||
if (i->empty()) {
|
if (i->empty()) {
|
||||||
if (p < s.size())
|
if (p < s.size())
|
||||||
res += s[p];
|
res += s[p];
|
||||||
|
@ -3938,9 +3940,6 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a
|
||||||
} else {
|
} else {
|
||||||
p += i->size();
|
p += i->size();
|
||||||
}
|
}
|
||||||
for (auto& path : j->second)
|
|
||||||
context.insert(path);
|
|
||||||
j->second.clear();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -3958,7 +3957,11 @@ static RegisterPrimOp primop_replaceStrings({
|
||||||
.args = {"from", "to", "s"},
|
.args = {"from", "to", "s"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Given string *s*, replace every occurrence of the strings in *from*
|
Given string *s*, replace every occurrence of the strings in *from*
|
||||||
with the corresponding string in *to*. For example,
|
with the corresponding string in *to*.
|
||||||
|
|
||||||
|
The argument *to* is lazy, that is, it is only evaluated when its corresponding pattern in *from* is matched in the string *s*
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
|
builtins.replaceStrings ["oo" "a"] ["a" "i"] "foobar"
|
||||||
|
|
|
@ -286,9 +286,9 @@ static RegisterPrimOp primop_fetchurl({
|
||||||
.name = "__fetchurl",
|
.name = "__fetchurl",
|
||||||
.args = {"url"},
|
.args = {"url"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Download the specified URL and return the path of the downloaded
|
Download the specified URL and return the path of the downloaded file.
|
||||||
file. This function is not available if [restricted evaluation
|
|
||||||
mode](../command-ref/conf-file.md) is enabled.
|
Not available in [restricted evaluation mode](@docroot@/command-ref/conf-file.md#conf-restrict-eval).
|
||||||
)",
|
)",
|
||||||
.fun = prim_fetchurl,
|
.fun = prim_fetchurl,
|
||||||
});
|
});
|
||||||
|
@ -338,8 +338,7 @@ static RegisterPrimOp primop_fetchTarball({
|
||||||
stdenv.mkDerivation { … }
|
stdenv.mkDerivation { … }
|
||||||
```
|
```
|
||||||
|
|
||||||
This function is not available if [restricted evaluation
|
Not available in [restricted evaluation mode](@docroot@/command-ref/conf-file.md#conf-restrict-eval).
|
||||||
mode](../command-ref/conf-file.md) is enabled.
|
|
||||||
)",
|
)",
|
||||||
.fun = prim_fetchTarball,
|
.fun = prim_fetchTarball,
|
||||||
});
|
});
|
||||||
|
@ -470,14 +469,9 @@ static RegisterPrimOp primop_fetchGit({
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
Nix will refetch the branch according to the [`tarball-ttl`](@docroot@/command-ref/conf-file.md#conf-tarball-ttl) setting.
|
||||||
>
|
|
||||||
> Nix will refetch the branch in accordance with
|
|
||||||
> the option `tarball-ttl`.
|
|
||||||
|
|
||||||
> **Note**
|
This behavior is disabled in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
>
|
|
||||||
> This behavior is disabled in *Pure evaluation mode*.
|
|
||||||
|
|
||||||
- To fetch the content of a checked-out work directory:
|
- To fetch the content of a checked-out work directory:
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace nix {
|
||||||
hintfmt("value is %s while a string was expected", "an integer"),
|
hintfmt("value is %s while a string was expected", "an integer"),
|
||||||
hintfmt("while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
hintfmt("while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
||||||
|
|
||||||
ASSERT_TRACE2("replaceStrings [ \"old\" ] [ true ] {}",
|
ASSERT_TRACE2("replaceStrings [ \"oo\" ] [ true ] \"foo\"",
|
||||||
TypeError,
|
TypeError,
|
||||||
hintfmt("value is %s while a string was expected", "a Boolean"),
|
hintfmt("value is %s while a string was expected", "a Boolean"),
|
||||||
hintfmt("while evaluating one of the replacement strings passed to builtins.replaceStrings"));
|
hintfmt("while evaluating one of the replacement strings passed to builtins.replaceStrings"));
|
||||||
|
|
|
@ -75,22 +75,28 @@ SourcePath SourcePath::resolveSymlinks() const
|
||||||
|
|
||||||
int linksAllowed = 1024;
|
int linksAllowed = 1024;
|
||||||
|
|
||||||
for (auto & component : path) {
|
std::list<std::string> todo;
|
||||||
res.path.push(component);
|
for (auto & c : path)
|
||||||
while (true) {
|
todo.push_back(std::string(c));
|
||||||
if (auto st = res.maybeLstat()) {
|
|
||||||
|
while (!todo.empty()) {
|
||||||
|
auto c = *todo.begin();
|
||||||
|
todo.pop_front();
|
||||||
|
if (c == "" || c == ".")
|
||||||
|
;
|
||||||
|
else if (c == "..")
|
||||||
|
res.path.pop();
|
||||||
|
else {
|
||||||
|
res.path.push(c);
|
||||||
|
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||||
if (!linksAllowed--)
|
if (!linksAllowed--)
|
||||||
throw Error("infinite symlink recursion in path '%s'", path);
|
throw Error("infinite symlink recursion in path '%s'", path);
|
||||||
if (st->type != InputAccessor::tSymlink) break;
|
|
||||||
auto target = res.readLink();
|
auto target = res.readLink();
|
||||||
|
res.path.pop();
|
||||||
if (hasPrefix(target, "/"))
|
if (hasPrefix(target, "/"))
|
||||||
res = CanonPath(target);
|
res.path = CanonPath::root;
|
||||||
else {
|
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||||
res.path.pop();
|
}
|
||||||
res.path.extend(CanonPath(target));
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,7 +357,7 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull()
|
||||||
for (auto & [_, status] : initialOutputs) {
|
for (auto & [_, status] : initialOutputs) {
|
||||||
if (!status.known) continue;
|
if (!status.known) continue;
|
||||||
if (buildMode != bmCheck && status.known->isValid()) continue;
|
if (buildMode != bmCheck && status.known->isValid()) continue;
|
||||||
auto p = worker.store.printStorePath(status.known->path);
|
auto p = worker.store.toRealPath(status.known->path);
|
||||||
if (pathExists(chrootRootDir + p))
|
if (pathExists(chrootRootDir + p))
|
||||||
renameFile((chrootRootDir + p), p);
|
renameFile((chrootRootDir + p), p);
|
||||||
}
|
}
|
||||||
|
@ -1772,7 +1772,8 @@ void LocalDerivationGoal::runChild()
|
||||||
if (pathExists(path))
|
if (pathExists(path))
|
||||||
ss.push_back(path);
|
ss.push_back(path);
|
||||||
|
|
||||||
dirsInChroot.emplace(settings.caFile, "/etc/ssl/certs/ca-certificates.crt");
|
if (settings.caFile != "")
|
||||||
|
dirsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
||||||
|
|
|
@ -183,7 +183,7 @@ bool Settings::isWSL1()
|
||||||
Path Settings::getDefaultSSLCertFile()
|
Path Settings::getDefaultSSLCertFile()
|
||||||
{
|
{
|
||||||
for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
|
for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
|
||||||
if (pathExists(fn)) return fn;
|
if (pathAccessible(fn)) return fn;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1014,6 +1014,18 @@ public:
|
||||||
| `~/.nix-profile` | `$XDG_STATE_HOME/nix/profile` |
|
| `~/.nix-profile` | `$XDG_STATE_HOME/nix/profile` |
|
||||||
| `~/.nix-defexpr` | `$XDG_STATE_HOME/nix/defexpr` |
|
| `~/.nix-defexpr` | `$XDG_STATE_HOME/nix/defexpr` |
|
||||||
| `~/.nix-channels` | `$XDG_STATE_HOME/nix/channels` |
|
| `~/.nix-channels` | `$XDG_STATE_HOME/nix/channels` |
|
||||||
|
|
||||||
|
If you already have Nix installed and are using [profiles](@docroot@/package-management/profiles.md) or [channels](@docroot@/package-management/channels.md), you should migrate manually when you enable this option.
|
||||||
|
If `$XDG_STATE_HOME` is not set, use `$HOME/.local/state/nix` instead of `$XDG_STATE_HOME/nix`.
|
||||||
|
This can be achieved with the following shell commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nix_state_home=${XDG_STATE_HOME-$HOME/.local/state}/nix
|
||||||
|
mkdir -p $nix_state_home
|
||||||
|
mv $HOME/.nix-profile $nix_state_home/profile
|
||||||
|
mv $HOME/.nix-defexpr $nix_state_home/defexpr
|
||||||
|
mv $HOME/.nix-channels $nix_state_home/channels
|
||||||
|
```
|
||||||
)"
|
)"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -190,7 +190,11 @@ LocalStore::LocalStore(const Params & params)
|
||||||
|
|
||||||
/* Create missing state directories if they don't already exist. */
|
/* Create missing state directories if they don't already exist. */
|
||||||
createDirs(realStoreDir);
|
createDirs(realStoreDir);
|
||||||
makeStoreWritable();
|
if (readOnly) {
|
||||||
|
experimentalFeatureSettings.require(Xp::ReadOnlyLocalStore);
|
||||||
|
} else {
|
||||||
|
makeStoreWritable();
|
||||||
|
}
|
||||||
createDirs(linksDir);
|
createDirs(linksDir);
|
||||||
Path profilesDir = stateDir + "/profiles";
|
Path profilesDir = stateDir + "/profiles";
|
||||||
createDirs(profilesDir);
|
createDirs(profilesDir);
|
||||||
|
@ -202,10 +206,6 @@ LocalStore::LocalStore(const Params & params)
|
||||||
createSymlink(profilesDir, gcRootsDir + "/profiles");
|
createSymlink(profilesDir, gcRootsDir + "/profiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readOnly) {
|
|
||||||
experimentalFeatureSettings.require(Xp::ReadOnlyLocalStore);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
|
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
|
||||||
createDirs(perUserDir);
|
createDirs(perUserDir);
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
|
|
|
@ -9,8 +9,8 @@ static void checkName(std::string_view path, std::string_view name)
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
throw BadStorePath("store path '%s' has an empty name", path);
|
throw BadStorePath("store path '%s' has an empty name", path);
|
||||||
if (name.size() > StorePath::MaxPathLen)
|
if (name.size() > StorePath::MaxPathLen)
|
||||||
throw BadStorePath("store path '%s' has a name longer than '%d characters",
|
throw BadStorePath("store path '%s' has a name longer than %d characters",
|
||||||
StorePath::MaxPathLen, path);
|
path, StorePath::MaxPathLen);
|
||||||
// See nameRegexStr for the definition
|
// See nameRegexStr for the definition
|
||||||
for (auto c : name)
|
for (auto c : name)
|
||||||
if (!((c >= '0' && c <= '9')
|
if (!((c >= '0' && c <= '9')
|
||||||
|
|
|
@ -50,6 +50,8 @@ constexpr std::array<ExperimentalFeatureDetails, 14> xpFeatureDetails = {{
|
||||||
or other impure derivations can rely on impure derivations. Finally,
|
or other impure derivations can rely on impure derivations. Finally,
|
||||||
an impure derivation cannot also be
|
an impure derivation cannot also be
|
||||||
[content-addressed](#xp-feature-ca-derivations).
|
[content-addressed](#xp-feature-ca-derivations).
|
||||||
|
|
||||||
|
This is a more explicit alternative to using [`builtins.currentTime`](@docroot@/language/builtin-constants.md#builtins-currentTime).
|
||||||
)",
|
)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -202,7 +202,7 @@ namespace nix {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(pathExists, bogusPathDoesNotExist) {
|
TEST(pathExists, bogusPathDoesNotExist) {
|
||||||
ASSERT_FALSE(pathExists("/home/schnitzel/darmstadt/pommes"));
|
ASSERT_FALSE(pathExists("/schnitzel/darmstadt/pommes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -266,6 +266,17 @@ bool pathExists(const Path & path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pathAccessible(const Path & path)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return pathExists(path);
|
||||||
|
} catch (SysError & e) {
|
||||||
|
// swallow EPERM
|
||||||
|
if (e.errNo == EPERM) return false;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Path readLink(const Path & path)
|
Path readLink(const Path & path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,6 +120,14 @@ struct stat lstat(const Path & path);
|
||||||
*/
|
*/
|
||||||
bool pathExists(const Path & path);
|
bool pathExists(const Path & path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version of pathExists that returns false on a permission error.
|
||||||
|
* Useful for inferring default paths across directories that might not
|
||||||
|
* be readable.
|
||||||
|
* @return true iff the given path can be accessed and exists
|
||||||
|
*/
|
||||||
|
bool pathAccessible(const Path & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the contents (target) of a symbolic link. The result is not
|
* Read the contents (target) of a symbolic link. The result is not
|
||||||
* in any way canonicalised.
|
* in any way canonicalised.
|
||||||
|
|
121
src/nix/flake.cc
121
src/nix/flake.cc
|
@ -259,6 +259,7 @@ struct CmdFlakeInfo : CmdFlakeMetadata
|
||||||
struct CmdFlakeCheck : FlakeCommand
|
struct CmdFlakeCheck : FlakeCommand
|
||||||
{
|
{
|
||||||
bool build = true;
|
bool build = true;
|
||||||
|
bool checkAllSystems = false;
|
||||||
|
|
||||||
CmdFlakeCheck()
|
CmdFlakeCheck()
|
||||||
{
|
{
|
||||||
|
@ -267,6 +268,11 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
.description = "Do not build checks.",
|
.description = "Do not build checks.",
|
||||||
.handler = {&build, false}
|
.handler = {&build, false}
|
||||||
});
|
});
|
||||||
|
addFlag({
|
||||||
|
.longName = "all-systems",
|
||||||
|
.description = "Check the outputs for all systems.",
|
||||||
|
.handler = {&checkAllSystems, true}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string description() override
|
std::string description() override
|
||||||
|
@ -292,6 +298,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
|
|
||||||
lockFlags.applyNixConfig = true;
|
lockFlags.applyNixConfig = true;
|
||||||
auto flake = lockFlake();
|
auto flake = lockFlake();
|
||||||
|
auto localSystem = std::string(settings.thisSystem.get());
|
||||||
|
|
||||||
bool hasErrors = false;
|
bool hasErrors = false;
|
||||||
auto reportError = [&](const Error & e) {
|
auto reportError = [&](const Error & e) {
|
||||||
|
@ -307,6 +314,8 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::set<std::string> omittedSystems;
|
||||||
|
|
||||||
// FIXME: rewrite to use EvalCache.
|
// FIXME: rewrite to use EvalCache.
|
||||||
|
|
||||||
auto resolve = [&] (PosIdx p) {
|
auto resolve = [&] (PosIdx p) {
|
||||||
|
@ -327,6 +336,15 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos)));
|
reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos)));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto checkSystemType = [&](const std::string & system, const PosIdx pos) {
|
||||||
|
if (!checkAllSystems && system != localSystem) {
|
||||||
|
omittedSystems.insert(system);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional<StorePath> {
|
auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional<StorePath> {
|
||||||
try {
|
try {
|
||||||
auto drvInfo = getDerivation(*state, v, false);
|
auto drvInfo = getDerivation(*state, v, false);
|
||||||
|
@ -509,16 +527,18 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
for (auto & attr2 : *attr.value->attrs) {
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
auto drvPath = checkDerivation(
|
for (auto & attr2 : *attr.value->attrs) {
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
auto drvPath = checkDerivation(
|
||||||
*attr2.value, attr2.pos);
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
if (drvPath && attr_name == settings.thisSystem.get()) {
|
*attr2.value, attr2.pos);
|
||||||
drvPaths.push_back(DerivedPath::Built {
|
if (drvPath && attr_name == settings.thisSystem.get()) {
|
||||||
.drvPath = *drvPath,
|
drvPaths.push_back(DerivedPath::Built {
|
||||||
.outputs = OutputsSpec::All { },
|
.drvPath = *drvPath,
|
||||||
});
|
.outputs = OutputsSpec::All { },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,9 +549,11 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
checkApp(
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
fmt("%s.%s", name, attr_name),
|
checkApp(
|
||||||
*attr.value, attr.pos);
|
fmt("%s.%s", name, attr_name),
|
||||||
|
*attr.value, attr.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,11 +562,13 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
for (auto & attr2 : *attr.value->attrs)
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
checkDerivation(
|
for (auto & attr2 : *attr.value->attrs)
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
checkDerivation(
|
||||||
*attr2.value, attr2.pos);
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
|
*attr2.value, attr2.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,11 +577,13 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
for (auto & attr2 : *attr.value->attrs)
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
checkApp(
|
for (auto & attr2 : *attr.value->attrs)
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
checkApp(
|
||||||
*attr2.value, attr2.pos);
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
|
*attr2.value, attr2.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,9 +592,11 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
checkDerivation(
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
fmt("%s.%s", name, attr_name),
|
checkDerivation(
|
||||||
*attr.value, attr.pos);
|
fmt("%s.%s", name, attr_name),
|
||||||
|
*attr.value, attr.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,9 +605,11 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
checkApp(
|
if (checkSystemType(attr_name, attr.pos) ) {
|
||||||
fmt("%s.%s", name, attr_name),
|
checkApp(
|
||||||
*attr.value, attr.pos);
|
fmt("%s.%s", name, attr_name),
|
||||||
|
*attr.value, attr.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +617,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
state->forceAttrs(vOutput, pos, "");
|
state->forceAttrs(vOutput, pos, "");
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
checkSystemName(state->symbols[attr.name], attr.pos);
|
checkSystemName(state->symbols[attr.name], attr.pos);
|
||||||
|
checkSystemType(state->symbols[attr.name], attr.pos);
|
||||||
// FIXME: do getDerivations?
|
// FIXME: do getDerivations?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -636,9 +667,11 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
checkBundler(
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
fmt("%s.%s", name, attr_name),
|
checkBundler(
|
||||||
*attr.value, attr.pos);
|
fmt("%s.%s", name, attr_name),
|
||||||
|
*attr.value, attr.pos);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,12 +680,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
for (auto & attr : *vOutput.attrs) {
|
for (auto & attr : *vOutput.attrs) {
|
||||||
const auto & attr_name = state->symbols[attr.name];
|
const auto & attr_name = state->symbols[attr.name];
|
||||||
checkSystemName(attr_name, attr.pos);
|
checkSystemName(attr_name, attr.pos);
|
||||||
state->forceAttrs(*attr.value, attr.pos, "");
|
if (checkSystemType(attr_name, attr.pos)) {
|
||||||
for (auto & attr2 : *attr.value->attrs) {
|
state->forceAttrs(*attr.value, attr.pos, "");
|
||||||
checkBundler(
|
for (auto & attr2 : *attr.value->attrs) {
|
||||||
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
checkBundler(
|
||||||
*attr2.value, attr2.pos);
|
fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
|
||||||
}
|
*attr2.value, attr2.pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,7 +720,15 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
}
|
}
|
||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
throw Error("some errors were encountered during the evaluation");
|
throw Error("some errors were encountered during the evaluation");
|
||||||
}
|
|
||||||
|
if (!omittedSystems.empty()) {
|
||||||
|
warn(
|
||||||
|
"The check omitted these incompatible systems: %s\n"
|
||||||
|
"Use '--all-systems' to check all.",
|
||||||
|
concatStringsSep(", ", omittedSystems)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
static Strings defaultTemplateAttrPathsPrefixes{"templates."};
|
static Strings defaultTemplateAttrPathsPrefixes{"templates."};
|
||||||
|
|
|
@ -102,6 +102,7 @@ way:
|
||||||
available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
|
available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
|
||||||
|
|
||||||
For example, if `/foo/bar` is a git repository with the following structure:
|
For example, if `/foo/bar` is a git repository with the following structure:
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
└── baz
|
└── baz
|
||||||
|
|
|
@ -35,3 +35,9 @@ nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
||||||
# Check that symlink cycles don't cause a hang.
|
# Check that symlink cycles don't cause a hang.
|
||||||
ln -sfn cycle.nix $TEST_ROOT/cycle.nix
|
ln -sfn cycle.nix $TEST_ROOT/cycle.nix
|
||||||
(! nix eval --file $TEST_ROOT/cycle.nix)
|
(! nix eval --file $TEST_ROOT/cycle.nix)
|
||||||
|
|
||||||
|
# Check that relative symlinks are resolved correctly.
|
||||||
|
mkdir -p $TEST_ROOT/xyzzy $TEST_ROOT/foo
|
||||||
|
ln -sfn ../xyzzy $TEST_ROOT/foo/bar
|
||||||
|
printf 123 > $TEST_ROOT/xyzzy/default.nix
|
||||||
|
[[ $(nix eval --impure --expr "import $TEST_ROOT/foo/bar") = 123 ]]
|
||||||
|
|
|
@ -72,6 +72,8 @@ cat > $flakeDir/flake.nix <<EOF
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
checkRes=$(nix flake check --keep-going $flakeDir 2>&1 && fail "nix flake check should have failed" || true)
|
nix flake check $flakeDir
|
||||||
|
|
||||||
|
checkRes=$(nix flake check --all-systems --keep-going $flakeDir 2>&1 && fail "nix flake check --all-systems should have failed" || true)
|
||||||
echo "$checkRes" | grepQuiet "packages.system-1.default"
|
echo "$checkRes" | grepQuiet "packages.system-1.default"
|
||||||
echo "$checkRes" | grepQuiet "packages.system-2.default"
|
echo "$checkRes" | grepQuiet "packages.system-2.default"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
[ "faabar" "fbar" "fubar" "faboor" "fubar" "XaXbXcX" "X" "a_b" ]
|
[ "faabar" "fbar" "fubar" "faboor" "fubar" "XaXbXcX" "X" "a_b" "fubar" ]
|
||||||
|
|
|
@ -8,4 +8,5 @@ with builtins;
|
||||||
(replaceStrings [""] ["X"] "abc")
|
(replaceStrings [""] ["X"] "abc")
|
||||||
(replaceStrings [""] ["X"] "")
|
(replaceStrings [""] ["X"] "")
|
||||||
(replaceStrings ["-"] ["_"] "a-b")
|
(replaceStrings ["-"] ["_"] "a-b")
|
||||||
|
(replaceStrings ["oo" "XX"] ["u" (throw "unreachable")] "foobar")
|
||||||
]
|
]
|
||||||
|
|
29
tests/linux-sandbox-cert-test.nix
Normal file
29
tests/linux-sandbox-cert-test.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{ fixed-output }:
|
||||||
|
|
||||||
|
with import ./config.nix;
|
||||||
|
|
||||||
|
mkDerivation ({
|
||||||
|
name = "ssl-export";
|
||||||
|
buildCommand = ''
|
||||||
|
# Add some indirection, otherwise grepping into the debug output finds the string.
|
||||||
|
report () { echo CERT_$1_IN_SANDBOX; }
|
||||||
|
|
||||||
|
if [ -f /etc/ssl/certs/ca-certificates.crt ]; then
|
||||||
|
content=$(</etc/ssl/certs/ca-certificates.crt)
|
||||||
|
if [ "$content" == CERT_CONTENT ]; then
|
||||||
|
report present
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
report missing
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always fail, because we do not want to bother with fixed-output
|
||||||
|
# derivations being cached, and do not want to compute the right hash.
|
||||||
|
false;
|
||||||
|
'';
|
||||||
|
} // (
|
||||||
|
if fixed-output == "fixed-output"
|
||||||
|
then { outputHash = "sha256:0000000000000000000000000000000000000000000000000000000000000000"; }
|
||||||
|
else { }
|
||||||
|
))
|
||||||
|
|
|
@ -40,3 +40,27 @@ grepQuiet 'may not be deterministic' $TEST_ROOT/log
|
||||||
|
|
||||||
# Test that sandboxed builds cannot write to /etc easily
|
# Test that sandboxed builds cannot write to /etc easily
|
||||||
(! nix-build -E 'with import ./config.nix; mkDerivation { name = "etc-write"; buildCommand = "echo > /etc/test"; }' --no-out-link --sandbox-paths /nix/store)
|
(! nix-build -E 'with import ./config.nix; mkDerivation { name = "etc-write"; buildCommand = "echo > /etc/test"; }' --no-out-link --sandbox-paths /nix/store)
|
||||||
|
|
||||||
|
|
||||||
|
## Test mounting of SSL certificates into the sandbox
|
||||||
|
testCert () {
|
||||||
|
(! nix-build linux-sandbox-cert-test.nix --argstr fixed-output "$2" --no-out-link --sandbox-paths /nix/store --option ssl-cert-file "$3" 2> $TEST_ROOT/log)
|
||||||
|
cat $TEST_ROOT/log
|
||||||
|
grepQuiet "CERT_${1}_IN_SANDBOX" $TEST_ROOT/log
|
||||||
|
}
|
||||||
|
|
||||||
|
nocert=$TEST_ROOT/no-cert-file.pem
|
||||||
|
cert=$TEST_ROOT/some-cert-file.pem
|
||||||
|
echo -n "CERT_CONTENT" > $cert
|
||||||
|
|
||||||
|
# No cert in sandbox when not a fixed-output derivation
|
||||||
|
testCert missing normal "$cert"
|
||||||
|
|
||||||
|
# No cert in sandbox when ssl-cert-file is empty
|
||||||
|
testCert missing fixed-output ""
|
||||||
|
|
||||||
|
# No cert in sandbox when ssl-cert-file is a nonexistent file
|
||||||
|
testCert missing fixed-output "$nocert"
|
||||||
|
|
||||||
|
# Cert in sandbox when ssl-cert-file is set to an existing file
|
||||||
|
testCert present fixed-output "$cert"
|
||||||
|
|
Loading…
Reference in a new issue