mirror of
https://github.com/NixOS/nix.git
synced 2025-11-24 03:09:35 +01:00
Merge commit '8388d2c7c6' into progress-bar
This commit is contained in:
commit
e73dcf2cdd
95 changed files with 1215 additions and 717 deletions
26
.github/workflows/backport.yml
vendored
Normal file
26
.github/workflows/backport.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
name: Backport
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [closed, labeled]
|
||||||
|
jobs:
|
||||||
|
backport:
|
||||||
|
name: Backport Pull Request
|
||||||
|
if: github.repository_owner == 'NixOS' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
# required to find all branches
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Create backport PRs
|
||||||
|
# should be kept in sync with `version`
|
||||||
|
uses: zeebe-io/backport-action@v0.0.7
|
||||||
|
with:
|
||||||
|
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
github_workspace: ${{ github.workspace }}
|
||||||
|
pull_description: |-
|
||||||
|
Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}.
|
||||||
|
# should be kept in sync with `uses`
|
||||||
|
version: v0.0.5
|
||||||
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
|
|
@ -14,10 +14,10 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.3.5
|
- uses: actions/checkout@v2.4.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@v14.1
|
- uses: cachix/install-nix-action@v16
|
||||||
- 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@v10
|
- uses: cachix/cachix-action@v10
|
||||||
if: needs.check_cachix.outputs.secret == 'true'
|
if: needs.check_cachix.outputs.secret == 'true'
|
||||||
|
|
@ -46,11 +46,11 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
installerURL: ${{ steps.prepare-installer.outputs.installerURL }}
|
installerURL: ${{ steps.prepare-installer.outputs.installerURL }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.3.5
|
- uses: actions/checkout@v2.4.0
|
||||||
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@v14.1
|
- uses: cachix/install-nix-action@v16
|
||||||
- uses: cachix/cachix-action@v10
|
- uses: cachix/cachix-action@v10
|
||||||
with:
|
with:
|
||||||
name: '${{ env.CACHIX_NAME }}'
|
name: '${{ env.CACHIX_NAME }}'
|
||||||
|
|
@ -67,9 +67,9 @@ jobs:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.3.5
|
- uses: actions/checkout@v2.4.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@v14.1
|
- uses: cachix/install-nix-action@v16
|
||||||
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"
|
||||||
|
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -26,8 +26,6 @@ perl/Makefile.config
|
||||||
|
|
||||||
# /scripts/
|
# /scripts/
|
||||||
/scripts/nix-profile.sh
|
/scripts/nix-profile.sh
|
||||||
/scripts/nix-reduce-build
|
|
||||||
/scripts/nix-http-export.cgi
|
|
||||||
/scripts/nix-profile-daemon.sh
|
/scripts/nix-profile-daemon.sh
|
||||||
|
|
||||||
# /src/libexpr/
|
# /src/libexpr/
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
|
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
|
||||||
index 1cee6a0b..46c3acd9 100644
|
index 4b2c429..1fb4c52 100644
|
||||||
--- a/pthread_stop_world.c
|
--- a/pthread_stop_world.c
|
||||||
+++ b/pthread_stop_world.c
|
+++ b/pthread_stop_world.c
|
||||||
@@ -674,6 +674,8 @@ GC_INNER void GC_push_all_stacks(void)
|
@@ -673,6 +673,8 @@ GC_INNER void GC_push_all_stacks(void)
|
||||||
struct GC_traced_stack_sect_s *traced_stack_sect;
|
struct GC_traced_stack_sect_s *traced_stack_sect;
|
||||||
pthread_t self = pthread_self();
|
pthread_t self = pthread_self();
|
||||||
word total_size = 0;
|
word total_size = 0;
|
||||||
|
|
@ -11,7 +11,7 @@ index 1cee6a0b..46c3acd9 100644
|
||||||
|
|
||||||
if (!EXPECT(GC_thr_initialized, TRUE))
|
if (!EXPECT(GC_thr_initialized, TRUE))
|
||||||
GC_thr_init();
|
GC_thr_init();
|
||||||
@@ -723,6 +725,28 @@ GC_INNER void GC_push_all_stacks(void)
|
@@ -722,6 +724,31 @@ GC_INNER void GC_push_all_stacks(void)
|
||||||
hi = p->altstack + p->altstack_size;
|
hi = p->altstack + p->altstack_size;
|
||||||
/* FIXME: Need to scan the normal stack too, but how ? */
|
/* FIXME: Need to scan the normal stack too, but how ? */
|
||||||
/* FIXME: Assume stack grows down */
|
/* FIXME: Assume stack grows down */
|
||||||
|
|
@ -22,6 +22,9 @@ index 1cee6a0b..46c3acd9 100644
|
||||||
+ if (pthread_attr_getstacksize(&pattr, &stack_limit)) {
|
+ if (pthread_attr_getstacksize(&pattr, &stack_limit)) {
|
||||||
+ ABORT("GC_push_all_stacks: pthread_attr_getstacksize failed!");
|
+ ABORT("GC_push_all_stacks: pthread_attr_getstacksize failed!");
|
||||||
+ }
|
+ }
|
||||||
|
+ if (pthread_attr_destroy(&pattr)) {
|
||||||
|
+ ABORT("GC_push_all_stacks: pthread_attr_destroy failed!");
|
||||||
|
+ }
|
||||||
+ // When a thread goes into a coroutine, we lose its original sp until
|
+ // When a thread goes into a coroutine, we lose its original sp until
|
||||||
+ // control flow returns to the thread.
|
+ // control flow returns to the thread.
|
||||||
+ // While in the coroutine, the sp points outside the thread stack,
|
+ // While in the coroutine, the sp points outside the thread stack,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
- [Prerequisites](installation/prerequisites-source.md)
|
- [Prerequisites](installation/prerequisites-source.md)
|
||||||
- [Obtaining a Source Distribution](installation/obtaining-source.md)
|
- [Obtaining a Source Distribution](installation/obtaining-source.md)
|
||||||
- [Building Nix from Source](installation/building-source.md)
|
- [Building Nix from Source](installation/building-source.md)
|
||||||
|
- [Using Nix within Docker](installation/installing-docker.md)
|
||||||
- [Security](installation/nix-security.md)
|
- [Security](installation/nix-security.md)
|
||||||
- [Single-User Mode](installation/single-user.md)
|
- [Single-User Mode](installation/single-user.md)
|
||||||
- [Multi-User Mode](installation/multi-user.md)
|
- [Multi-User Mode](installation/multi-user.md)
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,9 @@ By default Nix reads settings from the following places:
|
||||||
will be loaded in reverse order.
|
will be loaded in reverse order.
|
||||||
|
|
||||||
Otherwise it will look for `nix/nix.conf` files in `XDG_CONFIG_DIRS`
|
Otherwise it will look for `nix/nix.conf` files in `XDG_CONFIG_DIRS`
|
||||||
and `XDG_CONFIG_HOME`. If these are unset, it will look in
|
and `XDG_CONFIG_HOME`. If unset, `XDG_CONFIG_DIRS` defaults to
|
||||||
`$HOME/.config/nix.conf`.
|
`/etc/xdg`, and `XDG_CONFIG_HOME` defaults to `$HOME/.config`
|
||||||
|
as per [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
|
||||||
|
|
||||||
- If `NIX_CONFIG` is set, its contents is treated as the contents of
|
- If `NIX_CONFIG` is set, its contents is treated as the contents of
|
||||||
a configuration file.
|
a configuration file.
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,16 @@ a number of possible ways:
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
To install a specific version of `gcc` from the active Nix expression:
|
To install a package using a specific attribute path from the active Nix expression:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-env -iA gcc40mips
|
||||||
|
installing `gcc-4.0.2'
|
||||||
|
$ nix-env -iA xorg.xorgserver
|
||||||
|
installing `xorg-server-1.2.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
To install a specific version of `gcc` using the derivation name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --install gcc-3.3.2
|
$ nix-env --install gcc-3.3.2
|
||||||
|
|
@ -246,6 +255,9 @@ installing `gcc-3.3.2'
|
||||||
uninstalling `gcc-3.1'
|
uninstalling `gcc-3.1'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Using attribute path for selecting a package is preferred,
|
||||||
|
as it is much faster and there will not be multiple matches.
|
||||||
|
|
||||||
Note the previously installed version is removed, since
|
Note the previously installed version is removed, since
|
||||||
`--preserve-installed` was not specified.
|
`--preserve-installed` was not specified.
|
||||||
|
|
||||||
|
|
@ -256,13 +268,6 @@ $ nix-env --install gcc
|
||||||
installing `gcc-3.3.2'
|
installing `gcc-3.3.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
To install using a specific attribute:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ nix-env -i -A gcc40mips
|
|
||||||
$ nix-env -i -A xorg.xorgserver
|
|
||||||
```
|
|
||||||
|
|
||||||
To install all derivations in the Nix expression `foo.nix`:
|
To install all derivations in the Nix expression `foo.nix`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
|
@ -374,22 +379,29 @@ For the other flags, see `--install`.
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env --upgrade gcc
|
$ nix-env --upgrade -A 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:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u gcc-3.3.2 --always (switch to a specific version)
|
$ nix-env --upgrade -A nixpkgs.pan
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix-env -u gcc-3.3.2 --always
|
||||||
upgrading `gcc-3.4' to `gcc-3.3.2'
|
upgrading `gcc-3.4' to `gcc-3.3.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
To try to upgrade everything
|
||||||
$ nix-env --upgrade pan
|
(matching packages based on the part of the derivation name without version):
|
||||||
(no upgrades available, so nothing happens)
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -u (try to upgrade everything)
|
$ nix-env -u
|
||||||
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'
|
||||||
```
|
```
|
||||||
|
|
@ -401,7 +413,7 @@ of a derivation `x` by looking at their respective `name` attributes.
|
||||||
The names (e.g., `gcc-3.3.1` are split into two parts: the package name
|
The names (e.g., `gcc-3.3.1` are split into two parts: the package name
|
||||||
(`gcc`), and the version (`3.3.1`). The version part starts after the
|
(`gcc`), and the version (`3.3.1`). The version part starts after the
|
||||||
first dash not followed by a letter. `x` is considered an upgrade of `y`
|
first dash not followed by a letter. `x` is considered an upgrade of `y`
|
||||||
if their package names match, and the version of `y` is higher that that
|
if their package names match, and the version of `y` is higher than that
|
||||||
of `x`.
|
of `x`.
|
||||||
|
|
||||||
The versions are compared by splitting them into contiguous components
|
The versions are compared by splitting them into contiguous components
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ Special exit codes:
|
||||||
|
|
||||||
- `104`\
|
- `104`\
|
||||||
Not deterministic, the build succeeded in check mode but the
|
Not deterministic, the build succeeded in check mode but the
|
||||||
resulting output is not binary reproducable.
|
resulting output is not binary reproducible.
|
||||||
|
|
||||||
With the `--keep-going` flag it's possible for multiple failures to
|
With the `--keep-going` flag it's possible for multiple failures to
|
||||||
occur, in this case the 1xx status codes are or combined using binary
|
occur, in this case the 1xx status codes are or combined using binary
|
||||||
|
|
|
||||||
|
|
@ -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 -i
|
So if you call this Nix expression (e.g., when you do `nix-env -iA
|
||||||
pkgname`), the function will be called automatically using the
|
pkgname`), the function will be called automatically using the
|
||||||
value [`builtins.currentSystem`](../expressions/builtins.md) for
|
value [`builtins.currentSystem`](../expressions/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 -i pkgname --arg system \"i686-freebsd\"`. (Note that
|
`nix-env -iA pkgname --arg system \"i686-freebsd\"`. (Note that
|
||||||
since the argument is a Nix string literal, you have to escape the
|
since the argument is a Nix string literal, you have to escape the
|
||||||
quotes.)
|
quotes.)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
## Goals
|
## Goals
|
||||||
|
|
||||||
Purpose of this document is to provide a clear direction to **help design
|
Purpose of this document is to provide a clear direction to **help design
|
||||||
delightful command line** experience. This document contain guidelines to
|
delightful command line** experience. This document contains guidelines to
|
||||||
follow to ensure a consistent and approachable user experience.
|
follow to ensure a consistent and approachable user experience.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
@ -103,7 +103,7 @@ impacted the most by bad user experience.
|
||||||
# Help is essential
|
# Help is essential
|
||||||
|
|
||||||
Help should be built into your command line so that new users can gradually
|
Help should be built into your command line so that new users can gradually
|
||||||
discover new features when they need them.
|
discover new features when they need them.
|
||||||
|
|
||||||
## Looking for help
|
## Looking for help
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ The rules are:
|
||||||
|
|
||||||
- Help is shown by using `--help` or `help` command (eg `nix` `--``help` or
|
- Help is shown by using `--help` or `help` command (eg `nix` `--``help` or
|
||||||
`nix help`).
|
`nix help`).
|
||||||
- For non-COMMANDs (eg. `nix` `--``help` and `nix store` `--``help`) we **show
|
- For non-COMMANDs (eg. `nix` `--``help` and `nix store` `--``help`) we **show
|
||||||
a summary** of most common use cases. Summary is presented on the STDOUT
|
a summary** of most common use cases. Summary is presented on the STDOUT
|
||||||
without any use of PAGER.
|
without any use of PAGER.
|
||||||
- For COMMANDs (eg. `nix init` `--``help` or `nix help init`) we display the
|
- For COMMANDs (eg. `nix init` `--``help` or `nix help init`) we display the
|
||||||
|
|
@ -176,7 +176,7 @@ $ nix init --template=template#pyton
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Initializing Nix project at `/path/to/here`.
|
Initializing Nix project at `/path/to/here`.
|
||||||
Select a template for you new project:
|
Select a template for you new project:
|
||||||
|> template#pyton
|
|> template#python
|
||||||
template#python-pip
|
template#python-pip
|
||||||
template#python-poetry
|
template#python-poetry
|
||||||
```
|
```
|
||||||
|
|
@ -230,17 +230,17 @@ Now **Learn** part of the output is where you educate users. You should only
|
||||||
show it when you know that a build will take some time and not annoy users of
|
show it when you know that a build will take some time and not annoy users of
|
||||||
the builds that take only few seconds.
|
the builds that take only few seconds.
|
||||||
|
|
||||||
Every feature like this should go though a intensive review and testing to
|
Every feature like this should go through an intensive review and testing to
|
||||||
collect as much a feedback as possible and to fine tune every little detail. If
|
collect as much feedback as possible and to fine tune every little detail. If
|
||||||
done right this can be an awesome features beginners and advance users will
|
done right this can be an awesome features beginners and advance users will
|
||||||
love, but if not done perfectly it will annoy users and leave bad impression.
|
love, but if not done perfectly it will annoy users and leave bad impression.
|
||||||
|
|
||||||
# Input
|
# Input
|
||||||
|
|
||||||
Input to a command is provided via `ARGUMENTS` and `OPTIONS`.
|
Input to a command is provided via `ARGUMENTS` and `OPTIONS`.
|
||||||
|
|
||||||
`ARGUMENTS` represent a required input for a function. When choosing to use
|
`ARGUMENTS` represent a required input for a function. When choosing to use
|
||||||
`ARGUMENT` over function please be aware of the downsides that come with it:
|
`ARGUMENTS` over `OPTIONS` please be aware of the downsides that come with it:
|
||||||
|
|
||||||
- User will need to remember the order of `ARGUMENTS`. This is not a problem if
|
- User will need to remember the order of `ARGUMENTS`. This is not a problem if
|
||||||
there is only one `ARGUMENT`.
|
there is only one `ARGUMENT`.
|
||||||
|
|
@ -253,7 +253,7 @@ developer consider the downsides and choose wisely.
|
||||||
|
|
||||||
## Naming the `OPTIONS`
|
## Naming the `OPTIONS`
|
||||||
|
|
||||||
Then only naming convention - apart from the ones mentioned in Naming the
|
The only naming convention - apart from the ones mentioned in Naming the
|
||||||
`COMMANDS` section is how flags are named.
|
`COMMANDS` section is how flags are named.
|
||||||
|
|
||||||
Flags are a type of `OPTION` that represent an option that can be turned ON of
|
Flags are a type of `OPTION` that represent an option that can be turned ON of
|
||||||
|
|
@ -271,12 +271,12 @@ to improve the discoverability of possible input. A new user will most likely
|
||||||
not know which `ARGUMENTS` and `OPTIONS` are required or which values are
|
not know which `ARGUMENTS` and `OPTIONS` are required or which values are
|
||||||
possible for those options.
|
possible for those options.
|
||||||
|
|
||||||
In cases, the user might not provide the input or they provide wrong input,
|
In case the user does not provide the input or they provide wrong input,
|
||||||
rather then show the error, prompt a user with an option to find and select
|
rather than show the error, prompt a user with an option to find and select
|
||||||
correct input (see examples).
|
correct input (see examples).
|
||||||
|
|
||||||
Prompting is of course not required when TTY is not attached to STDIN. This
|
Prompting is of course not required when TTY is not attached to STDIN. This
|
||||||
would mean that scripts wont need to handle prompt, but rather handle errors.
|
would mean that scripts won't need to handle prompt, but rather handle errors.
|
||||||
|
|
||||||
A place to use prompt and provide user with interactive select
|
A place to use prompt and provide user with interactive select
|
||||||
|
|
||||||
|
|
@ -300,9 +300,9 @@ going to happen.
|
||||||
```shell
|
```shell
|
||||||
$ nix build --option substitutors https://cache.example.org
|
$ nix build --option substitutors https://cache.example.org
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Warning! A security related question need to be answered.
|
Warning! A security related question needs to be answered.
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
The following substitutors will be used to in `my-project`:
|
The following substitutors will be used to in `my-project`:
|
||||||
- https://cache.example.org
|
- https://cache.example.org
|
||||||
|
|
||||||
Do you allow `my-project` to use above mentioned substitutors?
|
Do you allow `my-project` to use above mentioned substitutors?
|
||||||
|
|
@ -311,14 +311,14 @@ $ nix build --option substitutors https://cache.example.org
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
|
|
||||||
Terminal output can be quite limiting in many ways. Which should forces us to
|
Terminal output can be quite limiting in many ways. Which should force us to
|
||||||
think about the experience even more. As with every design the output is a
|
think about the experience even more. As with every design the output is a
|
||||||
compromise between being terse and being verbose, between showing help to
|
compromise between being terse and being verbose, between showing help to
|
||||||
beginners and annoying advance users. For this it is important that we know
|
beginners and annoying advance users. For this it is important that we know
|
||||||
what are the priorities.
|
what are the priorities.
|
||||||
|
|
||||||
Nix command line should be first and foremost written with beginners in mind.
|
Nix command line should be first and foremost written with beginners in mind.
|
||||||
But users wont stay beginners for long and what was once useful might quickly
|
But users won't stay beginners for long and what was once useful might quickly
|
||||||
become annoying. There is no golden rule that we can give in this guideline
|
become annoying. There is no golden rule that we can give in this guideline
|
||||||
that would make it easier how to draw a line and find best compromise.
|
that would make it easier how to draw a line and find best compromise.
|
||||||
|
|
||||||
|
|
@ -342,7 +342,7 @@ also allowing them to redirect content to a file. For example:
|
||||||
```shell
|
```shell
|
||||||
$ nix build > build.txt
|
$ nix build > build.txt
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Error! Atrribute `bin` missing at (1:94) from string.
|
Error! Attribute `bin` missing at (1:94) from string.
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
1| with import <nixpkgs> { }; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (surge.bin) ]; } ""
|
1| with import <nixpkgs> { }; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (surge.bin) ]; } ""
|
||||||
|
|
@ -408,7 +408,7 @@ Above command clearly states that command successfully completed. And in case
|
||||||
of `nix build`, which is a command that might take some time to complete, it is
|
of `nix build`, which is a command that might take some time to complete, it is
|
||||||
equally important to also show that a command started.
|
equally important to also show that a command started.
|
||||||
|
|
||||||
## Text alignment
|
## Text alignment
|
||||||
|
|
||||||
Text alignment is the number one design element that will present all of the
|
Text alignment is the number one design element that will present all of the
|
||||||
Nix commands as a family and not as separate tools glued together.
|
Nix commands as a family and not as separate tools glued together.
|
||||||
|
|
@ -419,7 +419,7 @@ The format we should follow is:
|
||||||
$ nix COMMAND
|
$ nix COMMAND
|
||||||
VERB_1 NOUN and other words
|
VERB_1 NOUN and other words
|
||||||
VERB__1 NOUN and other words
|
VERB__1 NOUN and other words
|
||||||
|> Some details
|
|> Some details
|
||||||
```
|
```
|
||||||
|
|
||||||
Few rules that we can extract from above example:
|
Few rules that we can extract from above example:
|
||||||
|
|
@ -444,13 +444,13 @@ is not even notable, therefore relying on it wouldn’t make much sense.
|
||||||
|
|
||||||
**The bright text is much better supported** across terminals and color
|
**The bright text is much better supported** across terminals and color
|
||||||
schemes. Most of the time the difference is perceived as if the bright text
|
schemes. Most of the time the difference is perceived as if the bright text
|
||||||
would be bold.
|
would be bold.
|
||||||
|
|
||||||
## Colors
|
## Colors
|
||||||
|
|
||||||
Humans are already conditioned by society to attach certain meaning to certain
|
Humans are already conditioned by society to attach certain meaning to certain
|
||||||
colors. While the meaning is not universal, a simple collection of colors is
|
colors. While the meaning is not universal, a simple collection of colors is
|
||||||
used to represent basic emotions.
|
used to represent basic emotions.
|
||||||
|
|
||||||
Colors that can be used in output
|
Colors that can be used in output
|
||||||
|
|
||||||
|
|
@ -508,7 +508,7 @@ can, with a few key strokes, be changed into and advance introspection tool.
|
||||||
|
|
||||||
### Progress
|
### Progress
|
||||||
|
|
||||||
For longer running commands we should provide and overview of the progress.
|
For longer running commands we should provide and overview the progress.
|
||||||
This is shown best in `nix build` example:
|
This is shown best in `nix build` example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
@ -553,9 +553,9 @@ going to happen.
|
||||||
```shell
|
```shell
|
||||||
$ nix build --option substitutors https://cache.example.org
|
$ nix build --option substitutors https://cache.example.org
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Warning! A security related question need to be answered.
|
Warning! A security related question needs to be answered.
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
The following substitutors will be used to in `my-project`:
|
The following substitutors will be used to in `my-project`:
|
||||||
- https://cache.example.org
|
- https://cache.example.org
|
||||||
|
|
||||||
Do you allow `my-project` to use above mentioned substitutors?
|
Do you allow `my-project` to use above mentioned substitutors?
|
||||||
|
|
@ -566,7 +566,7 @@ $ nix build --option substitutors https://cache.example.org
|
||||||
|
|
||||||
There are many ways that you can control verbosity.
|
There are many ways that you can control verbosity.
|
||||||
|
|
||||||
Verbosity levels are:
|
Verbosity levels are:
|
||||||
|
|
||||||
- `ERROR` (level 0)
|
- `ERROR` (level 0)
|
||||||
- `WARN` (level 1)
|
- `WARN` (level 1)
|
||||||
|
|
@ -586,4 +586,4 @@ There are also two shortcuts, `--debug` to run in `DEBUG` verbosity level and
|
||||||
|
|
||||||
# Appendix 1: Commands naming exceptions
|
# Appendix 1: Commands naming exceptions
|
||||||
|
|
||||||
`nix init` and `nix repl` are well established
|
`nix init` and `nix repl` are well established
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ Derivations can declare some infrequently used optional attributes.
|
||||||
- `preferLocalBuild`\
|
- `preferLocalBuild`\
|
||||||
If this attribute is set to `true` and [distributed building is
|
If this attribute is set to `true` and [distributed building is
|
||||||
enabled](../advanced-topics/distributed-builds.md), then, if
|
enabled](../advanced-topics/distributed-builds.md), then, if
|
||||||
possible, the derivaton will be built locally instead of forwarded
|
possible, the derivation will be built locally instead of forwarded
|
||||||
to a remote machine. This is appropriate for trivial builders
|
to a remote machine. This is appropriate for trivial builders
|
||||||
where the cost of doing a download or remote build would exceed
|
where the cost of doing a download or remote build would exceed
|
||||||
the cost of building locally.
|
the cost of building locally.
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,5 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>derivation <var>attrs</var></code>;
|
<dt><code>derivation <var>attrs</var></code>;
|
||||||
<code>builtins.derivation <var>attrs</var></code></dt>
|
<code>builtins.derivation <var>attrs</var></code></dt>
|
||||||
<dd><p><var>derivation</var> in described in
|
<dd><p><var>derivation</var> is described in
|
||||||
<a href="derivations.md">its own section</a>.</p></dd>
|
<a href="derivations.md">its own section</a>.</p></dd>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ elements (referenced from the figure by number):
|
||||||
called with three arguments: `stdenv`, `fetchurl`, and `perl`. They
|
called with three arguments: `stdenv`, `fetchurl`, and `perl`. They
|
||||||
are needed to build Hello, but we don't know how to build them here;
|
are needed to build Hello, but we don't know how to build them here;
|
||||||
that's why they are function arguments. `stdenv` is a package that
|
that's why they are function arguments. `stdenv` is a package that
|
||||||
is used by almost all Nix Packages packages; it provides a
|
is used by almost all Nix Packages; it provides a
|
||||||
“standard” environment consisting of the things you would expect
|
“standard” environment consisting of the things you would expect
|
||||||
in a basic Unix environment: a C/C++ compiler (GCC, to be precise),
|
in a basic Unix environment: a C/C++ compiler (GCC, to be precise),
|
||||||
the Bash shell, fundamental Unix tools such as `cp`, `grep`, `tar`,
|
the Bash shell, fundamental Unix tools such as `cp`, `grep`, `tar`,
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ order of precedence (from strongest to weakest binding).
|
||||||
| String Concatenation | *string1* `+` *string2* | left | String concatenation. | 7 |
|
| String Concatenation | *string1* `+` *string2* | left | String concatenation. | 7 |
|
||||||
| Not | `!` *e* | none | Boolean negation. | 8 |
|
| Not | `!` *e* | none | Boolean negation. | 8 |
|
||||||
| Update | *e1* `//` *e2* | right | Return a set consisting of the attributes in *e1* and *e2* (with the latter taking precedence over the former in case of equally named attributes). | 9 |
|
| Update | *e1* `//` *e2* | right | Return a set consisting of the attributes in *e1* and *e2* (with the latter taking precedence over the former in case of equally named attributes). | 9 |
|
||||||
| Less Than | *e1* `<` *e2*, | none | Arithmetic comparison. | 10 |
|
| Less Than | *e1* `<` *e2*, | none | Arithmetic/lexicographic comparison. | 10 |
|
||||||
| Less Than or Equal To | *e1* `<=` *e2* | none | Arithmetic comparison. | 10 |
|
| Less Than or Equal To | *e1* `<=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
|
||||||
| Greater Than | *e1* `>` *e2* | none | Arithmetic comparison. | 10 |
|
| Greater Than | *e1* `>` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
|
||||||
| Greater Than or Equal To | *e1* `>=` *e2* | none | Arithmetic comparison. | 10 |
|
| Greater Than or Equal To | *e1* `>=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
|
||||||
| Equality | *e1* `==` *e2* | none | Equality. | 11 |
|
| Equality | *e1* `==` *e2* | none | Equality. | 11 |
|
||||||
| Inequality | *e1* `!=` *e2* | none | Inequality. | 11 |
|
| Inequality | *e1* `!=` *e2* | none | Inequality. | 11 |
|
||||||
| Logical AND | *e1* `&&` *e2* | left | Logical AND. | 12 |
|
| Logical AND | *e1* `&&` *e2* | left | Logical AND. | 12 |
|
||||||
| Logical OR | *e1* `\|\|` *e2* | left | Logical OR. | 13 |
|
| Logical OR | *e1* <code>||</code> *e2* | left | Logical OR. | 13 |
|
||||||
| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to `!e1 \|\| e2`). | 14 |
|
| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to <code>!e1 || e2</code>). | 14 |
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ Nix has the following basic data types:
|
||||||
the start of each line. To be precise, it strips from each line a
|
the start of each line. To be precise, it strips from each line a
|
||||||
number of spaces equal to the minimal indentation of the string as a
|
number of spaces equal to the minimal indentation of the string as a
|
||||||
whole (disregarding the indentation of empty lines). For instance,
|
whole (disregarding the indentation of empty lines). For instance,
|
||||||
the first and second line are indented two space, while the third
|
the first and second line are indented two spaces, while the third
|
||||||
line is indented four spaces. Thus, two spaces are stripped from
|
line is indented four spaces. Thus, two spaces are stripped from
|
||||||
each line, so the resulting string is
|
each line, so the resulting string is
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Building and Testing
|
# Building and Testing
|
||||||
|
|
||||||
You can now try to build Hello. Of course, you could do `nix-env -i
|
You can now try to build Hello. Of course, you could do `nix-env -f . -iA
|
||||||
hello`, but you may not want to install a possibly broken package just
|
hello`, but you may not want to install a possibly broken package just
|
||||||
yet. The best way to test the package is by using the command
|
yet. The best way to test the package is by using the command
|
||||||
`nix-build`, which builds a Nix expression and creates a symlink named
|
`nix-build`, which builds a Nix expression and creates a symlink named
|
||||||
|
|
|
||||||
59
doc/manual/src/installation/installing-docker.md
Normal file
59
doc/manual/src/installation/installing-docker.md
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
# Using Nix within Docker
|
||||||
|
|
||||||
|
To run the latest stable release of Nix with Docker run the following command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker -ti run nixos/nix
|
||||||
|
Unable to find image 'nixos/nix:latest' locally
|
||||||
|
latest: Pulling from nixos/nix
|
||||||
|
5843afab3874: Pull complete
|
||||||
|
b52bf13f109c: Pull complete
|
||||||
|
1e2415612aa3: Pull complete
|
||||||
|
Digest: sha256:27f6e7f60227e959ee7ece361f75d4844a40e1cc6878b6868fe30140420031ff
|
||||||
|
Status: Downloaded newer image for nixos/nix:latest
|
||||||
|
35ca4ada6e96:/# nix --version
|
||||||
|
nix (Nix) 2.3.12
|
||||||
|
35ca4ada6e96:/# exit
|
||||||
|
```
|
||||||
|
|
||||||
|
# What is included in Nix' Docker image?
|
||||||
|
|
||||||
|
The official Docker image is created using `pkgs.dockerTools.buildLayeredImage`
|
||||||
|
(and not with `Dockerfile` as it is usual with Docker images). You can still
|
||||||
|
base your custom Docker image on it as you would do with any other Docker
|
||||||
|
image.
|
||||||
|
|
||||||
|
The Docker image is also not based on any other image and includes minimal set
|
||||||
|
of runtime dependencies that are required to use Nix:
|
||||||
|
|
||||||
|
- pkgs.nix
|
||||||
|
- pkgs.bashInteractive
|
||||||
|
- pkgs.coreutils-full
|
||||||
|
- pkgs.gnutar
|
||||||
|
- pkgs.gzip
|
||||||
|
- pkgs.gnugrep
|
||||||
|
- pkgs.which
|
||||||
|
- pkgs.curl
|
||||||
|
- pkgs.less
|
||||||
|
- pkgs.wget
|
||||||
|
- pkgs.man
|
||||||
|
- pkgs.cacert.out
|
||||||
|
- pkgs.findutils
|
||||||
|
|
||||||
|
# Docker image with the latest development version of Nix
|
||||||
|
|
||||||
|
To get the latest image that was built by [Hydra](https://hydra.nixos.org) run
|
||||||
|
the following command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ curl -L https://hydra.nixos.org/job/nix/master/dockerImage.x86_64-linux/latest/download/1 | docker load
|
||||||
|
$ docker run -ti nix:2.5pre20211105
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also build a Docker image from source yourself:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ nix build ./\#hydraJobs.dockerImage.x86_64-linux
|
||||||
|
$ docker load -i ./result
|
||||||
|
$ docker run -ti nix:2.5pre20211105
|
||||||
|
```
|
||||||
|
|
@ -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 some-packages
|
$ nix-env --upgrade -A nixpkgs.some-package
|
||||||
$ nix-env --rollback
|
$ nix-env --rollback
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -122,12 +122,12 @@ 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 firefox
|
$ nix-env --install -A 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
|
||||||
also all its dependencies (all the way up to the C library and the
|
also all its dependencies (all the way up to the C library and the
|
||||||
compiler) would have to built, at least if they are not already in the
|
compiler) would have to be built, at least if they are not already in the
|
||||||
Nix store. This is a _source deployment model_. For most users,
|
Nix store. This is a _source deployment model_. For most users,
|
||||||
building from source is not very pleasant as it takes far too long.
|
building from source is not very pleasant as it takes far too long.
|
||||||
However, Nix can automatically skip building from source and instead
|
However, Nix can automatically skip building from source and instead
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ collection; you could write your own Nix expressions based on Nixpkgs,
|
||||||
or completely new ones.)
|
or completely new ones.)
|
||||||
|
|
||||||
You can manually download the latest version of Nixpkgs from
|
You can manually download the latest version of Nixpkgs from
|
||||||
<http://nixos.org/nixpkgs/download.html>. However, it’s much more
|
<https://github.com/NixOS/nixpkgs>. However, it’s much more
|
||||||
convenient to use the Nixpkgs [*channel*](channels.md), since it makes
|
convenient to use the Nixpkgs [*channel*](channels.md), since it makes
|
||||||
it easy to stay up to date with new versions of Nixpkgs. Nixpkgs is
|
it easy to stay up to date with new versions of Nixpkgs. Nixpkgs is
|
||||||
automatically added to your list of “subscribed” channels when you
|
automatically added to your list of “subscribed” channels when you
|
||||||
|
|
@ -47,41 +47,45 @@ $ 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 -qa
|
$ nix-env -qaP
|
||||||
aterm-2.2
|
nixpkgs.aterm aterm-2.2
|
||||||
bash-3.0
|
nixpkgs.bash bash-3.0
|
||||||
binutils-2.15
|
nixpkgs.binutils binutils-2.15
|
||||||
bison-1.875d
|
nixpkgs.bison bison-1.875d
|
||||||
blackdown-1.4.2
|
nixpkgs.blackdown blackdown-1.4.2
|
||||||
bzip2-1.0.2
|
nixpkgs.bzip2 bzip2-1.0.2
|
||||||
…
|
…
|
||||||
```
|
```
|
||||||
|
|
||||||
The flag `-q` specifies a query operation, and `-a` means that you want
|
The flag `-q` specifies a query operation, `-a` means that you want
|
||||||
to show the “available” (i.e., installable) packages, as opposed to the
|
to show the “available” (i.e., installable) packages, as opposed to the
|
||||||
installed packages. If you downloaded Nixpkgs yourself, or if you
|
installed packages, and `-P` prints the attribute paths that can be used
|
||||||
checked it out from GitHub, then you need to pass the path to your
|
to unambiguously select a package for installation (listed in the first column).
|
||||||
Nixpkgs tree using the `-f` flag:
|
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:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qaf /path/to/nixpkgs
|
$ nix-env -qaPf /path/to/nixpkgs
|
||||||
|
aterm aterm-2.2
|
||||||
|
bash bash-3.0
|
||||||
|
…
|
||||||
```
|
```
|
||||||
|
|
||||||
where */path/to/nixpkgs* is where you’ve unpacked or checked out
|
where */path/to/nixpkgs* is where you’ve unpacked or checked out
|
||||||
Nixpkgs.
|
Nixpkgs.
|
||||||
|
|
||||||
You can select specific packages by name:
|
You can filter the packages by name:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa firefox
|
$ nix-env -qaP firefox
|
||||||
firefox-34.0.5
|
nixpkgs.firefox-esr firefox-91.3.0esr
|
||||||
firefox-with-plugins-34.0.5
|
nixpkgs.firefox firefox-94.0.1
|
||||||
```
|
```
|
||||||
|
|
||||||
and using regular expressions:
|
and using regular expressions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa 'firefox.*'
|
$ nix-env -qaP '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.,
|
||||||
|
|
@ -89,11 +93,11 @@ whether they are installed into the user environment and/or present in
|
||||||
the system:
|
the system:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qas
|
$ nix-env -qaPs
|
||||||
…
|
…
|
||||||
-PS bash-3.0
|
-PS nixpkgs.bash bash-3.0
|
||||||
--S binutils-2.15
|
--S nixpkgs.binutils binutils-2.15
|
||||||
IPS bison-1.875d
|
IPS nixpkgs.bison bison-1.875d
|
||||||
…
|
…
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -106,13 +110,13 @@ 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 -i`. For instance,
|
You can install a package using `nix-env -iA`. For instance,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i subversion
|
$ nix-env -iA nixpkgs.subversion
|
||||||
```
|
```
|
||||||
|
|
||||||
will install the package called `subversion` (which is, of course, the
|
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
|
||||||
[Subversion version management system](http://subversion.tigris.org/)).
|
[Subversion version management system](http://subversion.tigris.org/)).
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
|
|
@ -122,7 +126,7 @@ will install the package called `subversion` (which is, of course, the
|
||||||
> binary cache <https://cache.nixos.org>; it contains binaries for most
|
> binary cache <https://cache.nixos.org>; it contains binaries for most
|
||||||
> packages in Nixpkgs. Only if no binary is available in the binary
|
> packages in Nixpkgs. Only if no binary is available in the binary
|
||||||
> cache, Nix will build the package from source. So if `nix-env
|
> cache, Nix will build the package from source. So if `nix-env
|
||||||
> -i subversion` results in Nix building stuff from source, then either
|
> -iA nixpkgs.subversion` results in Nix building stuff from source, then either
|
||||||
> the package is not built for your platform by the Nixpkgs build
|
> the package is not built for your platform by the Nixpkgs build
|
||||||
> servers, or your version of Nixpkgs is too old or too new. For
|
> servers, or your version of Nixpkgs is too old or too new. For
|
||||||
> instance, if you have a very recent checkout of Nixpkgs, then the
|
> instance, if you have a very recent checkout of Nixpkgs, then the
|
||||||
|
|
@ -133,7 +137,10 @@ will install the package called `subversion` (which is, of course, the
|
||||||
> using a Git checkout of the Nixpkgs tree), you will get binaries for
|
> using a Git checkout of the Nixpkgs tree), you will get binaries for
|
||||||
> most packages.
|
> most packages.
|
||||||
|
|
||||||
Naturally, packages can also be uninstalled:
|
Naturally, packages can also be uninstalled. Unlike when installing, you will
|
||||||
|
need to use the derivation name (though the version part can be omitted),
|
||||||
|
instead of the attribute path, as `nix-env` does not record which attribute
|
||||||
|
was used for installing:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -e subversion
|
$ nix-env -e subversion
|
||||||
|
|
@ -143,7 +150,7 @@ 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 -u subversion
|
$ nix-env -uA 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
|
||||||
|
|
|
||||||
|
|
@ -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 -i nix-serve
|
$ nix-env -iA 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
|
||||||
`--option extra-binary-caches`, e.g.:
|
`--option extra-binary-caches`, e.g.:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i firefox --option extra-binary-caches http://avalon:8080/
|
$ nix-env -iA nixpkgs.firefox --option extra-binary-caches http://avalon:8080/
|
||||||
```
|
```
|
||||||
|
|
||||||
The option `extra-binary-caches` tells Nix to use this binary cache in
|
The option `extra-binary-caches` tells Nix to use this binary cache in
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ collector as follows:
|
||||||
$ nix-store --gc
|
$ nix-store --gc
|
||||||
```
|
```
|
||||||
|
|
||||||
The behaviour of the gargage collector is affected by the
|
The behaviour of the garbage collector is affected by the
|
||||||
`keep-derivations` (default: true) and `keep-outputs` (default: false)
|
`keep-derivations` (default: true) and `keep-outputs` (default: false)
|
||||||
options in the Nix configuration file. The defaults will ensure that all
|
options in the Nix configuration file. The defaults will ensure that all
|
||||||
derivations that are build-time dependencies of garbage collector roots
|
derivations that are build-time dependencies of garbage collector roots
|
||||||
|
|
|
||||||
|
|
@ -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 -i subversion
|
$ nix-env -iA 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 -i subversion firefox
|
$ nix-env -iA 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 -i subversion
|
$ nix-env -p /nix/var/nix/profiles/other-profile -iA 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 -i firefox --substituters ssh://alice@avalon
|
$ nix-env -iA 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
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,19 @@ to subsequent chapters.
|
||||||
channel:
|
channel:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -qa
|
$ nix-env -qaP
|
||||||
docbook-xml-4.3
|
nixpkgs.docbook_xml_dtd_43 docbook-xml-4.3
|
||||||
docbook-xml-4.5
|
nixpkgs.docbook_xml_dtd_45 docbook-xml-4.5
|
||||||
firefox-33.0.2
|
nixpkgs.firefox firefox-33.0.2
|
||||||
hello-2.9
|
nixpkgs.hello hello-2.9
|
||||||
libxslt-1.1.28
|
nixpkgs.libxslt libxslt-1.1.28
|
||||||
…
|
…
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Install some packages from the channel:
|
1. Install some packages from the channel:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-env -i hello
|
$ nix-env -iA nixpkgs.hello
|
||||||
```
|
```
|
||||||
|
|
||||||
This should download pre-built packages; it should not build them
|
This should download pre-built packages; it should not build them
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,5 @@
|
||||||
* Binary cache stores now have a setting `compression-level`.
|
* Binary cache stores now have a setting `compression-level`.
|
||||||
|
|
||||||
* `nix develop` now has a flag `--unpack` to run `unpackPhase`.
|
* `nix develop` now has a flag `--unpack` to run `unpackPhase`.
|
||||||
|
|
||||||
|
* Lists can now be compared lexicographically using the `<` operator.
|
||||||
|
|
|
||||||
251
docker.nix
Normal file
251
docker.nix
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { }
|
||||||
|
, lib ? pkgs.lib
|
||||||
|
, name ? "nix"
|
||||||
|
, tag ? "latest"
|
||||||
|
, channelName ? "nixpkgs"
|
||||||
|
, channelURL ? "https://nixos.org/channels/nixpkgs-unstable"
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
defaultPkgs = with pkgs; [
|
||||||
|
nix
|
||||||
|
bashInteractive
|
||||||
|
coreutils-full
|
||||||
|
gnutar
|
||||||
|
gzip
|
||||||
|
gnugrep
|
||||||
|
which
|
||||||
|
curl
|
||||||
|
less
|
||||||
|
wget
|
||||||
|
man
|
||||||
|
cacert.out
|
||||||
|
findutils
|
||||||
|
];
|
||||||
|
|
||||||
|
users = {
|
||||||
|
|
||||||
|
root = {
|
||||||
|
uid = 0;
|
||||||
|
shell = "/bin/bash";
|
||||||
|
home = "/root";
|
||||||
|
gid = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // lib.listToAttrs (
|
||||||
|
map
|
||||||
|
(
|
||||||
|
n: {
|
||||||
|
name = "nixbld${toString n}";
|
||||||
|
value = {
|
||||||
|
uid = 30000 + n;
|
||||||
|
gid = 30000;
|
||||||
|
groups = [ "nixbld" ];
|
||||||
|
description = "Nix build user ${toString n}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
(lib.lists.range 1 32)
|
||||||
|
);
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
root.gid = 0;
|
||||||
|
nixbld.gid = 30000;
|
||||||
|
};
|
||||||
|
|
||||||
|
userToPasswd = (
|
||||||
|
k:
|
||||||
|
{ uid
|
||||||
|
, gid ? 65534
|
||||||
|
, home ? "/var/empty"
|
||||||
|
, description ? ""
|
||||||
|
, shell ? "/bin/false"
|
||||||
|
, groups ? [ ]
|
||||||
|
}: "${k}:x:${toString uid}:${toString gid}:${description}:${home}:${shell}"
|
||||||
|
);
|
||||||
|
passwdContents = (
|
||||||
|
lib.concatStringsSep "\n"
|
||||||
|
(lib.attrValues (lib.mapAttrs userToPasswd users))
|
||||||
|
);
|
||||||
|
|
||||||
|
userToShadow = k: { ... }: "${k}:!:1::::::";
|
||||||
|
shadowContents = (
|
||||||
|
lib.concatStringsSep "\n"
|
||||||
|
(lib.attrValues (lib.mapAttrs userToShadow users))
|
||||||
|
);
|
||||||
|
|
||||||
|
# Map groups to members
|
||||||
|
# {
|
||||||
|
# group = [ "user1" "user2" ];
|
||||||
|
# }
|
||||||
|
groupMemberMap = (
|
||||||
|
let
|
||||||
|
# Create a flat list of user/group mappings
|
||||||
|
mappings = (
|
||||||
|
builtins.foldl'
|
||||||
|
(
|
||||||
|
acc: user:
|
||||||
|
let
|
||||||
|
groups = users.${user}.groups or [ ];
|
||||||
|
in
|
||||||
|
acc ++ map
|
||||||
|
(group: {
|
||||||
|
inherit user group;
|
||||||
|
})
|
||||||
|
groups
|
||||||
|
)
|
||||||
|
[ ]
|
||||||
|
(lib.attrNames users)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
(
|
||||||
|
builtins.foldl'
|
||||||
|
(
|
||||||
|
acc: v: acc // {
|
||||||
|
${v.group} = acc.${v.group} or [ ] ++ [ v.user ];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ }
|
||||||
|
mappings)
|
||||||
|
);
|
||||||
|
|
||||||
|
groupToGroup = k: { gid }:
|
||||||
|
let
|
||||||
|
members = groupMemberMap.${k} or [ ];
|
||||||
|
in
|
||||||
|
"${k}:x:${toString gid}:${lib.concatStringsSep "," members}";
|
||||||
|
groupContents = (
|
||||||
|
lib.concatStringsSep "\n"
|
||||||
|
(lib.attrValues (lib.mapAttrs groupToGroup groups))
|
||||||
|
);
|
||||||
|
|
||||||
|
nixConf = {
|
||||||
|
sandbox = "false";
|
||||||
|
build-users-group = "nixbld";
|
||||||
|
trusted-public-keys = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=";
|
||||||
|
};
|
||||||
|
nixConfContents = (lib.concatStringsSep "\n" (lib.mapAttrsFlatten (n: v: "${n} = ${v}") nixConf)) + "\n";
|
||||||
|
|
||||||
|
baseSystem =
|
||||||
|
let
|
||||||
|
nixpkgs = pkgs.path;
|
||||||
|
channel = pkgs.runCommand "channel-nixos" { } ''
|
||||||
|
mkdir $out
|
||||||
|
ln -s ${nixpkgs} $out/nixpkgs
|
||||||
|
echo "[]" > $out/manifest.nix
|
||||||
|
'';
|
||||||
|
rootEnv = pkgs.buildPackages.buildEnv {
|
||||||
|
name = "root-profile-env";
|
||||||
|
paths = defaultPkgs;
|
||||||
|
};
|
||||||
|
profile = pkgs.buildPackages.runCommand "user-environment" { } ''
|
||||||
|
mkdir $out
|
||||||
|
cp -a ${rootEnv}/* $out/
|
||||||
|
|
||||||
|
cat > $out/manifest.nix <<EOF
|
||||||
|
[
|
||||||
|
${lib.concatStringsSep "\n" (builtins.map (drv: let
|
||||||
|
outputs = drv.outputsToInstall or [ "out" ];
|
||||||
|
in ''
|
||||||
|
{
|
||||||
|
${lib.concatStringsSep "\n" (builtins.map (output: ''
|
||||||
|
${output} = { outPath = "${lib.getOutput output drv}"; };
|
||||||
|
'') outputs)}
|
||||||
|
outputs = [ ${lib.concatStringsSep " " (builtins.map (x: "\"${x}\"") outputs)} ];
|
||||||
|
name = "${drv.name}";
|
||||||
|
outPath = "${drv}";
|
||||||
|
system = "${drv.system}";
|
||||||
|
type = "derivation";
|
||||||
|
meta = { };
|
||||||
|
}
|
||||||
|
'') defaultPkgs)}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
pkgs.runCommand "base-system"
|
||||||
|
{
|
||||||
|
inherit passwdContents groupContents shadowContents nixConfContents;
|
||||||
|
passAsFile = [
|
||||||
|
"passwdContents"
|
||||||
|
"groupContents"
|
||||||
|
"shadowContents"
|
||||||
|
"nixConfContents"
|
||||||
|
];
|
||||||
|
allowSubstitutes = false;
|
||||||
|
preferLocalBuild = true;
|
||||||
|
} ''
|
||||||
|
env
|
||||||
|
set -x
|
||||||
|
mkdir -p $out/etc
|
||||||
|
|
||||||
|
cat $passwdContentsPath > $out/etc/passwd
|
||||||
|
echo "" >> $out/etc/passwd
|
||||||
|
|
||||||
|
cat $groupContentsPath > $out/etc/group
|
||||||
|
echo "" >> $out/etc/group
|
||||||
|
|
||||||
|
cat $shadowContentsPath > $out/etc/shadow
|
||||||
|
echo "" >> $out/etc/shadow
|
||||||
|
|
||||||
|
mkdir -p $out/usr
|
||||||
|
ln -s /nix/var/nix/profiles/share $out/usr/
|
||||||
|
|
||||||
|
mkdir -p $out/nix/var/nix/gcroots
|
||||||
|
|
||||||
|
mkdir $out/tmp
|
||||||
|
|
||||||
|
mkdir -p $out/etc/nix
|
||||||
|
cat $nixConfContentsPath > $out/etc/nix/nix.conf
|
||||||
|
|
||||||
|
mkdir -p $out/root
|
||||||
|
mkdir -p $out/nix/var/nix/profiles/per-user/root
|
||||||
|
|
||||||
|
ln -s ${profile} $out/nix/var/nix/profiles/default-1-link
|
||||||
|
ln -s $out/nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default
|
||||||
|
ln -s /nix/var/nix/profiles/default $out/root/.nix-profile
|
||||||
|
|
||||||
|
ln -s ${channel} $out/nix/var/nix/profiles/per-user/root/channels-1-link
|
||||||
|
ln -s $out/nix/var/nix/profiles/per-user/root/channels-1-link $out/nix/var/nix/profiles/per-user/root/channels
|
||||||
|
|
||||||
|
mkdir -p $out/root/.nix-defexpr
|
||||||
|
ln -s $out/nix/var/nix/profiles/per-user/root/channels $out/root/.nix-defexpr/channels
|
||||||
|
echo "${channelURL} ${channelName}" > $out/root/.nix-channels
|
||||||
|
|
||||||
|
mkdir -p $out/bin $out/usr/bin
|
||||||
|
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
||||||
|
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
||||||
|
'';
|
||||||
|
|
||||||
|
in
|
||||||
|
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
|
||||||
|
inherit name tag;
|
||||||
|
|
||||||
|
contents = [ baseSystem ];
|
||||||
|
|
||||||
|
extraCommands = ''
|
||||||
|
rm -rf nix-support
|
||||||
|
ln -s /nix/var/nix/profiles nix/var/nix/gcroots/profiles
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = {
|
||||||
|
Cmd = [ "/root/.nix-profile/bin/bash" ];
|
||||||
|
Env = [
|
||||||
|
"USER=root"
|
||||||
|
"PATH=${lib.concatStringsSep ":" [
|
||||||
|
"/root/.nix-profile/bin"
|
||||||
|
"/nix/var/nix/profiles/default/bin"
|
||||||
|
"/nix/var/nix/profiles/default/sbin"
|
||||||
|
]}"
|
||||||
|
"MANPATH=${lib.concatStringsSep ":" [
|
||||||
|
"/root/.nix-profile/share/man"
|
||||||
|
"/nix/var/nix/profiles/default/share/man"
|
||||||
|
]}"
|
||||||
|
"SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
"GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
"NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||||
|
"NIX_PATH=/nix/var/nix/profiles/per-user/root/channels:/root/.nix-defexpr/channels"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
18
flake.nix
18
flake.nix
|
|
@ -91,7 +91,7 @@
|
||||||
libarchive
|
libarchive
|
||||||
boost
|
boost
|
||||||
lowdown-nix
|
lowdown-nix
|
||||||
gmock
|
gtest
|
||||||
]
|
]
|
||||||
++ lib.optionals stdenv.isLinux [libseccomp]
|
++ lib.optionals stdenv.isLinux [libseccomp]
|
||||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
||||||
|
|
@ -405,6 +405,21 @@
|
||||||
installerScript = installScriptFor [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" "armv6l-linux" "armv7l-linux" ];
|
installerScript = installScriptFor [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" "armv6l-linux" "armv7l-linux" ];
|
||||||
installerScriptForGHA = installScriptFor [ "x86_64-linux" "x86_64-darwin" "armv6l-linux" "armv7l-linux"];
|
installerScriptForGHA = installScriptFor [ "x86_64-linux" "x86_64-darwin" "armv6l-linux" "armv7l-linux"];
|
||||||
|
|
||||||
|
# docker image with Nix inside
|
||||||
|
dockerImage = nixpkgs.lib.genAttrs linux64BitSystems (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
image = import ./docker.nix { inherit pkgs; tag = version; };
|
||||||
|
in pkgs.runCommand "docker-image-tarball-${version}"
|
||||||
|
{ meta.description = "Docker image with Nix for ${system}";
|
||||||
|
}
|
||||||
|
''
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
image=$out/image.tar.gz
|
||||||
|
ln -s ${image} $image
|
||||||
|
echo "file binary-dist $image" >> $out/nix-support/hydra-build-products
|
||||||
|
'');
|
||||||
|
|
||||||
# Line coverage analysis.
|
# Line coverage analysis.
|
||||||
coverage =
|
coverage =
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.x86_64-linux;
|
||||||
|
|
@ -509,6 +524,7 @@
|
||||||
binaryTarball = self.hydraJobs.binaryTarball.${system};
|
binaryTarball = self.hydraJobs.binaryTarball.${system};
|
||||||
perlBindings = self.hydraJobs.perlBindings.${system};
|
perlBindings = self.hydraJobs.perlBindings.${system};
|
||||||
installTests = self.hydraJobs.installTests.${system};
|
installTests = self.hydraJobs.installTests.${system};
|
||||||
|
dockerImage = self.hydraJobs.dockerImage.${system};
|
||||||
});
|
});
|
||||||
|
|
||||||
packages = forAllSystems (system: {
|
packages = forAllSystems (system: {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package Nix::Config;
|
package Nix::Config;
|
||||||
|
|
||||||
use MIME::Base64;
|
use MIME::Base64;
|
||||||
|
use Nix::Store;
|
||||||
|
|
||||||
$version = "@PACKAGE_VERSION@";
|
$version = "@PACKAGE_VERSION@";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -742,6 +742,9 @@ setup_volume() {
|
||||||
|
|
||||||
use_special="${NIX_VOLUME_USE_SPECIAL:-$(create_volume)}"
|
use_special="${NIX_VOLUME_USE_SPECIAL:-$(create_volume)}"
|
||||||
|
|
||||||
|
_sudo "to ensure the Nix volume is not mounted" \
|
||||||
|
/usr/sbin/diskutil unmount force "$use_special" || true # might not be mounted
|
||||||
|
|
||||||
use_uuid=${NIX_VOLUME_USE_UUID:-$(volume_uuid_from_special "$use_special")}
|
use_uuid=${NIX_VOLUME_USE_UUID:-$(volume_uuid_from_special "$use_special")}
|
||||||
|
|
||||||
setup_fstab "$use_uuid"
|
setup_fstab "$use_uuid"
|
||||||
|
|
|
||||||
|
|
@ -387,19 +387,28 @@ EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
for profile_target in "${PROFILE_TARGETS[@]}"; do
|
||||||
|
# TODO: I think it would be good to accumulate a list of all
|
||||||
|
# of the copies so that people don't hit this 2 or 3x in
|
||||||
|
# a row for different files.
|
||||||
if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
|
if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then
|
||||||
|
# this backup process first released in Nix 2.1
|
||||||
failure <<EOF
|
failure <<EOF
|
||||||
When this script runs, it backs up the current $profile_target to
|
I back up shell profile/rc scripts before I add Nix to them.
|
||||||
$profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though.
|
I need to back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX,
|
||||||
|
but the latter already exists.
|
||||||
|
|
||||||
Please follow these instructions to clean up the old backup file:
|
Here's how to clean up the old backup file:
|
||||||
|
|
||||||
1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just
|
1. Back up (copy) $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX
|
||||||
in case.
|
to another location, just in case.
|
||||||
|
|
||||||
2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like
|
2. Ensure $profile_target$PROFILE_BACKUP_SUFFIX does not have anything
|
||||||
it has anything nix-related in it. If it does, something is probably
|
Nix-related in it. If it does, something is probably quite
|
||||||
quite wrong. Please open an issue or get in touch immediately.
|
wrong. Please open an issue or get in touch immediately.
|
||||||
|
|
||||||
|
3. Once you confirm $profile_target is backed up and
|
||||||
|
$profile_target$PROFILE_BACKUP_SUFFIX doesn't mention Nix, run:
|
||||||
|
mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
@ -599,7 +608,7 @@ manager. This will happen in a few stages:
|
||||||
1. Make sure your computer doesn't already have Nix. If it does, I
|
1. Make sure your computer doesn't already have Nix. If it does, I
|
||||||
will show you instructions on how to clean up your old install.
|
will show you instructions on how to clean up your old install.
|
||||||
|
|
||||||
2. Show you what we are going to install and where. Then we will ask
|
2. Show you what I am going to install and where. Then I will ask
|
||||||
if you are ready to continue.
|
if you are ready to continue.
|
||||||
|
|
||||||
3. Create the system users and groups that the Nix daemon uses to run
|
3. Create the system users and groups that the Nix daemon uses to run
|
||||||
|
|
@ -614,14 +623,14 @@ manager. This will happen in a few stages:
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if ui_confirm "Would you like to see a more detailed list of what we will do?"; then
|
if ui_confirm "Would you like to see a more detailed list of what I will do?"; then
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
We will:
|
I will:
|
||||||
|
|
||||||
- make sure your computer doesn't already have Nix files
|
- make sure your computer doesn't already have Nix files
|
||||||
(if it does, I will tell you how to clean them up.)
|
(if it does, I will tell you how to clean them up.)
|
||||||
- create local users (see the list above for the users we'll make)
|
- create local users (see the list above for the users I'll make)
|
||||||
- create a local group ($NIX_BUILD_GROUP_NAME)
|
- create a local group ($NIX_BUILD_GROUP_NAME)
|
||||||
- install Nix in to $NIX_ROOT
|
- install Nix in to $NIX_ROOT
|
||||||
- create a configuration file in /etc/nix
|
- create a configuration file in /etc/nix
|
||||||
|
|
@ -656,7 +665,7 @@ run in a headless fashion, like this:
|
||||||
|
|
||||||
$ curl -L https://nixos.org/nix/install | sh
|
$ curl -L https://nixos.org/nix/install | sh
|
||||||
|
|
||||||
or maybe in a CI pipeline. Because of that, we're going to skip the
|
or maybe in a CI pipeline. Because of that, I'm going to skip the
|
||||||
verbose output in the interest of brevity.
|
verbose output in the interest of brevity.
|
||||||
|
|
||||||
If you would like to
|
If you would like to
|
||||||
|
|
@ -670,7 +679,7 @@ EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
This script is going to call sudo a lot. Every time we do, it'll
|
This script is going to call sudo a lot. Every time I do, it'll
|
||||||
output exactly what it'll do, and why.
|
output exactly what it'll do, and why.
|
||||||
|
|
||||||
Just like this:
|
Just like this:
|
||||||
|
|
@ -682,15 +691,15 @@ EOF
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
This might look scary, but everything can be undone by running just a
|
This might look scary, but everything can be undone by running just a
|
||||||
few commands. We used to ask you to confirm each time sudo ran, but it
|
few commands. I used to ask you to confirm each time sudo ran, but it
|
||||||
was too many times. Instead, I'll just ask you this one time:
|
was too many times. Instead, I'll just ask you this one time:
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
if ui_confirm "Can we use sudo?"; then
|
if ui_confirm "Can I use sudo?"; then
|
||||||
ok "Yay! Thanks! Let's get going!"
|
ok "Yay! Thanks! Let's get going!"
|
||||||
else
|
else
|
||||||
failure <<EOF
|
failure <<EOF
|
||||||
That is okay, but we can't install.
|
That is okay, but I can't install.
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -809,10 +818,10 @@ main() {
|
||||||
# can fail faster in this case. Sourcing install-darwin... now runs
|
# can fail faster in this case. Sourcing install-darwin... now runs
|
||||||
# `touch /` to detect Read-only root, but it could update times on
|
# `touch /` to detect Read-only root, but it could update times on
|
||||||
# pre-Catalina macOS if run as root user.
|
# pre-Catalina macOS if run as root user.
|
||||||
if [ $EUID -eq 0 ]; then
|
if [ "$EUID" -eq 0 ]; then
|
||||||
failure <<EOF
|
failure <<EOF
|
||||||
Please do not run this script with root privileges. We will call sudo
|
Please do not run this script with root privileges. I will call sudo
|
||||||
when we need to.
|
when I need to.
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ fi
|
||||||
|
|
||||||
echo "performing a single-user installation of Nix..." >&2
|
echo "performing a single-user installation of Nix..." >&2
|
||||||
|
|
||||||
if ! [ -e $dest ]; then
|
if ! [ -e "$dest" ]; then
|
||||||
cmd="mkdir -m 0755 $dest && chown $USER $dest"
|
cmd="mkdir -m 0755 $dest && chown $USER $dest"
|
||||||
echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2
|
echo "directory $dest does not exist; creating it by running '$cmd' using sudo" >&2
|
||||||
if ! sudo sh -c "$cmd"; then
|
if ! sudo sh -c "$cmd"; then
|
||||||
|
|
@ -143,12 +143,12 @@ if ! [ -e $dest ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -w $dest ]; then
|
if ! [ -w "$dest" ]; then
|
||||||
echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see https://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2
|
echo "$0: directory $dest exists, but is not writable by you. This could indicate that another user has already performed a single-user installation of Nix on this system. If you wish to enable multi-user support see https://nixos.org/nix/manual/#ssec-multi-user. If you wish to continue with a single-user install for $USER please run 'chown -R $USER $dest' as root." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $dest/store
|
mkdir -p "$dest/store"
|
||||||
|
|
||||||
printf "copying Nix to %s..." "${dest}/store" >&2
|
printf "copying Nix to %s..." "${dest}/store" >&2
|
||||||
# Insert a newline if no progress is shown.
|
# Insert a newline if no progress is shown.
|
||||||
|
|
@ -189,17 +189,17 @@ fi
|
||||||
|
|
||||||
# Install an SSL certificate bundle.
|
# Install an SSL certificate bundle.
|
||||||
if [ -z "$NIX_SSL_CERT_FILE" ] || ! [ -f "$NIX_SSL_CERT_FILE" ]; then
|
if [ -z "$NIX_SSL_CERT_FILE" ] || ! [ -f "$NIX_SSL_CERT_FILE" ]; then
|
||||||
$nix/bin/nix-env -i "$cacert"
|
"$nix/bin/nix-env" -i "$cacert"
|
||||||
export NIX_SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
|
export NIX_SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Subscribe the user to the Nixpkgs channel and fetch it.
|
# Subscribe the user to the Nixpkgs channel and fetch it.
|
||||||
if [ -z "$NIX_INSTALLER_NO_CHANNEL_ADD" ]; then
|
if [ -z "$NIX_INSTALLER_NO_CHANNEL_ADD" ]; then
|
||||||
if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
|
if ! "$nix/bin/nix-channel" --list | grep -q "^nixpkgs "; then
|
||||||
$nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
"$nix/bin/nix-channel" --add https://nixos.org/channels/nixpkgs-unstable
|
||||||
fi
|
fi
|
||||||
if [ -z "$_NIX_INSTALLER_TEST" ]; then
|
if [ -z "$_NIX_INSTALLER_TEST" ]; then
|
||||||
if ! $nix/bin/nix-channel --update nixpkgs; then
|
if ! "$nix/bin/nix-channel" --update nixpkgs; then
|
||||||
echo "Fetching the nixpkgs channel failed. (Are you offline?)"
|
echo "Fetching the nixpkgs channel failed. (Are you offline?)"
|
||||||
echo "To try again later, run \"nix-channel --update nixpkgs\"."
|
echo "To try again later, run \"nix-channel --update nixpkgs\"."
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ readonly SERVICE_OVERRIDE=${SERVICE_DEST}.d/override.conf
|
||||||
|
|
||||||
create_systemd_override() {
|
create_systemd_override() {
|
||||||
header "Configuring proxy for the nix-daemon service"
|
header "Configuring proxy for the nix-daemon service"
|
||||||
_sudo "create directory for systemd unit override" mkdir -p "$(dirname $SERVICE_OVERRIDE)"
|
_sudo "create directory for systemd unit override" mkdir -p "$(dirname "$SERVICE_OVERRIDE")"
|
||||||
cat <<EOF | _sudo "create systemd unit override" tee "$SERVICE_OVERRIDE"
|
cat <<EOF | _sudo "create systemd unit override" tee "$SERVICE_OVERRIDE"
|
||||||
[Service]
|
[Service]
|
||||||
$1
|
$1
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,10 @@ if [ "$(uname -s)" != "Darwin" ]; then
|
||||||
require_util xz "unpack the binary tarball"
|
require_util xz "unpack the binary tarball"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if command -v wget > /dev/null 2>&1; then
|
if command -v curl > /dev/null 2>&1; then
|
||||||
fetch() { wget "$1" -O "$2"; }
|
|
||||||
elif command -v curl > /dev/null 2>&1; then
|
|
||||||
fetch() { curl -L "$1" -o "$2"; }
|
fetch() { curl -L "$1" -o "$2"; }
|
||||||
|
elif command -v wget > /dev/null 2>&1; then
|
||||||
|
fetch() { wget "$1" -O "$2"; }
|
||||||
else
|
else
|
||||||
oops "you don't have wget or curl installed, which I need to download the binary tarball"
|
oops "you don't have wget or curl installed, which I need to download the binary tarball"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
nix_noinst_scripts := \
|
nix_noinst_scripts := \
|
||||||
$(d)/nix-http-export.cgi \
|
$(d)/nix-profile.sh
|
||||||
$(d)/nix-profile.sh \
|
|
||||||
$(d)/nix-reduce-build
|
|
||||||
|
|
||||||
noinst-scripts += $(nix_noinst_scripts)
|
noinst-scripts += $(nix_noinst_scripts)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
export HOME=/tmp
|
|
||||||
export NIX_REMOTE=daemon
|
|
||||||
|
|
||||||
TMP_DIR="${TMP_DIR:-/tmp/nix-export}"
|
|
||||||
|
|
||||||
@coreutils@/mkdir -p "$TMP_DIR" || true
|
|
||||||
@coreutils@/chmod a+r "$TMP_DIR"
|
|
||||||
|
|
||||||
needed_path="?$QUERY_STRING"
|
|
||||||
needed_path="${needed_path#*[?&]needed_path=}"
|
|
||||||
needed_path="${needed_path%%&*}"
|
|
||||||
#needed_path="$(echo $needed_path | ./unhttp)"
|
|
||||||
needed_path="${needed_path//%2B/+}"
|
|
||||||
needed_path="${needed_path//%3D/=}"
|
|
||||||
|
|
||||||
echo needed_path: "$needed_path" >&2
|
|
||||||
|
|
||||||
NIX_STORE="${NIX_STORE_DIR:-/nix/store}"
|
|
||||||
|
|
||||||
echo NIX_STORE: "${NIX_STORE}" >&2
|
|
||||||
|
|
||||||
full_path="${NIX_STORE}"/"$needed_path"
|
|
||||||
|
|
||||||
if [ "$needed_path" != "${needed_path%.drv}" ]; then
|
|
||||||
echo "Status: 403 You should create the derivation file yourself"
|
|
||||||
echo "Content-Type: text/plain"
|
|
||||||
echo
|
|
||||||
echo "Refusing to disclose derivation contents"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if @bindir@/nix-store --check-validity "$full_path"; then
|
|
||||||
if ! [ -e nix-export/"$needed_path".nar.gz ]; then
|
|
||||||
@bindir@/nix-store --export "$full_path" | @gzip@ > "$TMP_DIR"/"$needed_path".nar.gz
|
|
||||||
@coreutils@/ln -fs "$TMP_DIR"/"$needed_path".nar.gz nix-export/"$needed_path".nar.gz
|
|
||||||
fi;
|
|
||||||
echo "Status: 301 Moved"
|
|
||||||
echo "Location: nix-export/"$needed_path".nar.gz"
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
echo "Status: 404 No such path found"
|
|
||||||
echo "Content-Type: text/plain"
|
|
||||||
echo
|
|
||||||
echo "Path not found:"
|
|
||||||
echo "$needed_path"
|
|
||||||
echo "checked:"
|
|
||||||
echo "$full_path"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ __ETC_PROFILE_NIX_SOURCED=1
|
||||||
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||||
|
|
||||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||||
if [ ! -z "${NIX_SSL_CERT_FILE:-}" ]; then
|
if [ -n "${NIX_SSL_CERT_FILE:-}" ]; then
|
||||||
: # Allow users to override the NIX_SSL_CERT_FILE
|
: # Allow users to override the NIX_SSL_CERT_FILE
|
||||||
elif [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
elif [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
||||||
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
@ -18,14 +18,14 @@ elif [ -e /etc/pki/tls/certs/ca-bundle.crt ]; then # Fedora, CentOS
|
||||||
else
|
else
|
||||||
# Fall back to what is in the nix profiles, favouring whatever is defined last.
|
# Fall back to what is in the nix profiles, favouring whatever is defined last.
|
||||||
check_nix_profiles() {
|
check_nix_profiles() {
|
||||||
if [ "$ZSH_VERSION" ]; then
|
if [ -n "$ZSH_VERSION" ]; then
|
||||||
# Zsh by default doesn't split words in unquoted parameter expansion.
|
# Zsh by default doesn't split words in unquoted parameter expansion.
|
||||||
# Set local_options for these options to be reverted at the end of the function
|
# Set local_options for these options to be reverted at the end of the function
|
||||||
# and shwordsplit to force splitting words in $NIX_PROFILES below.
|
# and shwordsplit to force splitting words in $NIX_PROFILES below.
|
||||||
setopt local_options shwordsplit
|
setopt local_options shwordsplit
|
||||||
fi
|
fi
|
||||||
for i in $NIX_PROFILES; do
|
for i in $NIX_PROFILES; do
|
||||||
if [ -e $i/etc/ssl/certs/ca-bundle.crt ]; then
|
if [ -e "$i/etc/ssl/certs/ca-bundle.crt" ]; then
|
||||||
export NIX_SSL_CERT_FILE=$i/etc/ssl/certs/ca-bundle.crt
|
export NIX_SSL_CERT_FILE=$i/etc/ssl/certs/ca-bundle.crt
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -1,171 +0,0 @@
|
||||||
#! @bash@
|
|
||||||
|
|
||||||
WORKING_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}"/nix-reduce-build-XXXXXX);
|
|
||||||
cd "$WORKING_DIRECTORY";
|
|
||||||
|
|
||||||
if test -z "$1" || test "a--help" = "a$1" ; then
|
|
||||||
echo 'nix-reduce-build (paths or Nix expressions) -- (package sources)' >&2
|
|
||||||
echo As in: >&2
|
|
||||||
echo nix-reduce-build /etc/nixos/nixos -- ssh://user@somewhere.nowhere.example.org >&2
|
|
||||||
echo nix-reduce-build /etc/nixos/nixos -- \\
|
|
||||||
echo " " \''http://somewhere.nowhere.example.org/nix/nix-http-export.cgi?needed_path='\' >&2
|
|
||||||
echo " store path name will be added into the end of the URL" >&2
|
|
||||||
echo nix-reduce-build /etc/nixos/nixos -- file://home/user/nar/ >&2
|
|
||||||
echo " that should be a directory where gzipped 'nix-store --export' ">&2
|
|
||||||
echo " files are located (they should have .nar.gz extension)" >&2
|
|
||||||
echo " Or all together: " >&2
|
|
||||||
echo -e nix-reduce-build /expr.nix /e2.nix -- \\\\\\\n\
|
|
||||||
" ssh://a@b.example.com http://n.example.com/get-nar?q= file://nar/" >&2
|
|
||||||
echo " Also supports best-effort local builds of failing expression set:" >&2
|
|
||||||
echo "nix-reduce-build /e.nix -- nix-daemon:// nix-self://" >&2
|
|
||||||
echo " nix-daemon:// builds using daemon"
|
|
||||||
echo " nix-self:// builds directly using nix-store from current installation" >&2
|
|
||||||
echo " nix-daemon-fixed:// and nix-self-fixed:// do the same, but only for" >&2;
|
|
||||||
echo "derivations with specified output hash (sha256, sha1 or md5)." >&2
|
|
||||||
echo " nix-daemon-substitute:// and nix-self-substitute:// try to substitute" >&2;
|
|
||||||
echo "maximum amount of paths" >&2;
|
|
||||||
echo " nix-daemon-build:// and nix-self-build:// try to build (not substitute)" >&2;
|
|
||||||
echo "maximum amount of paths" >&2;
|
|
||||||
echo " If no package sources are specified, required paths are listed." >&2;
|
|
||||||
exit;
|
|
||||||
fi;
|
|
||||||
|
|
||||||
while ! test "$1" = "--" || test "$1" = "" ; do
|
|
||||||
echo "$1" >> initial; >&2
|
|
||||||
shift;
|
|
||||||
done
|
|
||||||
shift;
|
|
||||||
echo Will work on $(cat initial | wc -l) targets. >&2
|
|
||||||
|
|
||||||
while read ; do
|
|
||||||
case "$REPLY" in
|
|
||||||
${NIX_STORE_DIR:-/nix/store}/*)
|
|
||||||
echo "$REPLY" >> paths; >&2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
(
|
|
||||||
IFS=: ;
|
|
||||||
nix-instantiate $REPLY >> paths;
|
|
||||||
);
|
|
||||||
;;
|
|
||||||
esac;
|
|
||||||
done < initial;
|
|
||||||
echo Proceeding $(cat paths | wc -l) paths. >&2
|
|
||||||
|
|
||||||
while read; do
|
|
||||||
case "$REPLY" in
|
|
||||||
*.drv)
|
|
||||||
echo "$REPLY" >> derivers; >&2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
nix-store --query --deriver "$REPLY" >>derivers;
|
|
||||||
;;
|
|
||||||
esac;
|
|
||||||
done < paths;
|
|
||||||
echo Found $(cat derivers | wc -l) derivers. >&2
|
|
||||||
|
|
||||||
cat derivers | xargs nix-store --query -R > derivers-closure;
|
|
||||||
echo Proceeding at most $(cat derivers-closure | wc -l) derivers. >&2
|
|
||||||
|
|
||||||
cat derivers-closure | egrep '[.]drv$' | xargs nix-store --query --outputs > wanted-paths;
|
|
||||||
cat derivers-closure | egrep -v '[.]drv$' >> wanted-paths;
|
|
||||||
echo Prepared $(cat wanted-paths | wc -l) paths to get. >&2
|
|
||||||
|
|
||||||
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
|
|
||||||
echo We need $(cat needed-paths | wc -l) paths. >&2
|
|
||||||
|
|
||||||
egrep '[.]drv$' derivers-closure > critical-derivers;
|
|
||||||
|
|
||||||
if test -z "$1" ; then
|
|
||||||
cat needed-paths;
|
|
||||||
fi;
|
|
||||||
|
|
||||||
refresh_critical_derivers() {
|
|
||||||
echo "Finding needed derivers..." >&2;
|
|
||||||
cat critical-derivers | while read; do
|
|
||||||
if ! (nix-store --query --outputs "$REPLY" | xargs nix-store --check-validity &> /dev/null;); then
|
|
||||||
echo "$REPLY";
|
|
||||||
fi;
|
|
||||||
done > new-critical-derivers;
|
|
||||||
mv new-critical-derivers critical-derivers;
|
|
||||||
echo The needed paths are realized by $(cat critical-derivers | wc -l) derivers. >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
build_here() {
|
|
||||||
cat critical-derivers | while read; do
|
|
||||||
echo "Realising $REPLY using nix-daemon" >&2
|
|
||||||
@bindir@/nix-store -r "${REPLY}"
|
|
||||||
done;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_to_substitute(){
|
|
||||||
cat needed-paths | while read ; do
|
|
||||||
echo "Building $REPLY using nix-daemon" >&2
|
|
||||||
@bindir@/nix-store -r "${NIX_STORE_DIR:-/nix/store}/${REPLY##*/}"
|
|
||||||
done;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in "$@"; do
|
|
||||||
sshHost="${i#ssh://}";
|
|
||||||
httpHost="${i#http://}";
|
|
||||||
httpsHost="${i#https://}";
|
|
||||||
filePath="${i#file:/}";
|
|
||||||
if [ "$i" != "$sshHost" ]; then
|
|
||||||
cat needed-paths | while read; do
|
|
||||||
echo "Getting $REPLY and its closure over ssh" >&2
|
|
||||||
nix-copy-closure --from "$sshHost" --gzip "$REPLY" </dev/null || true;
|
|
||||||
done;
|
|
||||||
elif [ "$i" != "$httpHost" ] || [ "$i" != "$httpsHost" ]; then
|
|
||||||
cat needed-paths | while read; do
|
|
||||||
echo "Getting $REPLY over http/https" >&2
|
|
||||||
curl ${BAD_CERTIFICATE:+-k} -L "$i${REPLY##*/}" | gunzip | nix-store --import;
|
|
||||||
done;
|
|
||||||
elif [ "$i" != "$filePath" ] ; then
|
|
||||||
cat needed-paths | while read; do
|
|
||||||
echo "Installing $REPLY from file" >&2
|
|
||||||
gunzip < "$filePath/${REPLY##*/}".nar.gz | nix-store --import;
|
|
||||||
done;
|
|
||||||
elif [ "$i" = "nix-daemon://" ] ; then
|
|
||||||
NIX_REMOTE=daemon try_to_substitute;
|
|
||||||
refresh_critical_derivers;
|
|
||||||
NIX_REMOTE=daemon build_here;
|
|
||||||
elif [ "$i" = "nix-self://" ] ; then
|
|
||||||
NIX_REMOTE= try_to_substitute;
|
|
||||||
refresh_critical_derivers;
|
|
||||||
NIX_REMOTE= build_here;
|
|
||||||
elif [ "$i" = "nix-daemon-fixed://" ] ; then
|
|
||||||
refresh_critical_derivers;
|
|
||||||
|
|
||||||
cat critical-derivers | while read; do
|
|
||||||
if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then
|
|
||||||
echo "Realising $REPLY using nix-daemon" >&2
|
|
||||||
NIX_REMOTE=daemon @bindir@/nix-store -r "${REPLY}"
|
|
||||||
fi;
|
|
||||||
done;
|
|
||||||
elif [ "$i" = "nix-self-fixed://" ] ; then
|
|
||||||
refresh_critical_derivers;
|
|
||||||
|
|
||||||
cat critical-derivers | while read; do
|
|
||||||
if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then
|
|
||||||
echo "Realising $REPLY using direct Nix build" >&2
|
|
||||||
NIX_REMOTE= @bindir@/nix-store -r "${REPLY}"
|
|
||||||
fi;
|
|
||||||
done;
|
|
||||||
elif [ "$i" = "nix-daemon-substitute://" ] ; then
|
|
||||||
NIX_REMOTE=daemon try_to_substitute;
|
|
||||||
elif [ "$i" = "nix-self-substitute://" ] ; then
|
|
||||||
NIX_REMOTE= try_to_substitute;
|
|
||||||
elif [ "$i" = "nix-daemon-build://" ] ; then
|
|
||||||
refresh_critical_derivers;
|
|
||||||
NIX_REMOTE=daemon build_here;
|
|
||||||
elif [ "$i" = "nix-self-build://" ] ; then
|
|
||||||
refresh_critical_derivers;
|
|
||||||
NIX_REMOTE= build_here;
|
|
||||||
fi;
|
|
||||||
mv needed-paths wanted-paths;
|
|
||||||
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
|
|
||||||
echo We still need $(cat needed-paths | wc -l) paths. >&2
|
|
||||||
done;
|
|
||||||
|
|
||||||
cd /
|
|
||||||
rm -r "$WORKING_DIRECTORY"
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
script=$(nix-build -A outputs.hydraJobs.installerScriptForGHA --no-out-link)
|
script=$(nix-build -A outputs.hydraJobs.installerScriptForGHA --no-out-link)
|
||||||
installerHash=$(echo $script | cut -b12-43 -)
|
installerHash=$(echo "$script" | cut -b12-43 -)
|
||||||
|
|
||||||
installerURL=https://$CACHIX_NAME.cachix.org/serve/$installerHash/install
|
installerURL=https://$CACHIX_NAME.cachix.org/serve/$installerHash/install
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -520,7 +520,7 @@ Path EvalState::checkSourcePath(const Path & path_)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", abspath);
|
throw RestrictedPathError("access to absolute path '%1%' is forbidden in restricted mode", abspath);
|
||||||
|
|
||||||
/* Resolve symlinks. */
|
/* Resolve symlinks. */
|
||||||
debug(format("checking access to '%s'") % abspath);
|
debug(format("checking access to '%s'") % abspath);
|
||||||
|
|
@ -533,7 +533,7 @@ Path EvalState::checkSourcePath(const Path & path_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path);
|
throw RestrictedPathError("access to canonical path '%1%' is forbidden in restricted mode", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -583,14 +583,20 @@ Value * EvalState::addConstant(const string & name, Value & v)
|
||||||
{
|
{
|
||||||
Value * v2 = allocValue();
|
Value * v2 = allocValue();
|
||||||
*v2 = v;
|
*v2 = v;
|
||||||
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
addConstant(name, v2);
|
||||||
baseEnv.values[baseEnvDispl++] = v2;
|
|
||||||
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v2));
|
|
||||||
return v2;
|
return v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::addConstant(const string & name, Value * v)
|
||||||
|
{
|
||||||
|
staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||||
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
|
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
||||||
|
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * EvalState::addPrimOp(const string & name,
|
Value * EvalState::addPrimOp(const string & name,
|
||||||
size_t arity, PrimOpFun primOp)
|
size_t arity, PrimOpFun primOp)
|
||||||
{
|
{
|
||||||
|
|
@ -609,7 +615,7 @@ Value * EvalState::addPrimOp(const string & name,
|
||||||
|
|
||||||
Value * v = allocValue();
|
Value * v = allocValue();
|
||||||
v->mkPrimOp(new PrimOp { .fun = primOp, .arity = arity, .name = sym });
|
v->mkPrimOp(new PrimOp { .fun = primOp, .arity = arity, .name = sym });
|
||||||
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl);
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
|
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
|
||||||
return v;
|
return v;
|
||||||
|
|
@ -635,7 +641,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||||
|
|
||||||
Value * v = allocValue();
|
Value * v = allocValue();
|
||||||
v->mkPrimOp(new PrimOp(std::move(primOp)));
|
v->mkPrimOp(new PrimOp(std::move(primOp)));
|
||||||
staticBaseEnv.vars[envName] = baseEnvDispl;
|
staticBaseEnv.vars.emplace_back(envName, baseEnvDispl);
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(primOp.name, v));
|
baseEnv.values[0]->attrs->push_back(Attr(primOp.name, v));
|
||||||
return v;
|
return v;
|
||||||
|
|
@ -785,7 +791,7 @@ void mkPath(Value & v, const char * s)
|
||||||
|
|
||||||
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||||
{
|
{
|
||||||
for (size_t l = var.level; l; --l, env = env->up) ;
|
for (auto l = var.level; l; --l, env = env->up) ;
|
||||||
|
|
||||||
if (!var.fromWith) return env->values[var.displ];
|
if (!var.fromWith) return env->values[var.displ];
|
||||||
|
|
||||||
|
|
@ -1058,7 +1064,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
/* The recursive attributes are evaluated in the new
|
/* The recursive attributes are evaluated in the new
|
||||||
environment, while the inherited attributes are evaluated
|
environment, while the inherited attributes are evaluated
|
||||||
in the original environment. */
|
in the original environment. */
|
||||||
size_t displ = 0;
|
Displacement displ = 0;
|
||||||
for (auto & i : attrs) {
|
for (auto & i : attrs) {
|
||||||
Value * vAttr;
|
Value * vAttr;
|
||||||
if (hasOverrides && !i.second.inherited) {
|
if (hasOverrides && !i.second.inherited) {
|
||||||
|
|
@ -1134,7 +1140,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||||
/* The recursive attributes are evaluated in the new environment,
|
/* The recursive attributes are evaluated in the new environment,
|
||||||
while the inherited attributes are evaluated in the original
|
while the inherited attributes are evaluated in the original
|
||||||
environment. */
|
environment. */
|
||||||
size_t displ = 0;
|
Displacement displ = 0;
|
||||||
for (auto & i : attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
env2.values[displ++] = i.second.e->maybeThunk(state, i.second.inherited ? env : env2);
|
||||||
|
|
||||||
|
|
@ -1251,144 +1257,184 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprApp::eval(EvalState & state, Env & env, Value & v)
|
void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos)
|
||||||
{
|
|
||||||
/* FIXME: vFun prevents GCC from doing tail call optimisation. */
|
|
||||||
Value vFun;
|
|
||||||
e1->eval(state, env, vFun);
|
|
||||||
state.callFunction(vFun, *(e2->maybeThunk(state, env)), v, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
|
|
||||||
{
|
|
||||||
/* Figure out the number of arguments still needed. */
|
|
||||||
size_t argsDone = 0;
|
|
||||||
Value * primOp = &fun;
|
|
||||||
while (primOp->isPrimOpApp()) {
|
|
||||||
argsDone++;
|
|
||||||
primOp = primOp->primOpApp.left;
|
|
||||||
}
|
|
||||||
assert(primOp->isPrimOp());
|
|
||||||
auto arity = primOp->primOp->arity;
|
|
||||||
auto argsLeft = arity - argsDone;
|
|
||||||
|
|
||||||
if (argsLeft == 1) {
|
|
||||||
/* We have all the arguments, so call the primop. */
|
|
||||||
|
|
||||||
/* Put all the arguments in an array. */
|
|
||||||
Value * vArgs[arity];
|
|
||||||
auto n = arity - 1;
|
|
||||||
vArgs[n--] = &arg;
|
|
||||||
for (Value * arg = &fun; arg->isPrimOpApp(); arg = arg->primOpApp.left)
|
|
||||||
vArgs[n--] = arg->primOpApp.right;
|
|
||||||
|
|
||||||
/* And call the primop. */
|
|
||||||
nrPrimOpCalls++;
|
|
||||||
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
|
||||||
primOp->primOp->fun(*this, pos, vArgs, v);
|
|
||||||
} else {
|
|
||||||
Value * fun2 = allocValue();
|
|
||||||
*fun2 = fun;
|
|
||||||
v.mkPrimOpApp(fun2, &arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
|
|
||||||
{
|
{
|
||||||
auto trace = evalSettings.traceFunctionCalls ? std::make_unique<FunctionCallTrace>(pos) : nullptr;
|
auto trace = evalSettings.traceFunctionCalls ? std::make_unique<FunctionCallTrace>(pos) : nullptr;
|
||||||
|
|
||||||
forceValue(fun, pos);
|
forceValue(fun, pos);
|
||||||
|
|
||||||
if (fun.isPrimOp() || fun.isPrimOpApp()) {
|
Value vCur(fun);
|
||||||
callPrimOp(fun, arg, v, pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fun.type() == nAttrs) {
|
auto makeAppChain = [&]()
|
||||||
auto found = fun.attrs->find(sFunctor);
|
{
|
||||||
if (found != fun.attrs->end()) {
|
vRes = vCur;
|
||||||
/* fun may be allocated on the stack of the calling function,
|
for (size_t i = 0; i < nrArgs; ++i) {
|
||||||
* but for functors we may keep a reference, so heap-allocate
|
auto fun2 = allocValue();
|
||||||
* a copy and use that instead.
|
*fun2 = vRes;
|
||||||
*/
|
vRes.mkPrimOpApp(fun2, args[i]);
|
||||||
auto & fun2 = *allocValue();
|
}
|
||||||
fun2 = fun;
|
};
|
||||||
/* !!! Should we use the attr pos here? */
|
|
||||||
Value v2;
|
|
||||||
callFunction(*found->value, fun2, v2, pos);
|
|
||||||
return callFunction(v2, arg, v, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fun.isLambda())
|
Attr * functor;
|
||||||
throwTypeError(pos, "attempt to call something which is not a function but %1%", fun);
|
|
||||||
|
|
||||||
ExprLambda & lambda(*fun.lambda.fun);
|
while (nrArgs > 0) {
|
||||||
|
|
||||||
auto size =
|
if (vCur.isLambda()) {
|
||||||
(lambda.arg.empty() ? 0 : 1) +
|
|
||||||
(lambda.hasFormals() ? lambda.formals->formals.size() : 0);
|
|
||||||
Env & env2(allocEnv(size));
|
|
||||||
env2.up = fun.lambda.env;
|
|
||||||
|
|
||||||
size_t displ = 0;
|
ExprLambda & lambda(*vCur.lambda.fun);
|
||||||
|
|
||||||
if (!lambda.hasFormals())
|
auto size =
|
||||||
env2.values[displ++] = &arg;
|
(lambda.arg.empty() ? 0 : 1) +
|
||||||
|
(lambda.hasFormals() ? lambda.formals->formals.size() : 0);
|
||||||
|
Env & env2(allocEnv(size));
|
||||||
|
env2.up = vCur.lambda.env;
|
||||||
|
|
||||||
else {
|
Displacement displ = 0;
|
||||||
forceAttrs(arg, pos);
|
|
||||||
|
|
||||||
if (!lambda.arg.empty())
|
if (!lambda.hasFormals())
|
||||||
env2.values[displ++] = &arg;
|
env2.values[displ++] = args[0];
|
||||||
|
|
||||||
/* For each formal argument, get the actual argument. If
|
else {
|
||||||
there is no matching actual argument but the formal
|
forceAttrs(*args[0], pos);
|
||||||
argument has a default, use the default. */
|
|
||||||
size_t attrsUsed = 0;
|
if (!lambda.arg.empty())
|
||||||
for (auto & i : lambda.formals->formals) {
|
env2.values[displ++] = args[0];
|
||||||
Bindings::iterator j = arg.attrs->find(i.name);
|
|
||||||
if (j == arg.attrs->end()) {
|
/* For each formal argument, get the actual argument. If
|
||||||
if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'",
|
there is no matching actual argument but the formal
|
||||||
lambda, i.name);
|
argument has a default, use the default. */
|
||||||
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
size_t attrsUsed = 0;
|
||||||
|
for (auto & i : lambda.formals->formals) {
|
||||||
|
auto j = args[0]->attrs->get(i.name);
|
||||||
|
if (!j) {
|
||||||
|
if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'",
|
||||||
|
lambda, i.name);
|
||||||
|
env2.values[displ++] = i.def->maybeThunk(*this, env2);
|
||||||
|
} else {
|
||||||
|
attrsUsed++;
|
||||||
|
env2.values[displ++] = j->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that each actual argument is listed as a formal
|
||||||
|
argument (unless the attribute match specifies a `...'). */
|
||||||
|
if (!lambda.formals->ellipsis && attrsUsed != args[0]->attrs->size()) {
|
||||||
|
/* Nope, so show the first unexpected argument to the
|
||||||
|
user. */
|
||||||
|
for (auto & i : *args[0]->attrs)
|
||||||
|
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
|
||||||
|
throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name);
|
||||||
|
abort(); // can't happen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nrFunctionCalls++;
|
||||||
|
if (countCalls) incrFunctionCall(&lambda);
|
||||||
|
|
||||||
|
/* Evaluate the body. */
|
||||||
|
try {
|
||||||
|
lambda.body->eval(*this, env2, vCur);
|
||||||
|
} catch (Error & e) {
|
||||||
|
if (loggerSettings.showTrace.get()) {
|
||||||
|
addErrorTrace(e, lambda.pos, "while evaluating %s",
|
||||||
|
(lambda.name.set()
|
||||||
|
? "'" + (string) lambda.name + "'"
|
||||||
|
: "anonymous lambda"));
|
||||||
|
addErrorTrace(e, pos, "from call site%s", "");
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
nrArgs--;
|
||||||
|
args += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (vCur.isPrimOp()) {
|
||||||
|
|
||||||
|
size_t argsLeft = vCur.primOp->arity;
|
||||||
|
|
||||||
|
if (nrArgs < argsLeft) {
|
||||||
|
/* We don't have enough arguments, so create a tPrimOpApp chain. */
|
||||||
|
makeAppChain();
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
/* We have all the arguments, so call the primop. */
|
||||||
env2.values[displ++] = j->value;
|
nrPrimOpCalls++;
|
||||||
|
if (countCalls) primOpCalls[vCur.primOp->name]++;
|
||||||
|
vCur.primOp->fun(*this, pos, args, vCur);
|
||||||
|
|
||||||
|
nrArgs -= argsLeft;
|
||||||
|
args += argsLeft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that each actual argument is listed as a formal
|
else if (vCur.isPrimOpApp()) {
|
||||||
argument (unless the attribute match specifies a `...'). */
|
/* Figure out the number of arguments still needed. */
|
||||||
if (!lambda.formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
size_t argsDone = 0;
|
||||||
/* Nope, so show the first unexpected argument to the
|
Value * primOp = &vCur;
|
||||||
user. */
|
while (primOp->isPrimOpApp()) {
|
||||||
for (auto & i : *arg.attrs)
|
argsDone++;
|
||||||
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
|
primOp = primOp->primOpApp.left;
|
||||||
throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name);
|
}
|
||||||
abort(); // can't happen
|
assert(primOp->isPrimOp());
|
||||||
|
auto arity = primOp->primOp->arity;
|
||||||
|
auto argsLeft = arity - argsDone;
|
||||||
|
|
||||||
|
if (nrArgs < argsLeft) {
|
||||||
|
/* We still don't have enough arguments, so extend the tPrimOpApp chain. */
|
||||||
|
makeAppChain();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* We have all the arguments, so call the primop with
|
||||||
|
the previous and new arguments. */
|
||||||
|
|
||||||
|
Value * vArgs[arity];
|
||||||
|
auto n = argsDone;
|
||||||
|
for (Value * arg = &vCur; arg->isPrimOpApp(); arg = arg->primOpApp.left)
|
||||||
|
vArgs[--n] = arg->primOpApp.right;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < argsLeft; ++i)
|
||||||
|
vArgs[argsDone + i] = args[i];
|
||||||
|
|
||||||
|
nrPrimOpCalls++;
|
||||||
|
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
||||||
|
primOp->primOp->fun(*this, pos, vArgs, vCur);
|
||||||
|
|
||||||
|
nrArgs -= argsLeft;
|
||||||
|
args += argsLeft;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (vCur.type() == nAttrs && (functor = vCur.attrs->get(sFunctor))) {
|
||||||
|
/* 'vCur' may be allocated on the stack of the calling
|
||||||
|
function, but for functors we may keep a reference, so
|
||||||
|
heap-allocate a copy and use that instead. */
|
||||||
|
Value * args2[] = {allocValue(), args[0]};
|
||||||
|
*args2[0] = vCur;
|
||||||
|
/* !!! Should we use the attr pos here? */
|
||||||
|
callFunction(*functor->value, 2, args2, vCur, pos);
|
||||||
|
nrArgs--;
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
throwTypeError(pos, "attempt to call something which is not a function but %1%", vCur);
|
||||||
}
|
}
|
||||||
|
|
||||||
nrFunctionCalls++;
|
vRes = vCur;
|
||||||
if (countCalls) incrFunctionCall(&lambda);
|
}
|
||||||
|
|
||||||
/* Evaluate the body. This is conditional on showTrace, because
|
|
||||||
catching exceptions makes this function not tail-recursive. */
|
void ExprCall::eval(EvalState & state, Env & env, Value & v)
|
||||||
if (loggerSettings.showTrace.get())
|
{
|
||||||
try {
|
Value vFun;
|
||||||
lambda.body->eval(*this, env2, v);
|
fun->eval(state, env, vFun);
|
||||||
} catch (Error & e) {
|
|
||||||
addErrorTrace(e, lambda.pos, "while evaluating %s",
|
Value * vArgs[args.size()];
|
||||||
(lambda.name.set()
|
for (size_t i = 0; i < args.size(); ++i)
|
||||||
? "'" + (string) lambda.name + "'"
|
vArgs[i] = args[i]->maybeThunk(state, env);
|
||||||
: "anonymous lambda"));
|
|
||||||
addErrorTrace(e, pos, "from call site%s", "");
|
state.callFunction(vFun, args.size(), vArgs, v, pos);
|
||||||
throw;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fun.lambda.fun->body->eval(*this, env2, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,8 @@ private:
|
||||||
|
|
||||||
Value * addConstant(const string & name, Value & v);
|
Value * addConstant(const string & name, Value & v);
|
||||||
|
|
||||||
|
void addConstant(const string & name, Value * v);
|
||||||
|
|
||||||
Value * addPrimOp(const string & name,
|
Value * addPrimOp(const string & name,
|
||||||
size_t arity, PrimOpFun primOp);
|
size_t arity, PrimOpFun primOp);
|
||||||
|
|
||||||
|
|
@ -316,8 +318,14 @@ public:
|
||||||
|
|
||||||
bool isFunctor(Value & fun);
|
bool isFunctor(Value & fun);
|
||||||
|
|
||||||
void callFunction(Value & fun, Value & arg, Value & v, const Pos & pos);
|
// FIXME: use std::span
|
||||||
void callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos);
|
void callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const Pos & pos);
|
||||||
|
|
||||||
|
void callFunction(Value & fun, Value & arg, Value & vRes, const Pos & pos)
|
||||||
|
{
|
||||||
|
Value * args[] = {&arg};
|
||||||
|
callFunction(fun, 1, args, vRes, pos);
|
||||||
|
}
|
||||||
|
|
||||||
/* Automatically call a function for which each argument has a
|
/* Automatically call a function for which each argument has a
|
||||||
default value or has a binding in the `args' map. */
|
default value or has a binding in the `args' map. */
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "flake.hh"
|
#include "flake.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
|
@ -52,21 +53,19 @@ void ConfigFile::apply()
|
||||||
auto trustedList = readTrustedList();
|
auto trustedList = readTrustedList();
|
||||||
|
|
||||||
bool trusted = false;
|
bool trusted = false;
|
||||||
|
if (nix::settings.acceptFlakeConfig){
|
||||||
if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
|
trusted = true;
|
||||||
|
} else if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
|
||||||
trusted = *saved;
|
trusted = *saved;
|
||||||
|
warn("Using saved setting for '%s = %s' from ~/.local/share/nix/trusted-settings.json.", name,valueS);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: filter ANSI escapes, newlines, \r, etc.
|
// FIXME: filter ANSI escapes, newlines, \r, etc.
|
||||||
if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) != 'y') {
|
if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) == 'y') {
|
||||||
if (std::tolower(logger->ask("do you want to permanently mark this value as untrusted (y/N)?").value_or('n')) == 'y') {
|
trusted = true;
|
||||||
trustedList[name][valueS] = false;
|
}
|
||||||
writeTrustedList(trustedList);
|
if (std::tolower(logger->ask(fmt("do you want to permanently mark this value as %s (y/N)?", trusted ? "trusted": "untrusted" )).value_or('n')) == 'y') {
|
||||||
}
|
trustedList[name][valueS] = trusted;
|
||||||
} else {
|
writeTrustedList(trustedList);
|
||||||
if (std::tolower(logger->ask("do you want to permanently mark this value as trusted (y/N)?").value_or('n')) == 'y') {
|
|
||||||
trustedList[name][valueS] = trusted = true;
|
|
||||||
writeTrustedList(trustedList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ LockedFlake lockFlake(
|
||||||
|
|
||||||
if (lockFlags.applyNixConfig) {
|
if (lockFlags.applyNixConfig) {
|
||||||
flake.config.apply();
|
flake.config.apply();
|
||||||
// FIXME: send new config to the daemon.
|
state.store->setOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -448,22 +448,18 @@ LockedFlake lockFlake(
|
||||||
update it. */
|
update it. */
|
||||||
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
|
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
|
||||||
|
|
||||||
auto hasChildUpdate =
|
auto mustRefetch =
|
||||||
lb != lockFlags.inputUpdates.end()
|
lb != lockFlags.inputUpdates.end()
|
||||||
&& lb->size() > inputPath.size()
|
&& lb->size() > inputPath.size()
|
||||||
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin());
|
&& std::equal(inputPath.begin(), inputPath.end(), lb->begin());
|
||||||
|
|
||||||
if (hasChildUpdate) {
|
FlakeInputs fakeInputs;
|
||||||
auto inputFlake = getFlake(
|
|
||||||
state, oldLock->lockedRef, false, flakeCache);
|
if (!mustRefetch) {
|
||||||
computeLocks(inputFlake.inputs, childNode, inputPath, oldLock, parent, parentPath);
|
|
||||||
} else {
|
|
||||||
/* No need to fetch this flake, we can be
|
/* No need to fetch this flake, we can be
|
||||||
lazy. However there may be new overrides on the
|
lazy. However there may be new overrides on the
|
||||||
inputs of this flake, so we need to check
|
inputs of this flake, so we need to check
|
||||||
those. */
|
those. */
|
||||||
FlakeInputs fakeInputs;
|
|
||||||
|
|
||||||
for (auto & i : oldLock->inputs) {
|
for (auto & i : oldLock->inputs) {
|
||||||
if (auto lockedNode = std::get_if<0>(&i.second)) {
|
if (auto lockedNode = std::get_if<0>(&i.second)) {
|
||||||
fakeInputs.emplace(i.first, FlakeInput {
|
fakeInputs.emplace(i.first, FlakeInput {
|
||||||
|
|
@ -471,15 +467,28 @@ LockedFlake lockFlake(
|
||||||
.isFlake = (*lockedNode)->isFlake,
|
.isFlake = (*lockedNode)->isFlake,
|
||||||
});
|
});
|
||||||
} else if (auto follows = std::get_if<1>(&i.second)) {
|
} else if (auto follows = std::get_if<1>(&i.second)) {
|
||||||
|
auto o = input.overrides.find(i.first);
|
||||||
|
// If the override disappeared, we have to refetch the flake,
|
||||||
|
// since some of the inputs may not be present in the lockfile.
|
||||||
|
if (o == input.overrides.end()) {
|
||||||
|
mustRefetch = true;
|
||||||
|
// There's no point populating the rest of the fake inputs,
|
||||||
|
// since we'll refetch the flake anyways.
|
||||||
|
break;
|
||||||
|
}
|
||||||
fakeInputs.emplace(i.first, FlakeInput {
|
fakeInputs.emplace(i.first, FlakeInput {
|
||||||
.follows = *follows,
|
.follows = *follows,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
computeLocks(fakeInputs, childNode, inputPath, oldLock, parent, parentPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeLocks(
|
||||||
|
mustRefetch
|
||||||
|
? getFlake(state, oldLock->lockedRef, false, flakeCache).inputs
|
||||||
|
: fakeInputs,
|
||||||
|
childNode, inputPath, oldLock, parent, parentPath);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We need to create a new lock file entry. So fetch
|
/* We need to create a new lock file entry. So fetch
|
||||||
this input. */
|
this input. */
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: optimize
|
||||||
static Expr * unescapeStr(SymbolTable & symbols, const char * s, size_t length)
|
static Expr * unescapeStr(SymbolTable & symbols, const char * s, size_t length)
|
||||||
{
|
{
|
||||||
string t;
|
string t;
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,16 @@ void ExprLambda::show(std::ostream & str) const
|
||||||
str << ": " << *body << ")";
|
str << ": " << *body << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExprCall::show(std::ostream & str) const
|
||||||
|
{
|
||||||
|
str << '(' << *fun;
|
||||||
|
for (auto e : args) {
|
||||||
|
str << ' ';
|
||||||
|
str << *e;
|
||||||
|
}
|
||||||
|
str << ')';
|
||||||
|
}
|
||||||
|
|
||||||
void ExprLet::show(std::ostream & str) const
|
void ExprLet::show(std::ostream & str) const
|
||||||
{
|
{
|
||||||
str << "(let ";
|
str << "(let ";
|
||||||
|
|
@ -263,13 +273,13 @@ void ExprVar::bindVars(const StaticEnv & env)
|
||||||
/* Check whether the variable appears in the environment. If so,
|
/* Check whether the variable appears in the environment. If so,
|
||||||
set its level and displacement. */
|
set its level and displacement. */
|
||||||
const StaticEnv * curEnv;
|
const StaticEnv * curEnv;
|
||||||
unsigned int level;
|
Level level;
|
||||||
int withLevel = -1;
|
int withLevel = -1;
|
||||||
for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) {
|
for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) {
|
||||||
if (curEnv->isWith) {
|
if (curEnv->isWith) {
|
||||||
if (withLevel == -1) withLevel = level;
|
if (withLevel == -1) withLevel = level;
|
||||||
} else {
|
} else {
|
||||||
StaticEnv::Vars::const_iterator i = curEnv->vars.find(name);
|
auto i = curEnv->find(name);
|
||||||
if (i != curEnv->vars.end()) {
|
if (i != curEnv->vars.end()) {
|
||||||
fromWith = false;
|
fromWith = false;
|
||||||
this->level = level;
|
this->level = level;
|
||||||
|
|
@ -311,14 +321,16 @@ void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
||||||
void ExprAttrs::bindVars(const StaticEnv & env)
|
void ExprAttrs::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
const StaticEnv * dynamicEnv = &env;
|
const StaticEnv * dynamicEnv = &env;
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env, recursive ? attrs.size() : 0);
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
dynamicEnv = &newEnv;
|
dynamicEnv = &newEnv;
|
||||||
|
|
||||||
unsigned int displ = 0;
|
Displacement displ = 0;
|
||||||
for (auto & i : attrs)
|
for (auto & i : attrs)
|
||||||
newEnv.vars[i.first] = i.second.displ = displ++;
|
newEnv.vars.emplace_back(i.first, i.second.displ = displ++);
|
||||||
|
|
||||||
|
// No need to sort newEnv since attrs is in sorted order.
|
||||||
|
|
||||||
for (auto & i : attrs)
|
for (auto & i : attrs)
|
||||||
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
||||||
|
|
@ -342,15 +354,20 @@ void ExprList::bindVars(const StaticEnv & env)
|
||||||
|
|
||||||
void ExprLambda::bindVars(const StaticEnv & env)
|
void ExprLambda::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(
|
||||||
|
false, &env,
|
||||||
|
(hasFormals() ? formals->formals.size() : 0) +
|
||||||
|
(arg.empty() ? 0 : 1));
|
||||||
|
|
||||||
unsigned int displ = 0;
|
Displacement displ = 0;
|
||||||
|
|
||||||
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
if (!arg.empty()) newEnv.vars.emplace_back(arg, displ++);
|
||||||
|
|
||||||
if (hasFormals()) {
|
if (hasFormals()) {
|
||||||
for (auto & i : formals->formals)
|
for (auto & i : formals->formals)
|
||||||
newEnv.vars[i.name] = displ++;
|
newEnv.vars.emplace_back(i.name, displ++);
|
||||||
|
|
||||||
|
newEnv.sort();
|
||||||
|
|
||||||
for (auto & i : formals->formals)
|
for (auto & i : formals->formals)
|
||||||
if (i.def) i.def->bindVars(newEnv);
|
if (i.def) i.def->bindVars(newEnv);
|
||||||
|
|
@ -359,13 +376,22 @@ void ExprLambda::bindVars(const StaticEnv & env)
|
||||||
body->bindVars(newEnv);
|
body->bindVars(newEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExprCall::bindVars(const StaticEnv & env)
|
||||||
|
{
|
||||||
|
fun->bindVars(env);
|
||||||
|
for (auto e : args)
|
||||||
|
e->bindVars(env);
|
||||||
|
}
|
||||||
|
|
||||||
void ExprLet::bindVars(const StaticEnv & env)
|
void ExprLet::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env, attrs->attrs.size());
|
||||||
|
|
||||||
unsigned int displ = 0;
|
Displacement displ = 0;
|
||||||
for (auto & i : attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
newEnv.vars[i.first] = i.second.displ = displ++;
|
newEnv.vars.emplace_back(i.first, i.second.displ = displ++);
|
||||||
|
|
||||||
|
// No need to sort newEnv since attrs->attrs is in sorted order.
|
||||||
|
|
||||||
for (auto & i : attrs->attrs)
|
for (auto & i : attrs->attrs)
|
||||||
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
i.second.e->bindVars(i.second.inherited ? env : newEnv);
|
||||||
|
|
@ -379,7 +405,7 @@ void ExprWith::bindVars(const StaticEnv & env)
|
||||||
level so that `lookupVar' can look up variables in the previous
|
level so that `lookupVar' can look up variables in the previous
|
||||||
`with' if this one doesn't contain the desired attribute. */
|
`with' if this one doesn't contain the desired attribute. */
|
||||||
const StaticEnv * curEnv;
|
const StaticEnv * curEnv;
|
||||||
unsigned int level;
|
Level level;
|
||||||
prevWith = 0;
|
prevWith = 0;
|
||||||
for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++)
|
for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++)
|
||||||
if (curEnv->isWith) {
|
if (curEnv->isWith) {
|
||||||
|
|
@ -452,5 +478,4 @@ size_t SymbolTable::totalSize() const
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
@ -135,6 +133,9 @@ struct ExprPath : Expr
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Value * maybeThunk(EvalState & state, Env & env);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef uint32_t Level;
|
||||||
|
typedef uint32_t Displacement;
|
||||||
|
|
||||||
struct ExprVar : Expr
|
struct ExprVar : Expr
|
||||||
{
|
{
|
||||||
Pos pos;
|
Pos pos;
|
||||||
|
|
@ -150,8 +151,8 @@ struct ExprVar : Expr
|
||||||
value is obtained by getting the attribute named `name' from
|
value is obtained by getting the attribute named `name' from
|
||||||
the set stored in the environment that is `level' levels up
|
the set stored in the environment that is `level' levels up
|
||||||
from the current one.*/
|
from the current one.*/
|
||||||
unsigned int level;
|
Level level;
|
||||||
unsigned int displ;
|
Displacement displ;
|
||||||
|
|
||||||
ExprVar(const Symbol & name) : name(name) { };
|
ExprVar(const Symbol & name) : name(name) { };
|
||||||
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
|
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
|
||||||
|
|
@ -185,7 +186,7 @@ struct ExprAttrs : Expr
|
||||||
bool inherited;
|
bool inherited;
|
||||||
Expr * e;
|
Expr * e;
|
||||||
Pos pos;
|
Pos pos;
|
||||||
unsigned int displ; // displacement
|
Displacement displ; // displacement
|
||||||
AttrDef(Expr * e, const Pos & pos, bool inherited=false)
|
AttrDef(Expr * e, const Pos & pos, bool inherited=false)
|
||||||
: inherited(inherited), e(e), pos(pos) { };
|
: inherited(inherited), e(e), pos(pos) { };
|
||||||
AttrDef() { };
|
AttrDef() { };
|
||||||
|
|
@ -250,6 +251,17 @@ struct ExprLambda : Expr
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExprCall : Expr
|
||||||
|
{
|
||||||
|
Expr * fun;
|
||||||
|
std::vector<Expr *> args;
|
||||||
|
Pos pos;
|
||||||
|
ExprCall(const Pos & pos, Expr * fun, std::vector<Expr *> && args)
|
||||||
|
: fun(fun), args(args), pos(pos)
|
||||||
|
{ }
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
struct ExprLet : Expr
|
struct ExprLet : Expr
|
||||||
{
|
{
|
||||||
ExprAttrs * attrs;
|
ExprAttrs * attrs;
|
||||||
|
|
@ -308,7 +320,6 @@ struct ExprOpNot : Expr
|
||||||
void eval(EvalState & state, Env & env, Value & v); \
|
void eval(EvalState & state, Env & env, Value & v); \
|
||||||
};
|
};
|
||||||
|
|
||||||
MakeBinOp(ExprApp, "")
|
|
||||||
MakeBinOp(ExprOpEq, "==")
|
MakeBinOp(ExprOpEq, "==")
|
||||||
MakeBinOp(ExprOpNEq, "!=")
|
MakeBinOp(ExprOpNEq, "!=")
|
||||||
MakeBinOp(ExprOpAnd, "&&")
|
MakeBinOp(ExprOpAnd, "&&")
|
||||||
|
|
@ -342,9 +353,28 @@ struct StaticEnv
|
||||||
{
|
{
|
||||||
bool isWith;
|
bool isWith;
|
||||||
const StaticEnv * up;
|
const StaticEnv * up;
|
||||||
typedef std::map<Symbol, unsigned int> Vars;
|
|
||||||
|
// Note: these must be in sorted order.
|
||||||
|
typedef std::vector<std::pair<Symbol, Displacement>> Vars;
|
||||||
Vars vars;
|
Vars vars;
|
||||||
StaticEnv(bool isWith, const StaticEnv * up) : isWith(isWith), up(up) { };
|
|
||||||
|
StaticEnv(bool isWith, const StaticEnv * up, size_t expectedSize = 0) : isWith(isWith), up(up) {
|
||||||
|
vars.reserve(expectedSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
void sort()
|
||||||
|
{
|
||||||
|
std::sort(vars.begin(), vars.end(),
|
||||||
|
[](const Vars::value_type & a, const Vars::value_type & b) { return a.first < b.first; });
|
||||||
|
}
|
||||||
|
|
||||||
|
Vars::const_iterator find(const Symbol & name) const
|
||||||
|
{
|
||||||
|
Vars::value_type key(name, 0);
|
||||||
|
auto i = std::lower_bound(vars.begin(), vars.end(), key);
|
||||||
|
if (i != vars.end() && i->first == name) return i;
|
||||||
|
return vars.end();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,9 @@ namespace nix {
|
||||||
Symbol file;
|
Symbol file;
|
||||||
FileOrigin origin;
|
FileOrigin origin;
|
||||||
std::optional<ErrorInfo> error;
|
std::optional<ErrorInfo> error;
|
||||||
Symbol sLetBody;
|
|
||||||
ParseData(EvalState & state)
|
ParseData(EvalState & state)
|
||||||
: state(state)
|
: state(state)
|
||||||
, symbols(state.symbols)
|
, symbols(state.symbols)
|
||||||
, sLetBody(symbols.create("<let-body>"))
|
|
||||||
{ };
|
{ };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -126,14 +124,14 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||||
auto j2 = jAttrs->attrs.find(ad.first);
|
auto j2 = jAttrs->attrs.find(ad.first);
|
||||||
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
||||||
dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
||||||
jAttrs->attrs[ad.first] = ad.second;
|
jAttrs->attrs.emplace(ad.first, ad.second);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dupAttr(attrPath, pos, j->second.pos);
|
dupAttr(attrPath, pos, j->second.pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This attr path is not defined. Let's create it.
|
// This attr path is not defined. Let's create it.
|
||||||
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
|
attrs->attrs.emplace(i->symbol, ExprAttrs::AttrDef(e, pos));
|
||||||
e->setName(i->symbol);
|
e->setName(i->symbol);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -283,7 +281,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||||
}
|
}
|
||||||
|
|
||||||
%type <e> start expr expr_function expr_if expr_op
|
%type <e> start expr expr_function expr_if expr_op
|
||||||
%type <e> expr_app expr_select expr_simple
|
%type <e> expr_select expr_simple expr_app
|
||||||
%type <list> expr_list
|
%type <list> expr_list
|
||||||
%type <attrs> binds
|
%type <attrs> binds
|
||||||
%type <formals> formals
|
%type <formals> formals
|
||||||
|
|
@ -353,13 +351,13 @@ expr_if
|
||||||
|
|
||||||
expr_op
|
expr_op
|
||||||
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
||||||
| '-' expr_op %prec NEGATE { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__sub")), new ExprInt(0)), $2); }
|
| '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {new ExprInt(0), $2}); }
|
||||||
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||||
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
||||||
| expr_op '<' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3); }
|
| expr_op '<' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__lessThan")), {$1, $3}); }
|
||||||
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1)); }
|
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__lessThan")), {$3, $1})); }
|
||||||
| expr_op '>' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1); }
|
| expr_op '>' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__lessThan")), {$3, $1}); }
|
||||||
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3)); }
|
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__lessThan")), {$1, $3})); }
|
||||||
| expr_op AND expr_op { $$ = new ExprOpAnd(CUR_POS, $1, $3); }
|
| expr_op AND expr_op { $$ = new ExprOpAnd(CUR_POS, $1, $3); }
|
||||||
| expr_op OR expr_op { $$ = new ExprOpOr(CUR_POS, $1, $3); }
|
| expr_op OR expr_op { $$ = new ExprOpOr(CUR_POS, $1, $3); }
|
||||||
| expr_op IMPL expr_op { $$ = new ExprOpImpl(CUR_POS, $1, $3); }
|
| expr_op IMPL expr_op { $$ = new ExprOpImpl(CUR_POS, $1, $3); }
|
||||||
|
|
@ -367,17 +365,22 @@ expr_op
|
||||||
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
|
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
|
||||||
| expr_op '+' expr_op
|
| expr_op '+' expr_op
|
||||||
{ $$ = new ExprConcatStrings(CUR_POS, false, new vector<Expr *>({$1, $3})); }
|
{ $$ = new ExprConcatStrings(CUR_POS, false, new vector<Expr *>({$1, $3})); }
|
||||||
| expr_op '-' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__sub")), $1), $3); }
|
| expr_op '-' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {$1, $3}); }
|
||||||
| expr_op '*' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__mul")), $1), $3); }
|
| expr_op '*' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__mul")), {$1, $3}); }
|
||||||
| expr_op '/' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprVar(data->symbols.create("__div")), $1), $3); }
|
| expr_op '/' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__div")), {$1, $3}); }
|
||||||
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(CUR_POS, $1, $3); }
|
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(CUR_POS, $1, $3); }
|
||||||
| expr_app
|
| expr_app
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_app
|
expr_app
|
||||||
: expr_app expr_select
|
: expr_app expr_select {
|
||||||
{ $$ = new ExprApp(CUR_POS, $1, $2); }
|
if (auto e2 = dynamic_cast<ExprCall *>($1)) {
|
||||||
| expr_select { $$ = $1; }
|
e2->args.push_back($2);
|
||||||
|
$$ = $1;
|
||||||
|
} else
|
||||||
|
$$ = new ExprCall(CUR_POS, $1, {$2});
|
||||||
|
}
|
||||||
|
| expr_select
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_select
|
expr_select
|
||||||
|
|
@ -388,7 +391,7 @@ expr_select
|
||||||
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
||||||
function named ‘or’, allow stuff like ‘map or [...]’. */
|
function named ‘or’, allow stuff like ‘map or [...]’. */
|
||||||
expr_simple OR_KW
|
expr_simple OR_KW
|
||||||
{ $$ = new ExprApp(CUR_POS, $1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
|
{ $$ = new ExprCall(CUR_POS, $1, {new ExprVar(CUR_POS, data->symbols.create("or"))}); }
|
||||||
| expr_simple { $$ = $1; }
|
| expr_simple { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -412,10 +415,10 @@ expr_simple
|
||||||
}
|
}
|
||||||
| SPATH {
|
| SPATH {
|
||||||
string path($1 + 1, strlen($1) - 2);
|
string path($1 + 1, strlen($1) - 2);
|
||||||
$$ = new ExprApp(CUR_POS,
|
$$ = new ExprCall(CUR_POS,
|
||||||
new ExprApp(new ExprVar(data->symbols.create("__findFile")),
|
new ExprVar(data->symbols.create("__findFile")),
|
||||||
new ExprVar(data->symbols.create("__nixPath"))),
|
{new ExprVar(data->symbols.create("__nixPath")),
|
||||||
new ExprString(data->symbols.create(path)));
|
new ExprString(data->symbols.create(path))});
|
||||||
}
|
}
|
||||||
| URI {
|
| URI {
|
||||||
static bool noURLLiterals = settings.isExperimentalFeatureEnabled(Xp::NoUrlLiterals);
|
static bool noURLLiterals = settings.isExperimentalFeatureEnabled(Xp::NoUrlLiterals);
|
||||||
|
|
@ -483,7 +486,7 @@ binds
|
||||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
dupAttr(i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos);
|
dupAttr(i.symbol, makeCurPos(@3, data), $$->attrs[i.symbol].pos);
|
||||||
Pos pos = makeCurPos(@3, data);
|
Pos pos = makeCurPos(@3, data);
|
||||||
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true);
|
$$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| binds INHERIT '(' expr ')' attrs ';'
|
| binds INHERIT '(' expr ')' attrs ';'
|
||||||
|
|
@ -492,7 +495,7 @@ binds
|
||||||
for (auto & i : *$6) {
|
for (auto & i : *$6) {
|
||||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
dupAttr(i.symbol, makeCurPos(@6, data), $$->attrs[i.symbol].pos);
|
dupAttr(i.symbol, makeCurPos(@6, data), $$->attrs[i.symbol].pos);
|
||||||
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data));
|
$$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| { $$ = new ExprAttrs(makeCurPos(@0, data)); }
|
| { $$ = new ExprAttrs(makeCurPos(@0, data)); }
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ void EvalState::realiseContext(const PathSet & context)
|
||||||
if (outputPaths.count(outputName) == 0)
|
if (outputPaths.count(outputName) == 0)
|
||||||
throw Error("derivation '%s' does not have an output named '%s'",
|
throw Error("derivation '%s' does not have an output named '%s'",
|
||||||
store->printStorePath(drvPath), outputName);
|
store->printStorePath(drvPath), outputName);
|
||||||
allowedPaths->insert(store->printStorePath(outputPaths.at(outputName)));
|
allowPath(outputPaths.at(outputName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,14 +184,17 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
Env * env = &state.allocEnv(vScope->attrs->size());
|
Env * env = &state.allocEnv(vScope->attrs->size());
|
||||||
env->up = &state.baseEnv;
|
env->up = &state.baseEnv;
|
||||||
|
|
||||||
StaticEnv staticEnv(false, &state.staticBaseEnv);
|
StaticEnv staticEnv(false, &state.staticBaseEnv, vScope->attrs->size());
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
for (auto & attr : *vScope->attrs) {
|
for (auto & attr : *vScope->attrs) {
|
||||||
staticEnv.vars[attr.name] = displ;
|
staticEnv.vars.emplace_back(attr.name, displ);
|
||||||
env->values[displ++] = attr.value;
|
env->values[displ++] = attr.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No need to call staticEnv.sort(), because
|
||||||
|
// args[0]->attrs is already sorted.
|
||||||
|
|
||||||
printTalkative("evaluating file '%1%'", realPath);
|
printTalkative("evaluating file '%1%'", realPath);
|
||||||
Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv);
|
Expr * e = state.parseExprFromFile(resolveExprPath(realPath), staticEnv);
|
||||||
|
|
||||||
|
|
@ -514,7 +517,11 @@ static RegisterPrimOp primop_isPath({
|
||||||
|
|
||||||
struct CompareValues
|
struct CompareValues
|
||||||
{
|
{
|
||||||
bool operator () (const Value * v1, const Value * v2) const
|
EvalState & state;
|
||||||
|
|
||||||
|
CompareValues(EvalState & state) : state(state) { };
|
||||||
|
|
||||||
|
bool operator () (Value * v1, Value * v2) const
|
||||||
{
|
{
|
||||||
if (v1->type() == nFloat && v2->type() == nInt)
|
if (v1->type() == nFloat && v2->type() == nInt)
|
||||||
return v1->fpoint < v2->integer;
|
return v1->fpoint < v2->integer;
|
||||||
|
|
@ -531,6 +538,17 @@ struct CompareValues
|
||||||
return strcmp(v1->string.s, v2->string.s) < 0;
|
return strcmp(v1->string.s, v2->string.s) < 0;
|
||||||
case nPath:
|
case nPath:
|
||||||
return strcmp(v1->path, v2->path) < 0;
|
return strcmp(v1->path, v2->path) < 0;
|
||||||
|
case nList:
|
||||||
|
// Lexicographic comparison
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
if (i == v2->listSize()) {
|
||||||
|
return false;
|
||||||
|
} else if (i == v1->listSize()) {
|
||||||
|
return true;
|
||||||
|
} else if (!state.eqValues(*v1->listElems()[i], *v2->listElems()[i])) {
|
||||||
|
return (*this)(v1->listElems()[i], v2->listElems()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
|
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
|
||||||
}
|
}
|
||||||
|
|
@ -618,7 +636,8 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
||||||
ValueList res;
|
ValueList res;
|
||||||
// `doneKeys' doesn't need to be a GC root, because its values are
|
// `doneKeys' doesn't need to be a GC root, because its values are
|
||||||
// reachable from res.
|
// reachable from res.
|
||||||
set<Value *, CompareValues> doneKeys;
|
auto cmp = CompareValues(state);
|
||||||
|
set<Value *, decltype(cmp)> doneKeys(cmp);
|
||||||
while (!workSet.empty()) {
|
while (!workSet.empty()) {
|
||||||
Value * e = *(workSet.begin());
|
Value * e = *(workSet.begin());
|
||||||
workSet.pop_front();
|
workSet.pop_front();
|
||||||
|
|
@ -1009,7 +1028,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
if (i->name == state.sStructuredAttrs) continue;
|
if (i->name == state.sStructuredAttrs) continue;
|
||||||
|
|
||||||
auto placeholder(jsonObject->placeholder(key));
|
auto placeholder(jsonObject->placeholder(key));
|
||||||
printValueAsJSON(state, true, *i->value, placeholder, context);
|
printValueAsJSON(state, true, *i->value, pos, placeholder, context);
|
||||||
|
|
||||||
if (i->name == state.sBuilder)
|
if (i->name == state.sBuilder)
|
||||||
drv.builder = state.forceString(*i->value, context, posDrvName);
|
drv.builder = state.forceString(*i->value, context, posDrvName);
|
||||||
|
|
@ -1580,7 +1599,7 @@ static void prim_toXML(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
PathSet context;
|
PathSet context;
|
||||||
printValueAsXML(state, true, false, *args[0], out, context);
|
printValueAsXML(state, true, false, *args[0], out, context, pos);
|
||||||
mkString(v, out.str(), context);
|
mkString(v, out.str(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1688,7 +1707,7 @@ static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
PathSet context;
|
PathSet context;
|
||||||
printValueAsJSON(state, true, *args[0], out, context);
|
printValueAsJSON(state, true, *args[0], pos, out, context);
|
||||||
mkString(v, out.str(), context);
|
mkString(v, out.str(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1860,12 +1879,12 @@ static void addPath(
|
||||||
// be rewritten to the actual output).
|
// be rewritten to the actual output).
|
||||||
state.realiseContext(context);
|
state.realiseContext(context);
|
||||||
|
|
||||||
|
StorePathSet refs;
|
||||||
|
|
||||||
if (state.store->isInStore(path)) {
|
if (state.store->isInStore(path)) {
|
||||||
auto [storePath, subPath] = state.store->toStorePath(path);
|
auto [storePath, subPath] = state.store->toStorePath(path);
|
||||||
auto info = state.store->queryPathInfo(storePath);
|
// FIXME: we should scanForReferences on the path before adding it
|
||||||
if (!info->references.empty())
|
refs = state.store->queryPathInfo(storePath)->references;
|
||||||
throw EvalError("store path '%s' is not allowed to have references",
|
|
||||||
state.store->printStorePath(storePath));
|
|
||||||
path = state.store->toRealPath(storePath) + subPath;
|
path = state.store->toRealPath(storePath) + subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1881,9 +1900,6 @@ static void addPath(
|
||||||
Value arg1;
|
Value arg1;
|
||||||
mkString(arg1, path);
|
mkString(arg1, path);
|
||||||
|
|
||||||
Value fun2;
|
|
||||||
state.callFunction(*filterFun, arg1, fun2, noPos);
|
|
||||||
|
|
||||||
Value arg2;
|
Value arg2;
|
||||||
mkString(arg2,
|
mkString(arg2,
|
||||||
S_ISREG(st.st_mode) ? "regular" :
|
S_ISREG(st.st_mode) ? "regular" :
|
||||||
|
|
@ -1891,8 +1907,9 @@ static void addPath(
|
||||||
S_ISLNK(st.st_mode) ? "symlink" :
|
S_ISLNK(st.st_mode) ? "symlink" :
|
||||||
"unknown" /* not supported, will fail! */);
|
"unknown" /* not supported, will fail! */);
|
||||||
|
|
||||||
|
Value * args []{&arg1, &arg2};
|
||||||
Value res;
|
Value res;
|
||||||
state.callFunction(fun2, arg2, res, noPos);
|
state.callFunction(*filterFun, 2, args, res, pos);
|
||||||
|
|
||||||
return state.forceBool(res, pos);
|
return state.forceBool(res, pos);
|
||||||
}) : defaultPathFilter;
|
}) : defaultPathFilter;
|
||||||
|
|
@ -1905,7 +1922,7 @@ static void addPath(
|
||||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||||
dstPath = state.store->printStorePath(settings.readOnlyMode
|
dstPath = state.store->printStorePath(settings.readOnlyMode
|
||||||
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
|
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
|
||||||
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair));
|
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs));
|
||||||
if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath))
|
if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath))
|
||||||
throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
|
throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
|
||||||
} else
|
} else
|
||||||
|
|
@ -2693,10 +2710,9 @@ static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args,
|
||||||
Value * vCur = args[1];
|
Value * vCur = args[1];
|
||||||
|
|
||||||
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
|
for (unsigned int n = 0; n < args[2]->listSize(); ++n) {
|
||||||
Value vTmp;
|
Value * vs []{vCur, args[2]->listElems()[n]};
|
||||||
state.callFunction(*args[0], *vCur, vTmp, pos);
|
|
||||||
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
|
vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue();
|
||||||
state.callFunction(vTmp, *args[2]->listElems()[n], *vCur, pos);
|
state.callFunction(*args[0], 2, vs, *vCur, pos);
|
||||||
}
|
}
|
||||||
state.forceValue(v, pos);
|
state.forceValue(v, pos);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2710,9 +2726,9 @@ static RegisterPrimOp primop_foldlStrict({
|
||||||
.args = {"op", "nul", "list"},
|
.args = {"op", "nul", "list"},
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Reduce a list by applying a binary operator, from left to right,
|
Reduce a list by applying a binary operator, from left to right,
|
||||||
e.g. `foldl’ op nul [x0 x1 x2 ...] = op (op (op nul x0) x1) x2)
|
e.g. `foldl' op nul [x0 x1 x2 ...] = op (op (op nul x0) x1) x2)
|
||||||
...`. The operator is applied strictly, i.e., its arguments are
|
...`. The operator is applied strictly, i.e., its arguments are
|
||||||
evaluated first. For example, `foldl’ (x: y: x + y) 0 [1 2 3]`
|
evaluated first. For example, `foldl' (x: y: x + y) 0 [1 2 3]`
|
||||||
evaluates to 6.
|
evaluates to 6.
|
||||||
)",
|
)",
|
||||||
.fun = prim_foldlStrict,
|
.fun = prim_foldlStrict,
|
||||||
|
|
@ -2817,17 +2833,16 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value
|
||||||
v.listElems()[n] = args[1]->listElems()[n];
|
v.listElems()[n] = args[1]->listElems()[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto comparator = [&](Value * a, Value * b) {
|
auto comparator = [&](Value * a, Value * b) {
|
||||||
/* Optimization: if the comparator is lessThan, bypass
|
/* Optimization: if the comparator is lessThan, bypass
|
||||||
callFunction. */
|
callFunction. */
|
||||||
if (args[0]->isPrimOp() && args[0]->primOp->fun == prim_lessThan)
|
if (args[0]->isPrimOp() && args[0]->primOp->fun == prim_lessThan)
|
||||||
return CompareValues()(a, b);
|
return CompareValues(state)(a, b);
|
||||||
|
|
||||||
Value vTmp1, vTmp2;
|
Value * vs[] = {a, b};
|
||||||
state.callFunction(*args[0], *a, vTmp1, pos);
|
Value vBool;
|
||||||
state.callFunction(vTmp1, *b, vTmp2, pos);
|
state.callFunction(*args[0], 2, vs, vBool, pos);
|
||||||
return state.forceBool(vTmp2, pos);
|
return state.forceBool(vBool, pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME: std::sort can segfault if the comparator is not a strict
|
/* FIXME: std::sort can segfault if the comparator is not a strict
|
||||||
|
|
@ -3104,7 +3119,7 @@ static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
{
|
{
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
state.forceValue(*args[1], pos);
|
state.forceValue(*args[1], pos);
|
||||||
CompareValues comp;
|
CompareValues comp{state};
|
||||||
mkBool(v, comp(args[0], args[1]));
|
mkBool(v, comp(args[0], args[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3694,7 +3709,7 @@ void EvalState::createBaseEnv()
|
||||||
language feature gets added. It's not necessary to increase it
|
language feature gets added. It's not necessary to increase it
|
||||||
when primops get added, because you can just use `builtins ?
|
when primops get added, because you can just use `builtins ?
|
||||||
primOp' to check. */
|
primOp' to check. */
|
||||||
mkInt(v, 5);
|
mkInt(v, 6);
|
||||||
addConstant("__langVersion", v);
|
addConstant("__langVersion", v);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
|
@ -3728,14 +3743,20 @@ void EvalState::createBaseEnv()
|
||||||
/* Add a wrapper around the derivation primop that computes the
|
/* Add a wrapper around the derivation primop that computes the
|
||||||
`drvPath' and `outPath' attributes lazily. */
|
`drvPath' and `outPath' attributes lazily. */
|
||||||
sDerivationNix = symbols.create("//builtin/derivation.nix");
|
sDerivationNix = symbols.create("//builtin/derivation.nix");
|
||||||
eval(parse(
|
auto vDerivation = allocValue();
|
||||||
#include "primops/derivation.nix.gen.hh"
|
addConstant("derivation", vDerivation);
|
||||||
, foFile, sDerivationNix, "/", staticBaseEnv), v);
|
|
||||||
addConstant("derivation", v);
|
|
||||||
|
|
||||||
/* Now that we've added all primops, sort the `builtins' set,
|
/* Now that we've added all primops, sort the `builtins' set,
|
||||||
because attribute lookups expect it to be sorted. */
|
because attribute lookups expect it to be sorted. */
|
||||||
baseEnv.values[0]->attrs->sort();
|
baseEnv.values[0]->attrs->sort();
|
||||||
|
|
||||||
|
staticBaseEnv.sort();
|
||||||
|
|
||||||
|
/* Note: we have to initialize the 'derivation' constant *after*
|
||||||
|
building baseEnv/staticBaseEnv because it uses 'builtins'. */
|
||||||
|
eval(parse(
|
||||||
|
#include "primops/derivation.nix.gen.hh"
|
||||||
|
, foFile, sDerivationNix, "/", staticBaseEnv), *vDerivation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,10 @@ std::string fixURI(std::string uri, EvalState & state, const std::string & defau
|
||||||
|
|
||||||
std::string fixURIForGit(std::string uri, EvalState & state)
|
std::string fixURIForGit(std::string uri, EvalState & state)
|
||||||
{
|
{
|
||||||
static std::regex scp_uri("([^/].*)@(.*):(.*)");
|
/* Detects scp-style uris (e.g. git@github.com:NixOS/nix) and fixes
|
||||||
|
* them by removing the `:` and assuming a scheme of `ssh://`
|
||||||
|
* */
|
||||||
|
static std::regex scp_uri("([^/]*)@(.*):(.*)");
|
||||||
if (uri[0] != '/' && std::regex_match(uri, scp_uri))
|
if (uri[0] != '/' && std::regex_match(uri, scp_uri))
|
||||||
return fixURI(std::regex_replace(uri, scp_uri, "$1@$2/$3"), state, "ssh");
|
return fixURI(std::regex_replace(uri, scp_uri, "$1@$2/$3"), state, "ssh");
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, JSONPlaceholder & out, PathSet & context)
|
Value & v, const Pos & pos, JSONPlaceholder & out, PathSet & context)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
if (strict) state.forceValue(v);
|
if (strict) state.forceValue(v, pos);
|
||||||
|
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nAttrs: {
|
case nAttrs: {
|
||||||
auto maybeString = state.tryAttrsToString(noPos, v, context, false, false);
|
auto maybeString = state.tryAttrsToString(pos, v, context, false, false);
|
||||||
if (maybeString) {
|
if (maybeString) {
|
||||||
out.write(*maybeString);
|
out.write(*maybeString);
|
||||||
break;
|
break;
|
||||||
|
|
@ -54,10 +54,10 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
for (auto & j : names) {
|
for (auto & j : names) {
|
||||||
Attr & a(*v.attrs->find(state.symbols.create(j)));
|
Attr & a(*v.attrs->find(state.symbols.create(j)));
|
||||||
auto placeholder(obj.placeholder(j));
|
auto placeholder(obj.placeholder(j));
|
||||||
printValueAsJSON(state, strict, *a.value, placeholder, context);
|
printValueAsJSON(state, strict, *a.value, *a.pos, placeholder, context);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
printValueAsJSON(state, strict, *i->value, out, context);
|
printValueAsJSON(state, strict, *i->value, *i->pos, out, context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
auto list(out.list());
|
auto list(out.list());
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
auto placeholder(list.placeholder());
|
auto placeholder(list.placeholder());
|
||||||
printValueAsJSON(state, strict, *v.listElems()[n], placeholder, context);
|
printValueAsJSON(state, strict, *v.listElems()[n], pos, placeholder, context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -79,18 +79,20 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nThunk:
|
case nThunk:
|
||||||
throw TypeError("cannot convert %1% to JSON", showType(v));
|
|
||||||
|
|
||||||
case nFunction:
|
case nFunction:
|
||||||
throw TypeError("cannot convert %1% to JSON", showType(v));
|
auto e = TypeError({
|
||||||
|
.msg = hintfmt("cannot convert %1% to JSON", showType(v)),
|
||||||
|
.errPos = v.determinePos(pos)
|
||||||
|
});
|
||||||
|
throw e.addTrace(pos, hintfmt("message for the trace"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, std::ostream & str, PathSet & context)
|
Value & v, const Pos & pos, std::ostream & str, PathSet & context)
|
||||||
{
|
{
|
||||||
JSONPlaceholder out(str);
|
JSONPlaceholder out(str);
|
||||||
printValueAsJSON(state, strict, v, out, context);
|
printValueAsJSON(state, strict, v, pos, out, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ namespace nix {
|
||||||
class JSONPlaceholder;
|
class JSONPlaceholder;
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, JSONPlaceholder & out, PathSet & context);
|
Value & v, const Pos & pos, JSONPlaceholder & out, PathSet & context);
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, std::ostream & str, PathSet & context);
|
Value & v, const Pos & pos, std::ostream & str, PathSet & context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ static XMLAttrs singletonAttrs(const string & name, const string & value)
|
||||||
|
|
||||||
|
|
||||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen);
|
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||||
|
const Pos & pos);
|
||||||
|
|
||||||
|
|
||||||
static void posToXML(XMLAttrs & xmlAttrs, const Pos & pos)
|
static void posToXML(XMLAttrs & xmlAttrs, const Pos & pos)
|
||||||
|
|
@ -46,17 +47,18 @@ static void showAttrs(EvalState & state, bool strict, bool location,
|
||||||
|
|
||||||
XMLOpenElement _(doc, "attr", xmlAttrs);
|
XMLOpenElement _(doc, "attr", xmlAttrs);
|
||||||
printValueAsXML(state, strict, location,
|
printValueAsXML(state, strict, location,
|
||||||
*a.value, doc, context, drvsSeen);
|
*a.value, doc, context, drvsSeen, *a.pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||||
|
const Pos & pos)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
if (strict) state.forceValue(v);
|
if (strict) state.forceValue(v, pos);
|
||||||
|
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
|
|
||||||
|
|
@ -91,14 +93,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Path drvPath;
|
Path drvPath;
|
||||||
a = v.attrs->find(state.sDrvPath);
|
a = v.attrs->find(state.sDrvPath);
|
||||||
if (a != v.attrs->end()) {
|
if (a != v.attrs->end()) {
|
||||||
if (strict) state.forceValue(*a->value);
|
if (strict) state.forceValue(*a->value, *a->pos);
|
||||||
if (a->value->type() == nString)
|
if (a->value->type() == nString)
|
||||||
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
|
xmlAttrs["drvPath"] = drvPath = a->value->string.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = v.attrs->find(state.sOutPath);
|
a = v.attrs->find(state.sOutPath);
|
||||||
if (a != v.attrs->end()) {
|
if (a != v.attrs->end()) {
|
||||||
if (strict) state.forceValue(*a->value);
|
if (strict) state.forceValue(*a->value, *a->pos);
|
||||||
if (a->value->type() == nString)
|
if (a->value->type() == nString)
|
||||||
xmlAttrs["outPath"] = a->value->string.s;
|
xmlAttrs["outPath"] = a->value->string.s;
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +123,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
case nList: {
|
case nList: {
|
||||||
XMLOpenElement _(doc, "list");
|
XMLOpenElement _(doc, "list");
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n)
|
for (unsigned int n = 0; n < v.listSize(); ++n)
|
||||||
printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen);
|
printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen, pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +151,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
}
|
}
|
||||||
|
|
||||||
case nExternal:
|
case nExternal:
|
||||||
v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen);
|
v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen, pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nFloat:
|
case nFloat:
|
||||||
|
|
@ -163,19 +165,20 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
|
|
||||||
|
|
||||||
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
||||||
bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen) const
|
bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||||
|
const Pos & pos) const
|
||||||
{
|
{
|
||||||
doc.writeEmptyElement("unevaluated");
|
doc.writeEmptyElement("unevaluated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Value & v, std::ostream & out, PathSet & context)
|
Value & v, std::ostream & out, PathSet & context, const Pos & pos)
|
||||||
{
|
{
|
||||||
XMLWriter doc(true, out);
|
XMLWriter doc(true, out);
|
||||||
XMLOpenElement root(doc, "expr");
|
XMLOpenElement root(doc, "expr");
|
||||||
PathSet drvsSeen;
|
PathSet drvsSeen;
|
||||||
printValueAsXML(state, strict, location, v, doc, context, drvsSeen);
|
printValueAsXML(state, strict, location, v, doc, context, drvsSeen, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Value & v, std::ostream & out, PathSet & context);
|
Value & v, std::ostream & out, PathSet & context, const Pos & pos);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ class ExternalValueBase
|
||||||
|
|
||||||
/* Print the value as XML. Defaults to unevaluated */
|
/* Print the value as XML. Defaults to unevaluated */
|
||||||
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
|
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
XMLWriter & doc, PathSet & context, PathSet & drvsSeen) const;
|
XMLWriter & doc, PathSet & context, PathSet & drvsSeen,
|
||||||
|
const Pos & pos) const;
|
||||||
|
|
||||||
virtual ~ExternalValueBase()
|
virtual ~ExternalValueBase()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ struct GitInputScheme : InputScheme
|
||||||
for (auto &[name, value] : url.query) {
|
for (auto &[name, value] : url.query) {
|
||||||
if (name == "rev" || name == "ref")
|
if (name == "rev" || name == "ref")
|
||||||
attrs.emplace(name, value);
|
attrs.emplace(name, value);
|
||||||
else if (name == "shallow")
|
else if (name == "shallow" || name == "submodules")
|
||||||
attrs.emplace(name, Explicit<bool> { value == "1" });
|
attrs.emplace(name, Explicit<bool> { value == "1" });
|
||||||
else
|
else
|
||||||
url2.query.emplace(name, value);
|
url2.query.emplace(name, value);
|
||||||
|
|
@ -324,17 +324,13 @@ struct GitInputScheme : InputScheme
|
||||||
Path cacheDir = getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, actualUrl).to_string(Base32, false);
|
Path cacheDir = getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, actualUrl).to_string(Base32, false);
|
||||||
repoDir = cacheDir;
|
repoDir = cacheDir;
|
||||||
|
|
||||||
Path cacheDirLock = cacheDir + ".lock";
|
|
||||||
createDirs(dirOf(cacheDir));
|
createDirs(dirOf(cacheDir));
|
||||||
AutoCloseFD lock = openLockFile(cacheDirLock, true);
|
PathLocks cacheDirLock({cacheDir + ".lock"});
|
||||||
lockFile(lock.get(), ltWrite, true);
|
|
||||||
|
|
||||||
if (!pathExists(cacheDir)) {
|
if (!pathExists(cacheDir)) {
|
||||||
runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir });
|
runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir });
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteLockFile(cacheDirLock, lock.get());
|
|
||||||
|
|
||||||
Path localRefFile =
|
Path localRefFile =
|
||||||
input.getRef()->compare(0, 5, "refs/") == 0
|
input.getRef()->compare(0, 5, "refs/") == 0
|
||||||
? cacheDir + "/" + *input.getRef()
|
? cacheDir + "/" + *input.getRef()
|
||||||
|
|
@ -399,6 +395,8 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
if (!input.getRev())
|
if (!input.getRev())
|
||||||
input.attrs.insert_or_assign("rev", Hash::parseAny(chomp(readFile(localRefFile)), htSHA1).gitRev());
|
input.attrs.insert_or_assign("rev", Hash::parseAny(chomp(readFile(localRefFile)), htSHA1).gitRev());
|
||||||
|
|
||||||
|
// cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "rev-parse", "--is-shallow-repository" })) == "true";
|
bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "rev-parse", "--is-shallow-repository" })) == "true";
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
|
||||||
if ("PAT" == token.substr(0, fldsplit))
|
if ("PAT" == token.substr(0, fldsplit))
|
||||||
return std::make_pair("Private-token", token.substr(fldsplit+1));
|
return std::make_pair("Private-token", token.substr(fldsplit+1));
|
||||||
warn("Unrecognized GitLab token type %s", token.substr(0, fldsplit));
|
warn("Unrecognized GitLab token type %s", token.substr(0, fldsplit));
|
||||||
return std::nullopt;
|
return std::make_pair(token.substr(0,fldsplit), token.substr(fldsplit+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
|
||||||
|
|
|
||||||
|
|
@ -308,16 +308,17 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, const string & name,
|
StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair)
|
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references)
|
||||||
{
|
{
|
||||||
if (method != FileIngestionMethod::Recursive || hashAlgo != htSHA256)
|
if (method != FileIngestionMethod::Recursive || hashAlgo != htSHA256)
|
||||||
unsupported("addToStoreFromDump");
|
unsupported("addToStoreFromDump");
|
||||||
return addToStoreCommon(dump, repair, CheckSigs, [&](HashResult nar) {
|
return addToStoreCommon(dump, repair, CheckSigs, [&](HashResult nar) {
|
||||||
ValidPathInfo info {
|
ValidPathInfo info {
|
||||||
makeFixedOutputPath(method, nar.first, name),
|
makeFixedOutputPath(method, nar.first, name, references),
|
||||||
nar.first,
|
nar.first,
|
||||||
};
|
};
|
||||||
info.narSize = nar.second;
|
info.narSize = nar.second;
|
||||||
|
info.references = references;
|
||||||
return info;
|
return info;
|
||||||
})->path;
|
})->path;
|
||||||
}
|
}
|
||||||
|
|
@ -385,7 +386,7 @@ void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
|
StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
|
||||||
FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair)
|
FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair, const StorePathSet & references)
|
||||||
{
|
{
|
||||||
/* FIXME: Make BinaryCacheStore::addToStoreCommon support
|
/* FIXME: Make BinaryCacheStore::addToStoreCommon support
|
||||||
non-recursive+sha256 so we can just use the default
|
non-recursive+sha256 so we can just use the default
|
||||||
|
|
@ -404,10 +405,11 @@ StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath
|
||||||
});
|
});
|
||||||
return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) {
|
return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) {
|
||||||
ValidPathInfo info {
|
ValidPathInfo info {
|
||||||
makeFixedOutputPath(method, h, name),
|
makeFixedOutputPath(method, h, name, references),
|
||||||
nar.first,
|
nar.first,
|
||||||
};
|
};
|
||||||
info.narSize = nar.second;
|
info.narSize = nar.second;
|
||||||
|
info.references = references;
|
||||||
info.ca = FixedOutputHash {
|
info.ca = FixedOutputHash {
|
||||||
.method = method,
|
.method = method,
|
||||||
.hash = h,
|
.hash = h,
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,11 @@ public:
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
||||||
|
|
||||||
StorePath addToStoreFromDump(Source & dump, const string & name,
|
StorePath addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair) override;
|
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references ) override;
|
||||||
|
|
||||||
StorePath addToStore(const string & name, const Path & srcPath,
|
StorePath addToStore(const string & name, const Path & srcPath,
|
||||||
FileIngestionMethod method, HashType hashAlgo,
|
FileIngestionMethod method, HashType hashAlgo,
|
||||||
PathFilter & filter, RepairFlag repair) override;
|
PathFilter & filter, RepairFlag repair, const StorePathSet & references) override;
|
||||||
|
|
||||||
StorePath addTextToStore(const string & name, const string & s,
|
StorePath addTextToStore(const string & name, const string & s,
|
||||||
const StorePathSet & references, RepairFlag repair) override;
|
const StorePathSet & references, RepairFlag repair) override;
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,7 @@ void LocalDerivationGoal::cleanupHookFinally()
|
||||||
void LocalDerivationGoal::cleanupPreChildKill()
|
void LocalDerivationGoal::cleanupPreChildKill()
|
||||||
{
|
{
|
||||||
sandboxMountNamespace = -1;
|
sandboxMountNamespace = -1;
|
||||||
|
sandboxUserNamespace = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -342,7 +343,7 @@ int childEntry(void * arg)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
static void linkOrCopy(const Path & from, const Path & to)
|
static void linkOrCopy(const Path & from, const Path & to)
|
||||||
{
|
{
|
||||||
if (link(from.c_str(), to.c_str()) == -1) {
|
if (link(from.c_str(), to.c_str()) == -1) {
|
||||||
|
|
@ -358,6 +359,7 @@ static void linkOrCopy(const Path & from, const Path & to)
|
||||||
copyPath(from, to);
|
copyPath(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void LocalDerivationGoal::startBuilder()
|
void LocalDerivationGoal::startBuilder()
|
||||||
|
|
@ -906,11 +908,14 @@ void LocalDerivationGoal::startBuilder()
|
||||||
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
||||||
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
|
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
|
||||||
|
|
||||||
/* Save the mount namespace of the child. We have to do this
|
/* Save the mount- and user namespace of the child. We have to do this
|
||||||
*before* the child does a chroot. */
|
*before* the child does a chroot. */
|
||||||
sandboxMountNamespace = open(fmt("/proc/%d/ns/mnt", (pid_t) pid).c_str(), O_RDONLY);
|
sandboxMountNamespace = open(fmt("/proc/%d/ns/mnt", (pid_t) pid).c_str(), O_RDONLY);
|
||||||
if (sandboxMountNamespace.get() == -1)
|
if (sandboxMountNamespace.get() == -1)
|
||||||
throw SysError("getting sandbox mount namespace");
|
throw SysError("getting sandbox mount namespace");
|
||||||
|
sandboxUserNamespace = open(fmt("/proc/%d/ns/user", (pid_t) pid).c_str(), O_RDONLY);
|
||||||
|
if (sandboxUserNamespace.get() == -1)
|
||||||
|
throw SysError("getting sandbox user namespace");
|
||||||
|
|
||||||
/* Signal the builder that we've updated its user namespace. */
|
/* Signal the builder that we've updated its user namespace. */
|
||||||
writeFull(userNamespaceSync.writeSide.get(), "1");
|
writeFull(userNamespaceSync.writeSide.get(), "1");
|
||||||
|
|
@ -918,7 +923,9 @@ void LocalDerivationGoal::startBuilder()
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#if __linux__
|
||||||
fallback:
|
fallback:
|
||||||
|
#endif
|
||||||
pid = startProcess([&]() {
|
pid = startProcess([&]() {
|
||||||
runChild();
|
runChild();
|
||||||
});
|
});
|
||||||
|
|
@ -1180,7 +1187,8 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
||||||
|
|
||||||
StorePath addToStore(const string & name, const Path & srcPath,
|
StorePath addToStore(const string & name, const Path & srcPath,
|
||||||
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
|
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
|
||||||
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) override
|
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair,
|
||||||
|
const StorePathSet & references = StorePathSet()) override
|
||||||
{ throw Error("addToStore"); }
|
{ throw Error("addToStore"); }
|
||||||
|
|
||||||
void addToStore(const ValidPathInfo & info, Source & narSource,
|
void addToStore(const ValidPathInfo & info, Source & narSource,
|
||||||
|
|
@ -1199,9 +1207,10 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePath addToStoreFromDump(Source & dump, const string & name,
|
StorePath addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override
|
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair,
|
||||||
|
const StorePathSet & references = StorePathSet()) override
|
||||||
{
|
{
|
||||||
auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair);
|
auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair, references);
|
||||||
goal.addDependency(path);
|
goal.addDependency(path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
@ -1419,7 +1428,7 @@ void LocalDerivationGoal::addDependency(const StorePath & path)
|
||||||
|
|
||||||
Path source = worker.store.Store::toRealPath(path);
|
Path source = worker.store.Store::toRealPath(path);
|
||||||
Path target = chrootRootDir + worker.store.printStorePath(path);
|
Path target = chrootRootDir + worker.store.printStorePath(path);
|
||||||
debug("bind-mounting %s -> %s", target, source);
|
debug("bind-mounting %s -> %s", source, target);
|
||||||
|
|
||||||
if (pathExists(target))
|
if (pathExists(target))
|
||||||
throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path));
|
throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path));
|
||||||
|
|
@ -1434,6 +1443,9 @@ void LocalDerivationGoal::addDependency(const StorePath & path)
|
||||||
child process.*/
|
child process.*/
|
||||||
Pid child(startProcess([&]() {
|
Pid child(startProcess([&]() {
|
||||||
|
|
||||||
|
if (usingUserNamespace && (setns(sandboxUserNamespace.get(), 0) == -1))
|
||||||
|
throw SysError("entering sandbox user namespace");
|
||||||
|
|
||||||
if (setns(sandboxMountNamespace.get(), 0) == -1)
|
if (setns(sandboxMountNamespace.get(), 0) == -1)
|
||||||
throw SysError("entering sandbox mount namespace");
|
throw SysError("entering sandbox mount namespace");
|
||||||
|
|
||||||
|
|
@ -1993,7 +2005,7 @@ void LocalDerivationGoal::runChild()
|
||||||
else if (drv->builder == "builtin:unpack-channel")
|
else if (drv->builder == "builtin:unpack-channel")
|
||||||
builtinUnpackChannel(drv2);
|
builtinUnpackChannel(drv2);
|
||||||
else
|
else
|
||||||
throw Error("unsupported builtin function '%1%'", string(drv->builder, 8));
|
throw Error("unsupported builtin builder '%1%'", string(drv->builder, 8));
|
||||||
_exit(0);
|
_exit(0);
|
||||||
} catch (std::exception & e) {
|
} catch (std::exception & e) {
|
||||||
writeFull(STDERR_FILENO, e.what() + std::string("\n"));
|
writeFull(STDERR_FILENO, e.what() + std::string("\n"));
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,10 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||||
/* Pipe for synchronising updates to the builder namespaces. */
|
/* Pipe for synchronising updates to the builder namespaces. */
|
||||||
Pipe userNamespaceSync;
|
Pipe userNamespaceSync;
|
||||||
|
|
||||||
/* The mount namespace of the builder, used to add additional
|
/* The mount namespace and user namespace of the builder, used to add additional
|
||||||
paths to the sandbox as a result of recursive Nix calls. */
|
paths to the sandbox as a result of recursive Nix calls. */
|
||||||
AutoCloseFD sandboxMountNamespace;
|
AutoCloseFD sandboxMountNamespace;
|
||||||
|
AutoCloseFD sandboxUserNamespace;
|
||||||
|
|
||||||
/* On Linux, whether we're doing the build in its own user
|
/* On Linux, whether we're doing the build in its own user
|
||||||
namespace. */
|
namespace. */
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,10 @@ ContentAddress parseContentAddress(std::string_view rawCa) {
|
||||||
|
|
||||||
ContentAddressMethod parseContentAddressMethod(std::string_view caMethod)
|
ContentAddressMethod parseContentAddressMethod(std::string_view caMethod)
|
||||||
{
|
{
|
||||||
std::string_view asPrefix {std::string{caMethod} + ":"};
|
std::string asPrefix = std::string{caMethod} + ":";
|
||||||
return parseContentAddressMethodPrefix(asPrefix);
|
// parseContentAddressMethodPrefix takes its argument by reference
|
||||||
|
std::string_view asPrefixView = asPrefix;
|
||||||
|
return parseContentAddressMethodPrefix(asPrefixView);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt)
|
std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt)
|
||||||
|
|
|
||||||
|
|
@ -403,9 +403,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
return store->queryPathInfo(path);
|
return store->queryPathInfo(path);
|
||||||
},
|
},
|
||||||
[&](FixedOutputHashMethod & fohm) {
|
[&](FixedOutputHashMethod & fohm) {
|
||||||
if (!refs.empty())
|
auto path = store->addToStoreFromDump(source, name, fohm.fileIngestionMethod, fohm.hashType, repair, refs);
|
||||||
throw UnimplementedError("cannot yet have refs with flat or nar-hashed data");
|
|
||||||
auto path = store->addToStoreFromDump(source, name, fohm.fileIngestionMethod, fohm.hashType, repair);
|
|
||||||
return store->queryPathInfo(path);
|
return store->queryPathInfo(path);
|
||||||
},
|
},
|
||||||
}, contentAddressMethod);
|
}, contentAddressMethod);
|
||||||
|
|
|
||||||
|
|
@ -544,6 +544,14 @@ struct curlFileTransfer : public FileTransfer
|
||||||
stopWorkerThread();
|
stopWorkerThread();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
/* Cause this thread to not share any FS attributes with the main thread,
|
||||||
|
because this causes setns() in restoreMountNamespace() to fail.
|
||||||
|
Ideally, this would happen in the std::thread() constructor. */
|
||||||
|
if (unshare(CLONE_FS) != 0)
|
||||||
|
throw SysError("unsharing filesystem state in download thread");
|
||||||
|
#endif
|
||||||
|
|
||||||
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@ static string quoteRegexChars(const string & raw)
|
||||||
return std::regex_replace(raw, specialRegex, R"(\$&)");
|
return std::regex_replace(raw, specialRegex, R"(\$&)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
static void readFileRoots(const char * path, UncheckedRoots & roots)
|
static void readFileRoots(const char * path, UncheckedRoots & roots)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -333,6 +334,7 @@ static void readFileRoots(const char * path, UncheckedRoots & roots)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
||||||
{
|
{
|
||||||
|
|
@ -414,7 +416,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if __linux__
|
||||||
readFileRoots("/proc/sys/kernel/modprobe", unchecked);
|
readFileRoots("/proc/sys/kernel/modprobe", unchecked);
|
||||||
readFileRoots("/proc/sys/kernel/fbsplash", unchecked);
|
readFileRoots("/proc/sys/kernel/fbsplash", unchecked);
|
||||||
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
|
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
|
||||||
|
|
|
||||||
|
|
@ -951,6 +951,9 @@ public:
|
||||||
|
|
||||||
Setting<bool> useRegistries{this, true, "use-registries",
|
Setting<bool> useRegistries{this, true, "use-registries",
|
||||||
"Whether to use flake registries to resolve flake references."};
|
"Whether to use flake registries to resolve flake references."};
|
||||||
|
|
||||||
|
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
|
||||||
|
"Whether to accept nix configuration from a flake without prompting."};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
|
||||||
|
|
||||||
StorePath addToStore(const string & name, const Path & srcPath,
|
StorePath addToStore(const string & name, const Path & srcPath,
|
||||||
FileIngestionMethod method, HashType hashAlgo,
|
FileIngestionMethod method, HashType hashAlgo,
|
||||||
PathFilter & filter, RepairFlag repair) override
|
PathFilter & filter, RepairFlag repair, const StorePathSet & references) override
|
||||||
{ unsupported("addToStore"); }
|
{ unsupported("addToStore"); }
|
||||||
|
|
||||||
StorePath addTextToStore(const string & name, const string & s,
|
StorePath addTextToStore(const string & name, const string & s,
|
||||||
|
|
|
||||||
|
|
@ -504,9 +504,6 @@ void LocalStore::makeStoreWritable()
|
||||||
throw SysError("getting info about the Nix store mount point");
|
throw SysError("getting info about the Nix store mount point");
|
||||||
|
|
||||||
if (stat.f_flag & ST_RDONLY) {
|
if (stat.f_flag & ST_RDONLY) {
|
||||||
if (unshare(CLONE_NEWNS) == -1)
|
|
||||||
throw SysError("setting up a private mount namespace");
|
|
||||||
|
|
||||||
if (mount(0, realStoreDir.get().c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
|
if (mount(0, realStoreDir.get().c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
|
||||||
throw SysError("remounting %1% writable", realStoreDir);
|
throw SysError("remounting %1% writable", realStoreDir);
|
||||||
}
|
}
|
||||||
|
|
@ -1311,7 +1308,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
||||||
|
|
||||||
|
|
||||||
StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
||||||
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair)
|
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references)
|
||||||
{
|
{
|
||||||
/* For computing the store path. */
|
/* For computing the store path. */
|
||||||
auto hashSink = std::make_unique<HashSink>(hashAlgo);
|
auto hashSink = std::make_unique<HashSink>(hashAlgo);
|
||||||
|
|
@ -1367,7 +1364,7 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
||||||
|
|
||||||
auto [hash, size] = hashSink->finish();
|
auto [hash, size] = hashSink->finish();
|
||||||
|
|
||||||
auto dstPath = makeFixedOutputPath(method, hash, name);
|
auto dstPath = makeFixedOutputPath(method, hash, name, references);
|
||||||
|
|
||||||
addTempRoot(dstPath);
|
addTempRoot(dstPath);
|
||||||
|
|
||||||
|
|
@ -1414,6 +1411,7 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, const string & name,
|
||||||
|
|
||||||
ValidPathInfo info { dstPath, narHash.first };
|
ValidPathInfo info { dstPath, narHash.first };
|
||||||
info.narSize = narHash.second;
|
info.narSize = narHash.second;
|
||||||
|
info.references = references;
|
||||||
info.ca = FixedOutputHash { .method = method, .hash = hash };
|
info.ca = FixedOutputHash { .method = method, .hash = hash };
|
||||||
registerValidPath(info);
|
registerValidPath(info);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ public:
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
||||||
|
|
||||||
StorePath addToStoreFromDump(Source & dump, const string & name,
|
StorePath addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair) override;
|
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override;
|
||||||
|
|
||||||
StorePath addTextToStore(const string & name, const string & s,
|
StorePath addTextToStore(const string & name, const string & s,
|
||||||
const StorePathSet & references, RepairFlag repair) override;
|
const StorePathSet & references, RepairFlag repair) override;
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,12 @@ void RefScanSink::operator () (std::string_view data)
|
||||||
fragment, so search in the concatenation of the tail of the
|
fragment, so search in the concatenation of the tail of the
|
||||||
previous fragment and the start of the current fragment. */
|
previous fragment and the start of the current fragment. */
|
||||||
auto s = tail;
|
auto s = tail;
|
||||||
s.append(data.data(), refLength);
|
auto tailLen = std::min(data.size(), refLength);
|
||||||
|
s.append(data.data(), tailLen);
|
||||||
search(s, hashes, seen);
|
search(s, hashes, seen);
|
||||||
|
|
||||||
search(data, hashes, seen);
|
search(data, hashes, seen);
|
||||||
|
|
||||||
auto tailLen = std::min(data.size(), refLength);
|
|
||||||
auto rest = refLength - tailLen;
|
auto rest = refLength - tailLen;
|
||||||
if (rest < tail.size())
|
if (rest < tail.size())
|
||||||
tail = tail.substr(tail.size() - rest);
|
tail = tail.substr(tail.size() - rest);
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,10 @@ ConnectionHandle RemoteStore::getConnection()
|
||||||
return ConnectionHandle(connections->get());
|
return ConnectionHandle(connections->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteStore::setOptions()
|
||||||
|
{
|
||||||
|
setOptions(*(getConnection().handle));
|
||||||
|
}
|
||||||
|
|
||||||
bool RemoteStore::isValidPathUncached(const StorePath & path)
|
bool RemoteStore::isValidPathUncached(const StorePath & path)
|
||||||
{
|
{
|
||||||
|
|
@ -578,9 +582,8 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
|
||||||
|
|
||||||
|
|
||||||
StorePath RemoteStore::addToStoreFromDump(Source & dump, const string & name,
|
StorePath RemoteStore::addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method, HashType hashType, RepairFlag repair)
|
FileIngestionMethod method, HashType hashType, RepairFlag repair, const StorePathSet & references)
|
||||||
{
|
{
|
||||||
StorePathSet references;
|
|
||||||
return addCAToStore(dump, name, FixedOutputHashMethod{ .fileIngestionMethod = method, .hashType = hashType }, references, repair)->path;
|
return addCAToStore(dump, name, FixedOutputHashMethod{ .fileIngestionMethod = method, .hashType = hashType }, references, repair)->path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public:
|
||||||
|
|
||||||
/* Add a content-addressable store path. Does not support references. `dump` will be drained. */
|
/* Add a content-addressable store path. Does not support references. `dump` will be drained. */
|
||||||
StorePath addToStoreFromDump(Source & dump, const string & name,
|
StorePath addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override;
|
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet()) override;
|
||||||
|
|
||||||
void addToStore(const ValidPathInfo & info, Source & nar,
|
void addToStore(const ValidPathInfo & info, Source & nar,
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
RepairFlag repair, CheckSigsFlag checkSigs) override;
|
||||||
|
|
@ -148,6 +148,8 @@ protected:
|
||||||
|
|
||||||
virtual void setOptions(Connection & conn);
|
virtual void setOptions(Connection & conn);
|
||||||
|
|
||||||
|
void setOptions() override;
|
||||||
|
|
||||||
ConnectionHandle getConnection();
|
ConnectionHandle getConnection();
|
||||||
|
|
||||||
friend struct ConnectionHandle;
|
friend struct ConnectionHandle;
|
||||||
|
|
|
||||||
|
|
@ -100,4 +100,5 @@
|
||||||
|
|
||||||
; Allow Rosetta 2 to run x86_64 binaries on aarch64-darwin.
|
; Allow Rosetta 2 to run x86_64 binaries on aarch64-darwin.
|
||||||
(allow file-read*
|
(allow file-read*
|
||||||
(subpath "/Library/Apple/usr/libexec/oah"))
|
(subpath "/Library/Apple/usr/libexec/oah")
|
||||||
|
(subpath "/System/Library/Apple/usr/libexec/oah"))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "sqlite.hh"
|
#include "sqlite.hh"
|
||||||
|
#include "globals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
@ -27,8 +28,12 @@ namespace nix {
|
||||||
|
|
||||||
SQLite::SQLite(const Path & path, bool create)
|
SQLite::SQLite(const Path & path, bool create)
|
||||||
{
|
{
|
||||||
|
// useSQLiteWAL also indicates what virtual file system we need. Using
|
||||||
|
// `unix-dotfile` is needed on NFS file systems and on Windows' Subsystem
|
||||||
|
// for Linux (WSL) where useSQLiteWAL should be false by default.
|
||||||
|
const char *vfs = settings.useSQLiteWAL ? 0 : "unix-dotfile";
|
||||||
if (sqlite3_open_v2(path.c_str(), &db,
|
if (sqlite3_open_v2(path.c_str(), &db,
|
||||||
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
|
SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), vfs) != SQLITE_OK)
|
||||||
throw Error("cannot open SQLite database '%s'", path);
|
throw Error("cannot open SQLite database '%s'", path);
|
||||||
|
|
||||||
if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
|
if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ StorePath Store::computeStorePathForText(const string & name, const string & s,
|
||||||
|
|
||||||
|
|
||||||
StorePath Store::addToStore(const string & name, const Path & _srcPath,
|
StorePath Store::addToStore(const string & name, const Path & _srcPath,
|
||||||
FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair)
|
FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair, const StorePathSet & references)
|
||||||
{
|
{
|
||||||
Path srcPath(absPath(_srcPath));
|
Path srcPath(absPath(_srcPath));
|
||||||
auto source = sinkToSource([&](Sink & sink) {
|
auto source = sinkToSource([&](Sink & sink) {
|
||||||
|
|
@ -246,7 +246,7 @@ StorePath Store::addToStore(const string & name, const Path & _srcPath,
|
||||||
else
|
else
|
||||||
readFile(srcPath, sink);
|
readFile(srcPath, sink);
|
||||||
});
|
});
|
||||||
return addToStoreFromDump(*source, name, method, hashAlgo, repair);
|
return addToStoreFromDump(*source, name, method, hashAlgo, repair, references);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -460,7 +460,7 @@ public:
|
||||||
libutil/archive.hh). */
|
libutil/archive.hh). */
|
||||||
virtual StorePath addToStore(const string & name, const Path & srcPath,
|
virtual StorePath addToStore(const string & name, const Path & srcPath,
|
||||||
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
|
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
|
||||||
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair);
|
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet());
|
||||||
|
|
||||||
/* Copy the contents of a path to the store and register the
|
/* Copy the contents of a path to the store and register the
|
||||||
validity the resulting path, using a constant amount of
|
validity the resulting path, using a constant amount of
|
||||||
|
|
@ -476,7 +476,8 @@ public:
|
||||||
`dump` may be drained */
|
`dump` may be drained */
|
||||||
// FIXME: remove?
|
// FIXME: remove?
|
||||||
virtual StorePath addToStoreFromDump(Source & dump, const string & name,
|
virtual StorePath addToStoreFromDump(Source & dump, const string & name,
|
||||||
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair)
|
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair,
|
||||||
|
const StorePathSet & references = StorePathSet())
|
||||||
{ unsupported("addToStoreFromDump"); }
|
{ unsupported("addToStoreFromDump"); }
|
||||||
|
|
||||||
/* Like addToStore, but the contents written to the output path is
|
/* Like addToStore, but the contents written to the output path is
|
||||||
|
|
@ -732,6 +733,11 @@ public:
|
||||||
virtual void createUser(const std::string & userName, uid_t userId)
|
virtual void createUser(const std::string & userName, uid_t userId)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronises the options of the client with those of the daemon
|
||||||
|
* (a no-op when there’s no daemon)
|
||||||
|
*/
|
||||||
|
virtual void setOptions() { }
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Stats stats;
|
Stats stats;
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,7 @@ Path getConfigDir()
|
||||||
std::vector<Path> getConfigDirs()
|
std::vector<Path> getConfigDirs()
|
||||||
{
|
{
|
||||||
Path configHome = getConfigDir();
|
Path configHome = getConfigDir();
|
||||||
string configDirs = getEnv("XDG_CONFIG_DIRS").value_or("");
|
string configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg");
|
||||||
std::vector<Path> result = tokenizeString<std::vector<string>>(configDirs, ":");
|
std::vector<Path> result = tokenizeString<std::vector<string>>(configDirs, ":");
|
||||||
result.insert(result.begin(), configHome);
|
result.insert(result.begin(), configHome);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1632,9 +1632,39 @@ void setStackSize(size_t stackSize)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void restoreProcessContext()
|
static AutoCloseFD fdSavedMountNamespace;
|
||||||
|
|
||||||
|
void saveMountNamespace()
|
||||||
|
{
|
||||||
|
#if __linux__
|
||||||
|
static std::once_flag done;
|
||||||
|
std::call_once(done, []() {
|
||||||
|
AutoCloseFD fd = open("/proc/self/ns/mnt", O_RDONLY);
|
||||||
|
if (!fd)
|
||||||
|
throw SysError("saving parent mount namespace");
|
||||||
|
fdSavedMountNamespace = std::move(fd);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreMountNamespace()
|
||||||
|
{
|
||||||
|
#if __linux__
|
||||||
|
try {
|
||||||
|
if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1)
|
||||||
|
throw SysError("restoring parent mount namespace");
|
||||||
|
} catch (Error & e) {
|
||||||
|
debug(e.msg());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreProcessContext(bool restoreMounts)
|
||||||
{
|
{
|
||||||
restoreSignals();
|
restoreSignals();
|
||||||
|
if (restoreMounts) {
|
||||||
|
restoreMountNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
restoreAffinity();
|
restoreAffinity();
|
||||||
|
|
||||||
|
|
@ -1774,7 +1804,7 @@ void commonChildInit(Pipe & logPipe)
|
||||||
logger = makeSimpleLogger();
|
logger = makeSimpleLogger();
|
||||||
|
|
||||||
const static string pathNullDevice = "/dev/null";
|
const static string pathNullDevice = "/dev/null";
|
||||||
restoreProcessContext();
|
restoreProcessContext(false);
|
||||||
|
|
||||||
/* Put the child in a separate session (and thus a separate
|
/* Put the child in a separate session (and thus a separate
|
||||||
process group) so that it has no controlling terminal (meaning
|
process group) so that it has no controlling terminal (meaning
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,15 @@ void setStackSize(size_t stackSize);
|
||||||
|
|
||||||
/* Restore the original inherited Unix process context (such as signal
|
/* Restore the original inherited Unix process context (such as signal
|
||||||
masks, stack size, CPU affinity). */
|
masks, stack size, CPU affinity). */
|
||||||
void restoreProcessContext();
|
void restoreProcessContext(bool restoreMounts = true);
|
||||||
|
|
||||||
|
/* Save the current mount namespace. Ignored if called more than
|
||||||
|
once. */
|
||||||
|
void saveMountNamespace();
|
||||||
|
|
||||||
|
/* Restore the mount namespace saved by saveMountNamespace(). Ignored
|
||||||
|
if saveMountNamespace() was never called. */
|
||||||
|
void restoreMountNamespace();
|
||||||
|
|
||||||
|
|
||||||
class ExecError : public Error
|
class ExecError : public Error
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
|
|
||||||
// List of environment variables kept for --pure
|
// List of environment variables kept for --pure
|
||||||
std::set<string> keepVars{
|
std::set<string> keepVars{
|
||||||
"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL",
|
"HOME", "XDG_RUNTIME_DIR", "USER", "LOGNAME", "DISPLAY",
|
||||||
|
"WAYLAND_DISPLAY", "WAYLAND_SOCKET", "PATH", "TERM", "IN_NIX_SHELL",
|
||||||
"NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
|
"NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
|
||||||
"http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy"
|
"http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy"
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -879,7 +879,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
|
||||||
placeholder.write(nullptr);
|
placeholder.write(nullptr);
|
||||||
} else {
|
} else {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
printValueAsJSON(*globals.state, true, *v, placeholder, context);
|
printValueAsJSON(*globals.state, true, *v, noPos, placeholder, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
else
|
else
|
||||||
state.autoCallFunction(autoArgs, v, vRes);
|
state.autoCallFunction(autoArgs, v, vRes);
|
||||||
if (output == okXML)
|
if (output == okXML)
|
||||||
printValueAsXML(state, strict, location, vRes, std::cout, context);
|
printValueAsXML(state, strict, location, vRes, std::cout, context, noPos);
|
||||||
else if (output == okJSON)
|
else if (output == okJSON)
|
||||||
printValueAsJSON(state, strict, vRes, std::cout, context);
|
printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context);
|
||||||
else {
|
else {
|
||||||
if (strict) state.forceValueDeep(vRes);
|
if (strict) state.forceValueDeep(vRes);
|
||||||
std::cout << vRes << std::endl;
|
std::cout << vRes << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ struct CmdEval : MixJSON, InstallableCommand
|
||||||
|
|
||||||
else if (json) {
|
else if (json) {
|
||||||
JSONPlaceholder jsonOut(std::cout);
|
JSONPlaceholder jsonOut(std::cout);
|
||||||
printValueAsJSON(*state, true, *v, jsonOut, context);
|
printValueAsJSON(*state, true, *v, pos, jsonOut, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -31,38 +31,38 @@ at the first error.
|
||||||
The following flake output attributes must be derivations:
|
The following flake output attributes must be derivations:
|
||||||
|
|
||||||
* `checks.`*system*`.`*name*
|
* `checks.`*system*`.`*name*
|
||||||
* `defaultPackage.`*system*`
|
* `defaultPackage.`*system*
|
||||||
* `devShell.`*system*`
|
* `devShell.`*system*
|
||||||
* `devShells.`*system*`.`*name*`
|
* `devShells.`*system*`.`*name*
|
||||||
* `nixosConfigurations.`*name*`.config.system.build.toplevel
|
* `nixosConfigurations.`*name*`.config.system.build.toplevel`
|
||||||
* `packages.`*system*`.`*name*
|
* `packages.`*system*`.`*name*
|
||||||
|
|
||||||
The following flake output attributes must be [app
|
The following flake output attributes must be [app
|
||||||
definitions](./nix3-run.md):
|
definitions](./nix3-run.md):
|
||||||
|
|
||||||
* `apps.`*system*`.`*name*
|
* `apps.`*system*`.`*name*
|
||||||
* `defaultApp.`*system*`
|
* `defaultApp.`*system*
|
||||||
|
|
||||||
The following flake output attributes must be [template
|
The following flake output attributes must be [template
|
||||||
definitions](./nix3-flake-init.md):
|
definitions](./nix3-flake-init.md):
|
||||||
|
|
||||||
* `defaultTemplate`
|
* `defaultTemplate`
|
||||||
* `templates`.`*name*
|
* `templates.`*name*
|
||||||
|
|
||||||
The following flake output attributes must be *Nixpkgs overlays*:
|
The following flake output attributes must be *Nixpkgs overlays*:
|
||||||
|
|
||||||
* `overlay`
|
* `overlay`
|
||||||
* `overlays`.`*name*
|
* `overlays.`*name*
|
||||||
|
|
||||||
The following flake output attributes must be *NixOS modules*:
|
The following flake output attributes must be *NixOS modules*:
|
||||||
|
|
||||||
* `nixosModule`
|
* `nixosModule`
|
||||||
* `nixosModules`.`*name*
|
* `nixosModules.`*name*
|
||||||
|
|
||||||
The following flake output attributes must be
|
The following flake output attributes must be
|
||||||
[bundlers](./nix3-bundle.md):
|
[bundlers](./nix3-bundle.md):
|
||||||
|
|
||||||
* `bundlers`.`*name*
|
* `bundlers.`*name*
|
||||||
* `defaultBundler`
|
* `defaultBundler`
|
||||||
|
|
||||||
In addition, the `hydraJobs` output is evaluated in the same way as
|
In addition, the `hydraJobs` output is evaluated in the same way as
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,14 @@ struct CmdFlakeInfo : CmdFlakeMetadata
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool argHasName(std::string_view arg, std::string_view expected)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
arg == expected
|
||||||
|
|| arg == "_"
|
||||||
|
|| (hasPrefix(arg, "_") && arg.substr(1) == expected);
|
||||||
|
}
|
||||||
|
|
||||||
struct CmdFlakeCheck : FlakeCommand
|
struct CmdFlakeCheck : FlakeCommand
|
||||||
{
|
{
|
||||||
bool build = true;
|
bool build = true;
|
||||||
|
|
@ -346,10 +354,14 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
state->forceValue(v, pos);
|
state->forceValue(v, pos);
|
||||||
if (!v.isLambda() || v.lambda.fun->hasFormals() || std::string(v.lambda.fun->arg) != "final")
|
if (!v.isLambda()
|
||||||
|
|| v.lambda.fun->hasFormals()
|
||||||
|
|| !argHasName(v.lambda.fun->arg, "final"))
|
||||||
throw Error("overlay does not take an argument named 'final'");
|
throw Error("overlay does not take an argument named 'final'");
|
||||||
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
|
auto body = dynamic_cast<ExprLambda *>(v.lambda.fun->body);
|
||||||
if (!body || body->hasFormals() || std::string(body->arg) != "prev")
|
if (!body
|
||||||
|
|| body->hasFormals()
|
||||||
|
|| !argHasName(body->arg, "prev"))
|
||||||
throw Error("overlay does not take an argument named 'prev'");
|
throw Error("overlay does not take an argument named 'prev'");
|
||||||
// FIXME: if we have a 'nixpkgs' input, use it to
|
// FIXME: if we have a 'nixpkgs' input, use it to
|
||||||
// evaluate the overlay.
|
// evaluate the overlay.
|
||||||
|
|
@ -1040,7 +1052,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|
||||||
(attrPath.size() == 1 && attrPath[0] == "overlay")
|
(attrPath.size() == 1 && attrPath[0] == "overlay")
|
||||||
|| (attrPath.size() == 2 && attrPath[0] == "overlays") ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") :
|
|| (attrPath.size() == 2 && attrPath[0] == "overlays") ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") :
|
||||||
attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? std::make_pair("nixos-configuration", "NixOS configuration") :
|
attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? std::make_pair("nixos-configuration", "NixOS configuration") :
|
||||||
attrPath.size() == 2 && attrPath[0] == "nixosModules" ? std::make_pair("nixos-module", "NixOS module") :
|
(attrPath.size() == 1 && attrPath[0] == "nixosModule")
|
||||||
|
|| (attrPath.size() == 2 && attrPath[0] == "nixosModules") ? std::make_pair("nixos-module", "NixOS module") :
|
||||||
std::make_pair("unknown", "unknown");
|
std::make_pair("unknown", "unknown");
|
||||||
if (json) {
|
if (json) {
|
||||||
j.emplace("type", type);
|
j.emplace("type", type);
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,16 @@ void mainWrapped(int argc, char * * argv)
|
||||||
initNix();
|
initNix();
|
||||||
initGC();
|
initGC();
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
|
if (getuid() == 0) {
|
||||||
|
try {
|
||||||
|
saveMountNamespace();
|
||||||
|
if (unshare(CLONE_NEWNS) == -1)
|
||||||
|
throw SysError("setting up a private mount namespace");
|
||||||
|
} catch (Error & e) { }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
programPath = argv[0];
|
programPath = argv[0];
|
||||||
auto programName = std::string(baseNameOf(programPath));
|
auto programName = std::string(baseNameOf(programPath));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,7 @@ struct CmdRegistry : virtual NixMultiCommand
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
|
settings.requireExperimentalFeature(Xp::Flakes);
|
||||||
if (!command)
|
if (!command)
|
||||||
throw UsageError("'nix registry' requires a sub-command.");
|
throw UsageError("'nix registry' requires a sub-command.");
|
||||||
command->second->prepare();
|
command->second->prepare();
|
||||||
|
|
|
||||||
|
|
@ -471,7 +471,10 @@ bool NixRepl::processLine(string line)
|
||||||
auto args = editorFor(pos);
|
auto args = editorFor(pos);
|
||||||
auto editor = args.front();
|
auto editor = args.front();
|
||||||
args.pop_front();
|
args.pop_front();
|
||||||
runProgram(editor, true, args);
|
|
||||||
|
// runProgram redirects stdout to a StringSink,
|
||||||
|
// using runProgram2 to allow editors to display their UI
|
||||||
|
runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args });
|
||||||
|
|
||||||
// Reload right after exiting the editor
|
// Reload right after exiting the editor
|
||||||
state->resetFileCache();
|
state->resetFileCache();
|
||||||
|
|
@ -504,8 +507,8 @@ bool NixRepl::processLine(string line)
|
||||||
state->store->buildPaths({DerivedPath::Built{drvPath}});
|
state->store->buildPaths({DerivedPath::Built{drvPath}});
|
||||||
auto drv = state->store->readDerivation(drvPath);
|
auto drv = state->store->readDerivation(drvPath);
|
||||||
logger->cout("\nThis derivation produced the following outputs:");
|
logger->cout("\nThis derivation produced the following outputs:");
|
||||||
for (auto & i : drv.outputsAndOptPaths(*state->store))
|
for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath))
|
||||||
logger->cout(" %s -> %s", i.first, state->store->printStorePath(*i.second.second));
|
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
||||||
} else if (command == ":i") {
|
} else if (command == ":i") {
|
||||||
runNix("nix-env", {"-i", drvPathRaw});
|
runNix("nix-env", {"-i", drvPathRaw});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -644,7 +647,8 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v)
|
||||||
{
|
{
|
||||||
if (displ >= envSize)
|
if (displ >= envSize)
|
||||||
throw Error("environment full; cannot add more variables");
|
throw Error("environment full; cannot add more variables");
|
||||||
staticEnv.vars[name] = displ;
|
staticEnv.vars.emplace_back(name, displ);
|
||||||
|
staticEnv.sort();
|
||||||
env->values[displ++] = &v;
|
env->values[displ++] = &v;
|
||||||
varNames.insert((string) name);
|
varNames.insert((string) name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,7 @@ struct CmdKey : NixMultiCommand
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
if (!command)
|
if (!command)
|
||||||
throw UsageError("'nix flake' requires a sub-command.");
|
throw UsageError("'nix key' requires a sub-command.");
|
||||||
settings.requireExperimentalFeature(Xp::Flakes);
|
|
||||||
command->second->prepare();
|
command->second->prepare();
|
||||||
command->second->run();
|
command->second->run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
tests/ca/repl.sh
Normal file
5
tests/ca/repl.sh
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
source common.sh
|
||||||
|
|
||||||
|
export NIX_TESTS_CA_BY_DEFAULT=1
|
||||||
|
|
||||||
|
cd .. && source repl.sh
|
||||||
|
|
@ -36,8 +36,9 @@ export PATH=@bindir@:$PATH
|
||||||
if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
|
if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
|
||||||
export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH
|
export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH
|
||||||
fi
|
fi
|
||||||
|
DAEMON_PATH="$PATH"
|
||||||
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
|
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
|
||||||
export NIX_DAEMON_COMMAND="$NIX_DAEMON_PACKAGE/bin/nix-daemon"
|
DAEMON_PATH="${NIX_DAEMON_PACKAGE}/bin:$DAEMON_PATH"
|
||||||
fi
|
fi
|
||||||
coreutils=@coreutils@
|
coreutils=@coreutils@
|
||||||
|
|
||||||
|
|
@ -89,7 +90,7 @@ startDaemon() {
|
||||||
# Start the daemon, wait for the socket to appear. !!!
|
# Start the daemon, wait for the socket to appear. !!!
|
||||||
# ‘nix-daemon’ should have an option to fork into the background.
|
# ‘nix-daemon’ should have an option to fork into the background.
|
||||||
rm -f $NIX_DAEMON_SOCKET_PATH
|
rm -f $NIX_DAEMON_SOCKET_PATH
|
||||||
${NIX_DAEMON_COMMAND:-nix daemon} &
|
PATH=$DAEMON_PATH nix daemon &
|
||||||
for ((i = 0; i < 30; i++)); do
|
for ((i = 0; i < 30; i++)); do
|
||||||
if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then break; fi
|
if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then break; fi
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
|
||||||
34
tests/flake-local-settings.sh
Normal file
34
tests/flake-local-settings.sh
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
source common.sh
|
||||||
|
|
||||||
|
clearStore
|
||||||
|
rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
|
||||||
|
|
||||||
|
cp ./simple.nix ./simple.builder.sh ./config.nix $TEST_HOME
|
||||||
|
|
||||||
|
cd $TEST_HOME
|
||||||
|
|
||||||
|
rm -f post-hook-ran
|
||||||
|
cat <<EOF > echoing-post-hook.sh
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "ThePostHookRan" > $PWD/post-hook-ran
|
||||||
|
EOF
|
||||||
|
chmod +x echoing-post-hook.sh
|
||||||
|
|
||||||
|
cat <<EOF > flake.nix
|
||||||
|
{
|
||||||
|
nixConfig.post-build-hook = "$PWD/echoing-post-hook.sh";
|
||||||
|
|
||||||
|
outputs = a: {
|
||||||
|
defaultPackage.$system = import ./simple.nix;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Without --accept-flake-config, the post hook should not run.
|
||||||
|
nix build < /dev/null
|
||||||
|
(! [[ -f post-hook-ran ]])
|
||||||
|
clearStore
|
||||||
|
|
||||||
|
nix build --accept-flake-config
|
||||||
|
test -f post-hook-ran || fail "The post hook should have ran"
|
||||||
|
|
@ -707,10 +707,10 @@ cat > $flakeFollowsA/flake.nix <<EOF
|
||||||
B = {
|
B = {
|
||||||
url = "path:./flakeB";
|
url = "path:./flakeB";
|
||||||
inputs.foobar.follows = "D";
|
inputs.foobar.follows = "D";
|
||||||
|
inputs.nonFlake.follows = "D";
|
||||||
};
|
};
|
||||||
|
|
||||||
D.url = "path:./flakeD";
|
D.url = "path:./flakeD";
|
||||||
foobar.url = "path:./flakeE";
|
|
||||||
};
|
};
|
||||||
outputs = { ... }: {};
|
outputs = { ... }: {};
|
||||||
}
|
}
|
||||||
|
|
@ -720,7 +720,8 @@ cat > $flakeFollowsB/flake.nix <<EOF
|
||||||
{
|
{
|
||||||
description = "Flake B";
|
description = "Flake B";
|
||||||
inputs = {
|
inputs = {
|
||||||
foobar.url = "path:./../flakeE";
|
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||||
|
nonFlake.url = "path:$nonFlakeDir";
|
||||||
C = {
|
C = {
|
||||||
url = "path:./flakeC";
|
url = "path:./flakeC";
|
||||||
inputs.foobar.follows = "foobar";
|
inputs.foobar.follows = "foobar";
|
||||||
|
|
@ -734,7 +735,7 @@ cat > $flakeFollowsC/flake.nix <<EOF
|
||||||
{
|
{
|
||||||
description = "Flake C";
|
description = "Flake C";
|
||||||
inputs = {
|
inputs = {
|
||||||
foobar.url = "path:./../../flakeE";
|
foobar.url = "path:$flakeFollowsA/flakeE";
|
||||||
};
|
};
|
||||||
outputs = { ... }: {};
|
outputs = { ... }: {};
|
||||||
}
|
}
|
||||||
|
|
@ -765,6 +766,27 @@ nix flake lock $flakeFollowsA
|
||||||
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
|
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
|
||||||
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
|
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
|
||||||
|
|
||||||
|
# Ensure removing follows from flake.nix removes them from the lockfile
|
||||||
|
|
||||||
|
cat > $flakeFollowsA/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
description = "Flake A";
|
||||||
|
inputs = {
|
||||||
|
B = {
|
||||||
|
url = "path:./flakeB";
|
||||||
|
inputs.nonFlake.follows = "D";
|
||||||
|
};
|
||||||
|
D.url = "path:./flakeD";
|
||||||
|
};
|
||||||
|
outputs = { ... }: {};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
nix flake lock $flakeFollowsA
|
||||||
|
|
||||||
|
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '"foobar"' ]]
|
||||||
|
jq -r -c '.nodes | keys | .[]' $flakeFollowsA/flake.lock | grep "^foobar$"
|
||||||
|
|
||||||
# Ensure a relative path is not allowed to go outside the store path
|
# Ensure a relative path is not allowed to go outside the store path
|
||||||
cat > $flakeFollowsA/flake.nix <<EOF
|
cat > $flakeFollowsA/flake.nix <<EOF
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,6 @@ function-trace exited (string):1:1 at
|
||||||
expect_trace '(x: x) 1 2' "
|
expect_trace '(x: x) 1 2' "
|
||||||
function-trace entered (string):1:1 at
|
function-trace entered (string):1:1 at
|
||||||
function-trace exited (string):1:1 at
|
function-trace exited (string):1:1 at
|
||||||
function-trace entered (string):1:1 at
|
|
||||||
function-trace exited (string):1:1 at
|
|
||||||
"
|
"
|
||||||
|
|
||||||
# Not a function
|
# Not a function
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
[ [ 42 77 147 249 483 526 ] [ 526 483 249 147 77 42 ] [ "bar" "fnord" "foo" "xyzzy" ] [ { key = 1; value = "foo"; } { key = 1; value = "fnord"; } { key = 2; value = "bar"; } ] ]
|
[ [ 42 77 147 249 483 526 ] [ 526 483 249 147 77 42 ] [ "bar" "fnord" "foo" "xyzzy" ] [ { key = 1; value = "foo"; } { key = 1; value = "fnord"; } { key = 2; value = "bar"; } ] [ [ ] [ ] [ 1 ] [ 1 4 ] [ 1 5 ] [ 1 6 ] [ 2 ] [ 2 3 ] [ 3 ] [ 3 ] ] ]
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,17 @@ with builtins;
|
||||||
(sort (x: y: y < x) [ 483 249 526 147 42 77 ])
|
(sort (x: y: y < x) [ 483 249 526 147 42 77 ])
|
||||||
(sort lessThan [ "foo" "bar" "xyzzy" "fnord" ])
|
(sort lessThan [ "foo" "bar" "xyzzy" "fnord" ])
|
||||||
(sort (x: y: x.key < y.key)
|
(sort (x: y: x.key < y.key)
|
||||||
[ { key = 1; value = "foo"; } { key = 2; value = "bar"; } { key = 1; value = "fnord"; } ])
|
[ { key = 1; value = "foo"; } { key = 2; value = "bar"; } { key = 1; value = "fnord"; } ])
|
||||||
|
(sort lessThan [
|
||||||
|
[ 1 6 ]
|
||||||
|
[ ]
|
||||||
|
[ 2 3 ]
|
||||||
|
[ 3 ]
|
||||||
|
[ 1 5 ]
|
||||||
|
[ 2 ]
|
||||||
|
[ 1 ]
|
||||||
|
[ ]
|
||||||
|
[ 1 4 ]
|
||||||
|
[ 3 ]
|
||||||
|
])
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,10 @@ nix_tests = \
|
||||||
recursive.sh \
|
recursive.sh \
|
||||||
describe-stores.sh \
|
describe-stores.sh \
|
||||||
flakes.sh \
|
flakes.sh \
|
||||||
|
flake-local-settings.sh \
|
||||||
build.sh \
|
build.sh \
|
||||||
compute-levels.sh \
|
compute-levels.sh \
|
||||||
repl.sh \
|
repl.sh ca/repl.sh \
|
||||||
ca/build.sh \
|
ca/build.sh \
|
||||||
ca/build-with-garbage-path.sh \
|
ca/build-with-garbage-path.sh \
|
||||||
ca/duplicate-realisation-in-closure.sh \
|
ca/duplicate-realisation-in-closure.sh \
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ simple = import ./simple.nix
|
||||||
|
|
||||||
testRepl () {
|
testRepl () {
|
||||||
local nixArgs=("$@")
|
local nixArgs=("$@")
|
||||||
local outPath=$(nix repl "${nixArgs[@]}" <<< "$replCmds" |&
|
local replOutput="$(nix repl "${nixArgs[@]}" <<< "$replCmds")"
|
||||||
|
echo "$replOutput"
|
||||||
|
local outPath=$(echo "$replOutput" |&
|
||||||
grep -o -E "$NIX_STORE_DIR/\w*-simple")
|
grep -o -E "$NIX_STORE_DIR/\w*-simple")
|
||||||
nix path-info "${nixArgs[@]}" "$outPath"
|
nix path-info "${nixArgs[@]}" "$outPath"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue