1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-11 21:16:02 +01:00

Fix merge conflicts with main

This commit is contained in:
Luc Perkins 2025-06-02 10:54:23 -07:00
commit 29cbee6eb8
No known key found for this signature in database
GPG key ID: C86EE5D85EE4DDA5
364 changed files with 6971 additions and 3855 deletions

View file

@ -128,3 +128,14 @@ pull_request_rules:
labels: labels:
- automatic backport - automatic backport
- merge-queue - merge-queue
- name: backport patches to 2.28
conditions:
- label=backport 2.28-maintenance
actions:
backport:
branches:
- "2.28-maintenance"
labels:
- automatic backport
- merge-queue

View file

@ -1 +1 @@
2.28.3 2.29.0

View file

@ -1 +1 @@
3.5.2 3.6.1

View file

@ -14,7 +14,7 @@ import sys
# literally. since the rules for these aren't even the same for # literally. since the rules for these aren't even the same for
# all three we will just fail when we encounter any of them (if # all three we will just fail when we encounter any of them (if
# asserts are off for some reason the depfile will likely point # asserts are off for some reason the depfile will likely point
# to nonexistant paths, making everything phony and thus fine.) # to nonexistent paths, making everything phony and thus fine.)
for path in glob.glob(sys.argv[1] + '/**', recursive=True): for path in glob.glob(sys.argv[1] + '/**', recursive=True):
assert '\\' not in path assert '\\' not in path
assert ' ' not in path assert ' ' not in path

View file

@ -33,6 +33,7 @@ let
{ {
settings, settings,
doc, doc,
uri-schemes,
experimentalFeature, experimentalFeature,
}: }:
let let

View file

@ -69,7 +69,7 @@ subdir('source/release-notes')
subdir('source') subdir('source')
# Hacky way to figure out if `nix` is an `ExternalProgram` or # Hacky way to figure out if `nix` is an `ExternalProgram` or
# `Exectuable`. Only the latter can occur in custom target input lists. # `Executable`. Only the latter can occur in custom target input lists.
if nix.full_path().startswith(meson.build_root()) if nix.full_path().startswith(meson.build_root())
nix_input = nix nix_input = nix
else else

View file

@ -11,6 +11,8 @@
python3, python3,
rsync, rsync,
nix-cli, nix-cli,
changelog-d,
officialRelease,
# Configuration Options # Configuration Options
@ -45,7 +47,8 @@ mkMesonDerivation (finalAttrs: {
]; ];
# Hack for sake of the dev shell # Hack for sake of the dev shell
passthru.externalNativeBuildInputs = [ passthru.externalNativeBuildInputs =
[
meson meson
ninja ninja
(lib.getBin lowdown-unsandboxed) (lib.getBin lowdown-unsandboxed)
@ -54,6 +57,13 @@ mkMesonDerivation (finalAttrs: {
jq jq
python3 python3
rsync rsync
changelog-d
]
++ lib.optionals (!officialRelease) [
# When not an official release, we likely have changelog entries that have
# yet to be rendered.
# When released, these are rendered into a committed file to save a dependency.
changelog-d
]; ];
nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [ nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [

View file

@ -370,6 +370,7 @@ const redirects = {
}, },
"glossary.html": { "glossary.html": {
"gloss-local-store": "store/types/local-store.html", "gloss-local-store": "store/types/local-store.html",
"package-attribute-set": "#package",
"gloss-chroot-store": "store/types/local-store.html", "gloss-chroot-store": "store/types/local-store.html",
"gloss-content-addressed-derivation": "#gloss-content-addressing-derivation", "gloss-content-addressed-derivation": "#gloss-content-addressing-derivation",
}, },

View file

@ -28,6 +28,7 @@
- [Data Types](language/types.md) - [Data Types](language/types.md)
- [String context](language/string-context.md) - [String context](language/string-context.md)
- [Syntax and semantics](language/syntax.md) - [Syntax and semantics](language/syntax.md)
- [Evaluation](language/evaluation.md)
- [Variables](language/variables.md) - [Variables](language/variables.md)
- [String literals](language/string-literals.md) - [String literals](language/string-literals.md)
- [Identifiers](language/identifiers.md) - [Identifiers](language/identifiers.md)
@ -128,6 +129,8 @@
- [Contributing](development/contributing.md) - [Contributing](development/contributing.md)
- [Determinate Nix Release Notes](release-notes-determinate/index.md) - [Determinate Nix Release Notes](release-notes-determinate/index.md)
- [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md)<!-- next --> - [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md)<!-- next -->
- [Release 3.6.1 (2025-05-24)](release-notes-determinate/rl-3.6.1.md)
- [Release 3.6.0 (2025-05-22)](release-notes-determinate/rl-3.6.0.md)
- [Release 3.5.2 (2025-05-12)](release-notes-determinate/rl-3.5.2.md) - [Release 3.5.2 (2025-05-12)](release-notes-determinate/rl-3.5.2.md)
- [Release 3.5.1 (2025-05-09)](release-notes-determinate/rl-3.5.1.md) - [Release 3.5.1 (2025-05-09)](release-notes-determinate/rl-3.5.1.md)
- [~~Release 3.5.0 (2025-05-09)~~](release-notes-determinate/rl-3.5.0.md) - [~~Release 3.5.0 (2025-05-09)~~](release-notes-determinate/rl-3.5.0.md)
@ -138,6 +141,7 @@
- [Release 3.0.0 (2025-03-04)](release-notes-determinate/rl-3.0.0.md) - [Release 3.0.0 (2025-03-04)](release-notes-determinate/rl-3.0.0.md)
- [Nix Release Notes](release-notes/index.md) - [Nix Release Notes](release-notes/index.md)
{{#include ./SUMMARY-rl-next.md}} {{#include ./SUMMARY-rl-next.md}}
- [Release 2.29 (2025-05-14)](release-notes/rl-2.29.md)
- [Release 2.28 (2025-04-02)](release-notes/rl-2.28.md) - [Release 2.28 (2025-04-02)](release-notes/rl-2.28.md)
- [Release 2.27 (2025-03-03)](release-notes/rl-2.27.md) - [Release 2.27 (2025-03-03)](release-notes/rl-2.27.md)
- [Release 2.26 (2025-01-22)](release-notes/rl-2.26.md) - [Release 2.26 (2025-01-22)](release-notes/rl-2.26.md)

View file

@ -27,7 +27,7 @@ nix store info --store ssh://username@mac
``` ```
To specify an SSH identity file as part of the remote store URI add a To specify an SSH identity file as part of the remote store URI add a
query paramater, e.g. query parameter, e.g.
```console ```console
nix store info --store ssh://username@mac?ssh-key=/home/alice/my-key nix store info --store ssh://username@mac?ssh-key=/home/alice/my-key

View file

@ -22,9 +22,9 @@ The following [concept map] shows its main components (rectangles), the objects
| | | |
+----------|-------------------|--------------------------------+ +----------|-------------------|--------------------------------+
| Nix | V | | Nix | V |
| | +-------------------------+ | | | +------------------------+ |
| | | commmand line interface |------. | | | | command line interface |------. |
| | +-------------------------+ | | | | +------------------------+ | |
| | | | | | | | | |
| evaluated by calls manages | | evaluated by calls manages |
| | | | | | | | | |

View file

@ -27,7 +27,7 @@ This operation deletes the specified generations of the current profile.
> >
> Older *and newer* generations will be deleted by this operation. > Older *and newer* generations will be deleted by this operation.
> >
> One might expect this to just delete older generations than the curent one, but that is only true if the current generation is also the latest. > One might expect this to just delete older generations than the current one, but that is only true if the current generation is also the latest.
> Because one can roll back to a previous generation, it is possible to have generations newer than the current one. > Because one can roll back to a previous generation, it is possible to have generations newer than the current one.
> They will also be deleted. > They will also be deleted.

View file

@ -242,16 +242,21 @@ print(t)
``` ```
Similarly, the following is a Perl script that specifies that it Similarly, the following is a Perl script that specifies that it
requires Perl and the `HTML::TokeParser::Simple` and `LWP` packages: requires Perl and the `HTML::TokeParser::Simple`, `LWP` and
`LWP::Protocol::Https` packages:
```perl ```perl
#! /usr/bin/env nix-shell #! /usr/bin/env nix-shell
#! nix-shell -i perl --packages perl perlPackages.HTMLTokeParserSimple perlPackages.LWP #! nix-shell -i perl
#! nix-shell --packages perl
#! nix-shell --packages perlPackages.HTMLTokeParserSimple
#! nix-shell --packages perlPackages.LWP
#! nix-shell --packages perlPackages.LWPProtocolHttps
use HTML::TokeParser::Simple; use HTML::TokeParser::Simple;
# Fetch nixos.org and print all hrefs. # Fetch nixos.org and print all hrefs.
my $p = HTML::TokeParser::Simple->new(url => 'http://nixos.org/'); my $p = HTML::TokeParser::Simple->new(url => 'https://nixos.org/');
while (my $token = $p->get_tag("a")) { while (my $token = $p->get_tag("a")) {
my $href = $token->get_attr("href"); my $href = $token->get_attr("href");
@ -316,7 +321,7 @@ contains:
```nix ```nix
with import <nixpkgs> {}; with import <nixpkgs> {};
runCommand "dummy" { buildInputs = [ python pythonPackages.prettytable ]; } "" runCommand "dummy" { buildInputs = [ python3 python3Packages.prettytable ]; } ""
``` ```
The script's file name is passed as the first argument to the interpreter specified by the `-i` flag. The script's file name is passed as the first argument to the interpreter specified by the `-i` flag.

View file

@ -45,10 +45,19 @@ symlink.
[output paths]: @docroot@/glossary.md#gloss-output-path [output paths]: @docroot@/glossary.md#gloss-output-path
- `--references`
Prints the set of [references] of the store paths
*paths*, that is, their immediate dependencies. (For *all*
dependencies, use `--requisites`.)
[references]: @docroot@/glossary.md#gloss-reference
- `--requisites` / `-R` - `--requisites` / `-R`
Prints out the [closure] of the store path *paths*. Prints out the set of [*requisites*][requisite] (better known as the [closure]) of the store path *paths*.
[requisite]: @docroot@/glossary.md#gloss-requisite
[closure]: @docroot@/glossary.md#gloss-closure [closure]: @docroot@/glossary.md#gloss-closure
This query has one option: This query has one option:
@ -65,29 +74,25 @@ symlink.
dependencies) is obtained by distributing the closure of a store dependencies) is obtained by distributing the closure of a store
derivation and specifying the option `--include-outputs`. derivation and specifying the option `--include-outputs`.
- `--references`
Prints the set of [references] of the store paths
*paths*, that is, their immediate dependencies. (For *all*
dependencies, use `--requisites`.)
[references]: @docroot@/glossary.md#gloss-reference
- `--referrers` - `--referrers`
Prints the set of *referrers* of the store paths *paths*, that is, Prints the set of [*referrers*][referrer] of the store paths *paths*, that is,
the store paths currently existing in the Nix store that refer to the store paths currently existing in the Nix store that refer to
one of *paths*. Note that contrary to the references, the set of one of *paths*. Note that contrary to the references, the set of
referrers is not constant; it can change as store paths are added or referrers is not constant; it can change as store paths are added or
removed. removed.
[referrer]: @docroot@/glossary.md#gloss-referrer
- `--referrers-closure` - `--referrers-closure`
Prints the closure of the set of store paths *paths* under the Prints the closure of the set of store paths *paths* under the
referrers relation; that is, all store paths that directly or [referrers relation][referrer]; that is, all store paths that directly or
indirectly refer to one of *paths*. These are all the path currently indirectly refer to one of *paths*. These are all the path currently
in the Nix store that are dependent on *paths*. in the Nix store that are dependent on *paths*.
[referrer]: @docroot@/glossary.md#gloss-referrer
- `--deriver` / `-d` - `--deriver` / `-d`
Prints the [deriver] that was used to build the store paths *paths*. If Prints the [deriver] that was used to build the store paths *paths*. If
@ -98,6 +103,13 @@ symlink.
example when *paths* were substituted from a binary cache. example when *paths* were substituted from a binary cache.
Use `--valid-derivers` instead to obtain valid paths only. Use `--valid-derivers` instead to obtain valid paths only.
> **Note**
>
> `nix-store --query --deriver` is replaced with the following `nix` command:
>
> nix path-info --json ... | jq -r '.[].deriver'
[deriver]: @docroot@/glossary.md#gloss-deriver [deriver]: @docroot@/glossary.md#gloss-deriver
- `--valid-derivers` - `--valid-derivers`

View file

@ -121,19 +121,25 @@ Nix uses a string with the following format to identify the *system type* or *pl
<cpu>-<os>[-<abi>] <cpu>-<os>[-<abi>]
``` ```
It is set when Nix is compiled for the given system, and based on the output of [`config.guess`](https://github.com/nixos/nix/blob/master/config/config.guess) ([upstream](https://git.savannah.gnu.org/cgit/config.git/tree/config.guess)): It is set when Nix is compiled for the given system, and based on the output of Meson's [`host_machine` information](https://mesonbuild.com/Reference-manual_builtin_host_machine.html)>
``` ```
<cpu>-<vendor>-<os>[<version>][-<abi>] <cpu>-<vendor>-<os>[<version>][-<abi>]
``` ```
When Nix is built such that `./configure` is passed any of the `--host`, `--build`, `--target` options, the value is based on the output of [`config.sub`](https://github.com/nixos/nix/blob/master/config/config.sub) ([upstream](https://git.savannah.gnu.org/cgit/config.git/tree/config.sub)): When cross-compiling Nix with Meson for local development, you need to specify a [cross-file](https://mesonbuild.com/Cross-compilation.html) using the `--cross-file` option. Cross-files define the target architecture and toolchain. When cross-compiling Nix with Nix, Nixpkgs takes care of this for you.
In the nix flake we also have some cross-compilation targets available:
``` ```
<cpu>-<vendor>[-<kernel>]-<os> nix build .#nix-everything-riscv64-unknown-linux-gnu
nix build .#nix-everything-armv7l-unknown-linux-gnueabihf
nix build .#nix-everything-armv7l-unknown-linux-gnueabihf
nix build .#nix-everything-x86_64-unknown-freebsd
nix build .#nix-everything-x86_64-w64-mingw32
``` ```
For historic reasons and backward-compatibility, some CPU and OS identifiers are translated from the GNU Autotools naming convention in [`configure.ac`](https://github.com/nixos/nix/blob/master/configure.ac) as follows: For historic reasons and backward-compatibility, some CPU and OS identifiers are translated as follows:
| `config.guess` | Nix | | `config.guess` | Nix |
|----------------------------|---------------------| |----------------------------|---------------------|
@ -156,10 +162,10 @@ Nix can be compiled using multiple environments:
To build with one of those environments, you can use To build with one of those environments, you can use
```console ```console
$ nix build .#nix-ccacheStdenv $ nix build .#nix-cli-ccacheStdenv
``` ```
You can use any of the other supported environments in place of `nix-ccacheStdenv`. You can use any of the other supported environments in place of `nix-cli-ccacheStdenv`.
## Editor integration ## Editor integration

View file

@ -170,9 +170,9 @@ sensitive.
```shell ```shell
$ nix init --template=template#pyton $ nix init --template=template#python
------------------------------------------------------------------------ ------------------------------------------------------------------------
Error! Template `template#pyton` not found. Error! Template `template#python` not found.
------------------------------------------------------------------------ ------------------------------------------------------------------------
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:

View file

@ -20,8 +20,9 @@ prs: 1238
Here's one or more paragraphs that describe the change. Here's one or more paragraphs that describe the change.
- It's markdown - It's markdown
- Add references to the manual using @docroot@ - Add references to the manual using [links like this](@_at_docroot@/example.md)
``` ```
<!-- for the raw markdown readers: that means using @docroot@ -->
Significant changes should add the following header, which moves them to the top. Significant changes should add the following header, which moves them to the top.

View file

@ -38,6 +38,13 @@
[store derivation]: #gloss-store-derivation [store derivation]: #gloss-store-derivation
- [directed acyclic graph]{#gloss-directed-acyclic-graph}
A [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) (DAG) is graph whose edges are given a direction ("a to b" is not the same edge as "b to a"), and for which no possible path (created by joining together edges) forms a cycle.
DAGs are very important to Nix.
In particular, the non-self-[references][reference] of [store object][store object] form a cycle.
- [derivation path]{#gloss-derivation-path} - [derivation path]{#gloss-derivation-path}
A [store path] which uniquely identifies a [store derivation]. A [store path] which uniquely identifies a [store derivation].
@ -71,9 +78,8 @@
This can be achieved by: This can be achieved by:
- Fetching a pre-built [store object] from a [substituter] - Fetching a pre-built [store object] from a [substituter]
- Running the [`builder`](@docroot@/language/derivations.md#attr-builder) executable as specified in the corresponding [store derivation] - [Building](@docroot@/store/building.md) the corresponding [store derivation]
- Delegating to a [remote machine](@docroot@/command-ref/conf-file.md#conf-builders) and retrieving the outputs - Delegating to a [remote machine](@docroot@/command-ref/conf-file.md#conf-builders) and retrieving the outputs
<!-- TODO: link [running] to build process page, #8888 -->
See [`nix-store --realise`](@docroot@/command-ref/nix-store/realise.md) for a detailed description of the algorithm. See [`nix-store --realise`](@docroot@/command-ref/nix-store/realise.md) for a detailed description of the algorithm.
@ -156,6 +162,8 @@
non-[fixed-output](#gloss-fixed-output-derivation) non-[fixed-output](#gloss-fixed-output-derivation)
derivation. derivation.
See [input-addressing derivation outputs](store/derivation/outputs/input-address.md) for details.
- [content-addressed store object]{#gloss-content-addressed-store-object} - [content-addressed store object]{#gloss-content-addressed-store-object}
A [store object] which is [content-addressed](#gloss-content-address), A [store object] which is [content-addressed](#gloss-content-address),
@ -215,23 +223,25 @@
> **Example** > **Example**
> >
> Building and deploying software using Nix entails writing Nix expressions as a high-level description of packages and compositions thereof. > Building and deploying software using Nix entails writing Nix expressions to describe [packages][package] and compositions thereof.
- [reference]{#gloss-reference} - [reference]{#gloss-reference}
A [store object] `O` is said to have a *reference* to a store object `P` if a [store path] to `P` appears in the contents of `O`. An edge from one [store object] to another.
Store objects can refer to both other store objects and themselves. See [References](@docroot@/store/store-object.md#references) for details.
References from a store object to itself are called *self-references*.
References other than a self-reference must not form a cycle.
[reference]: #gloss-reference [reference]: #gloss-reference
See [References](@docroot@/store/store-object.md#references) for details.
- [reachable]{#gloss-reachable} - [reachable]{#gloss-reachable}
A store path `Q` is reachable from another store path `P` if `Q` A store path `Q` is reachable from another store path `P` if `Q`
is in the *closure* of the *references* relation. is in the *closure* of the *references* relation.
See [References](@docroot@/store/store-object.md#references) for details.
- [closure]{#gloss-closure} - [closure]{#gloss-closure}
The closure of a store path is the set of store paths that are The closure of a store path is the set of store paths that are
@ -248,8 +258,21 @@
to a store object at path `Q`, then `Q` is in the closure of `P`. Further, if `Q` to a store object at path `Q`, then `Q` is in the closure of `P`. Further, if `Q`
references `R` then `R` is also in the closure of `P`. references `R` then `R` is also in the closure of `P`.
See [References](@docroot@/store/store-object.md#references) for details.
[closure]: #gloss-closure [closure]: #gloss-closure
- [requisite]{#gloss-requisite}
A store object [reachable] by a path (chain of references) from a given [store object].
The [closure] is the set of requisites.
See [References](@docroot@/store/store-object.md#references) for details.
- [referrer]{#gloss-reference}
A reversed edge from one [store object] to another.
- [output]{#gloss-output} - [output]{#gloss-output}
A [store object] produced by a [store derivation]. A [store object] produced by a [store derivation].
@ -320,7 +343,7 @@
See [Nix Archive](store/file-system-object/content-address.html#serial-nix-archive) for details. See [Nix Archive](store/file-system-object/content-address.html#serial-nix-archive) for details.
- [`∅`]{#gloss-emtpy-set} - [`∅`]{#gloss-empty-set}
The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile. The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile.
@ -330,18 +353,17 @@
- [package]{#package} - [package]{#package}
1. A software package; a collection of files and other data. A software package; files that belong together for a particular purpose, and metadata.
2. A [package attribute set]. Nix represents files as [file system objects][file system object], and how they belong together is encoded as [references][reference] between [store objects][store object] that contain these file system objects.
- [package attribute set]{#package-attribute-set} The [Nix language] allows denoting packages in terms of [attribute sets](@docroot@/language/types.md#attribute-set) containing:
- attributes that refer to the files of a package, typically in the form of [derivation outputs](#output),
- attributes with metadata, such as information about how the package is supposed to be used.
An [attribute set](@docroot@/language/types.md#attribute-set) containing the attribute `type = "derivation";` (derivation for historical reasons), as well as other attributes, such as The exact shape of these attribute sets is up to convention.
- attributes that refer to the files of a [package], typically in the form of [derivation outputs](#output),
- attributes that declare something about how the package is supposed to be installed or used,
- other metadata or arbitrary attributes.
[package attribute set]: #package-attribute-set [package]: #package
- [string interpolation]{#gloss-string-interpolation} - [string interpolation]{#gloss-string-interpolation}

View file

@ -15,8 +15,9 @@ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix
## How Nix works ## How Nix works
Nix treats packages like values in purely functional programming languages Nix is a _purely functional package manager_. This means that it
such as Haskell — they are built by functions that dont have treats packages like values in a purely functional programming language
— packages are built by functions that dont have
side-effects, and they never change after they have been built. Nix side-effects, and they never change after they have been built. Nix
stores packages in the _Nix store_, usually the directory stores packages in the _Nix store_, usually the directory
`/nix/store`, where each package has its own unique subdirectory such `/nix/store`, where each package has its own unique subdirectory such

View file

@ -73,12 +73,14 @@ Derivations can declare some infrequently used optional attributes.
> **Warning** > **Warning**
> >
> If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites), > If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites),
[`disallowedReferences`](#adv-attr-disallowedReferences) and [`disallowedRequisites`](#adv-attr-disallowedRequisites), maxSize, and maxClosureSize. [`disallowedReferences`](#adv-attr-disallowedReferences) and [`disallowedRequisites`](#adv-attr-disallowedRequisites), maxSize, and maxClosureSize.
will have no effect. will have no effect.
## Output checks ## Output checks
See the [corresponding section in the derivation output page](@docroot@/store/derivation/outputs/index.md).
- [`allowedReferences`]{#adv-attr-allowedReferences}\ - [`allowedReferences`]{#adv-attr-allowedReferences}\
The optional attribute `allowedReferences` specifies a list of legal The optional attribute `allowedReferences` specifies a list of legal
references (dependencies) of the output of the builder. For example, references (dependencies) of the output of the builder. For example,
@ -280,7 +282,7 @@ All other combinations are invalid.
<!-- <!--
`__contentAddressed` is ignored, becaused fixed-output derivations always content-address their outputs, by definition. `__contentAddressed` is ignored, because fixed-output derivations always content-address their outputs, by definition.
**TODO CHECK** **TODO CHECK**
@ -333,17 +335,17 @@ Here is more information on the `output*` attributes, and what values they may b
- [`outputHashAlgo`]{#adv-attr-outputHashAlgo} - [`outputHashAlgo`]{#adv-attr-outputHashAlgo}
This specifies the hash alorithm used to digest the [file system object] data of a content-addressing derivation output. This specifies the hash algorithm used to digest the [file system object] data of a content-addressing derivation output.
This works in conjunction with [`outputHashMode`](#adv-attr-outputHashAlgo). This works in conjunction with [`outputHashMode`](#adv-attr-outputHashAlgo).
Specifying one without the other is an error (unless [`outputHash` is also specified and includes its own hash algorithm as described below). Specifying one without the other is an error (unless `outputHash` is also specified and includes its own hash algorithm as described below).
The `outputHashAlgo` attribute specifies the hash algorithm used to compute the hash. The `outputHashAlgo` attribute specifies the hash algorithm used to compute the hash.
It can currently be `"blake3"`, "sha1"`, `"sha256"`, `"sha512"`, or `null`. It can currently be `"blake3"`, `"sha1"`, `"sha256"`, `"sha512"`, or `null`.
`outputHashAlgo` can only be `null` when `outputHash` follows the SRI format, because in that case the choice of hash algorithm is determined by `outputHash`. `outputHashAlgo` can only be `null` when `outputHash` follows the SRI format, because in that case the choice of hash algorithm is determined by `outputHash`.
- [`outputHash`]{#adv-attr-outputHashAlgo}; [`outputHash`]{#adv-attr-outputHashMode}\ - [`outputHash`]{#adv-attr-outputHashAlgo}; [`outputHash`]{#adv-attr-outputHashMode}
This will specify the output hash of the single output of a [fixed-output derivation]. This will specify the output hash of the single output of a [fixed-output derivation].

View file

@ -0,0 +1,77 @@
# Evaluation
Evaluation is the process of turning a Nix expression into a [Nix value](types.md).
This happens by a number of rules, such as:
- Constructing values from literals.
For example the number literal `1` is turned into the number value `1`.
- Applying operators
For example the addition operator `+` is applied to two number values to produce a new number value.
- Applying built-in functions
For example the expression `builtins.isInt 1` is evaluated to `true`.
- Applying user-defined functions
For example the expression `(x: x + 1) 10` can[*](#laziness) be thought of rewriting `x` in the function body to the argument, `10 + 1`, which is then evaluated to `11`.
These rules are applied as needed, driven by the specific use of the expression. For example, this can occur in the Nix command line interface or interactively with the [repl (read-eval-print loop)](@docroot@/command-ref/new-cli/nix3-repl.md), which is a useful tool when learning about evaluation.
# Details
## Values {#values}
Nix values can be thought of as a subset of Nix expressions.
For example, the expression `1 + 2` is not a value, because it can be reduced to `3`. The expression `3` is a value, because it cannot be reduced any further.
Evaluation normally happens by applying rules to the "head" of the expression, which is the outermost part of the expression. The head of an expression like `[ 1 2 ]` is the list literal (`[ a1 a2 ]`), for `1 + 2` it is the addition operator (`+`), and for `f 1` it is the function application "operator" (` `).
After applying all possible rules to the head until no rules can be applied, the expression is in "weak head normal form" (WHNF). This means that the outermost constructor of the expression is evaluated, but the inner values may or may not be. "Weak" only signifies that the expression may be a function. This is an historical or academic artifact, and Nix has no use for the non-weak "head normal form".
## Laziness and thunks {#laziness}
The Nix language implements _call by need_ (as opposed to _call by value_ or _call by reference_). <!-- No wikipedia link, which would be a huge distraction. --> Call by need is commonly known as laziness in functional programming, as it is a specific implementation of the concept where evaluation is deferred until the result is required, aiming to only evaluate the parts of an expression that are needed to produce the final result.
Furthermore, the result of evaluation is preserved, in values, in `let` bindings, in function _parameters_, which behave a lot like `let` bindings, but with the notable exception of function _calls_. Results of function calls rely on being put into `let` bindings, etc to be reused. <!-- which would be prohibitively expensive and too strict, or we wouldn't have a cache key for the argument -->
When discussing the process of evaluation in lower level terms, we may define values not as a subset of expressions, but separately, where each "value" is either a data constructor, a function or a _thunk_. A thunk is a delayed computation, represented by an expression reference and a "closure" &ndash; the values for the lexical scope around the delayed expression.
As a user of the language, you generally don't have to think about thunks, as they are not part of the language semantics, but you may encounter them in the repl, in the [C API] or in discussions.
## Strictness
Instead of thinking about thunks, it is often more productive to think in terms of _strictness_.
This term is used in functional programming to refer to the opposite of laziness, i.e. not just for something like error propagation. It refers to the need to evaluate certain expressions before evaluation can produce any result.
Statements about strictness usually implicitly refer to weak head normal form.
For example, we can say that the following function is strict in its argument:
```nix
x: isAttrs x || isFunction x
```
The above function must be strict in its argument `x` because determining its type requires evaluating `x` to at least some degree.
The following function is not strict in its argument:
```nix
x: { isOk = isAttrs x || isFunction x; }
```
It is not strict, because it can return the attribute set before evaluating `x`.
The attribute value for `isOk` _is_ strict in `x`.
A function with a _set pattern_ is always strict in its argument, as a consequence of checking the argument's type and/or attribute names:
```nix
let f = { ... }: "ok";
in f (throw "kablam")
=> error: kablam
```
However, a set pattern does not add any strictness beyond WHNF of the attribute set argument.
```nix
let f = orig@{ x, ... }: "ok";
in f { x = throw "error"; y = throw "error"; }
=> "ok"
```
[C API]: @docroot@/c-api.md

View file

@ -11,7 +11,14 @@ The language is:
- *domain-specific* - *domain-specific*
It comes with [built-in functions](@docroot@/language/builtins.md) to integrate with the Nix store, which manages files and performs the derivations declared in the Nix language. The Nix language is purpose-built for working with text files.
Its most characteristic features are:
- [File system path primitives](@docroot@/language/types.md#type-path), for accessing source files
- [Indented strings](@docroot@/language/string-literals.md) and [string interpolation](@docroot@/language/string-interpolation.md), for creating file contents
- [Strings with contexts](@docroot@/language/string-context.md), for transparently linking files
It comes with [built-in functions](@docroot@/language/builtins.md) to integrate with the [Nix store](@docroot@/store/index.md), which manages files and enables [realising](@docroot@/glossary.md#gloss-realise) derivations declared in the Nix language.
- *declarative* - *declarative*

View file

@ -13,8 +13,8 @@ The purpose of string contexts is to collect non-string values attached to strin
[string concatenation](./operators.md#string-concatenation), [string concatenation](./operators.md#string-concatenation),
[string interpolation](./string-interpolation.md), [string interpolation](./string-interpolation.md),
and similar operations. and similar operations.
The idea is that a user can combine together values to create a build instructions for derivations without manually keeping track of where they come from. The idea is that a user can reference other files when creating text files through Nix expressions, without manually keeping track of the exact paths.
Then the Nix language implicitly does that bookkeeping to efficiently obtain the closure of derivation inputs. Nix will ensure that the all referenced files are accessible that all [store paths](@docroot@/glossary.md#gloss-store-path) are [valid](@docroot@/glossary.md#gloss-validity).
> **Note** > **Note**
> >

View file

@ -18,7 +18,7 @@ is a JSON object with the following fields:
* `method`: * `method`:
For an output which will be [content addresed], a string representing the [method](@docroot@/store/store-object/content-address.md) of content addressing that is chosen. For an output which will be [content addressed], a string representing the [method](@docroot@/store/store-object/content-address.md) of content addressing that is chosen.
Valid method strings are: Valid method strings are:
- [`flat`](@docroot@/store/store-object/content-address.md#method-flat) - [`flat`](@docroot@/store/store-object/content-address.md#method-flat)
@ -29,7 +29,7 @@ is a JSON object with the following fields:
Otherwise, `null`. Otherwise, `null`.
* `hashAlgo`: * `hashAlgo`:
For an output which will be [content addresed], the name of the hash algorithm used. For an output which will be [content addressed], the name of the hash algorithm used.
Valid algorithm strings are: Valid algorithm strings are:
- `blake3` - `blake3`

View file

@ -46,7 +46,7 @@ defined as the timestamp of the newest file inside the tarball.
This protocol is supported by Gitea since v1.22.1 and by Forgejo since v7.0.4/v8.0.0 and can be used with the following flake URL schema: This protocol is supported by Gitea since v1.22.1 and by Forgejo since v7.0.4/v8.0.0 and can be used with the following flake URL schema:
``` ```
https://<domain name>/<owner>/<repo>/archive/<reference or revison>.tar.gz https://<domain name>/<owner>/<repo>/archive/<reference or revision>.tar.gz
``` ```
> **Example** > **Example**

View file

@ -1,6 +1,6 @@
# Changes between Nix and Determinate Nix # Changes between Nix and Determinate Nix
This section lists the differences between upstream Nix 2.28 and Determinate Nix 3.5.2.<!-- differences --> This section lists the differences between upstream Nix 2.29 and Determinate Nix 3.6.1.<!-- differences -->
* In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature. * In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature.
@ -29,3 +29,9 @@ This section lists the differences between upstream Nix 2.28 and Determinate Nix
<!-- Determinate Nix version 3.5.2 --> <!-- Determinate Nix version 3.5.2 -->
* Tell users a source is corrupted ("cannot read file from tarball: Truncated tar archive detected while reading data"), improving over the previous 'cannot read file from tarball' error by @edolstra in [DeterminateSystems/nix-src#64](https://github.com/DeterminateSystems/nix-src/pull/64) * Tell users a source is corrupted ("cannot read file from tarball: Truncated tar archive detected while reading data"), improving over the previous 'cannot read file from tarball' error by @edolstra in [DeterminateSystems/nix-src#64](https://github.com/DeterminateSystems/nix-src/pull/64)
<!-- Determinate Nix version 3.6.0 -->
* Emit warnings when using import-from-derivation by setting the `trace-import-from-derivation` option to `true` by @gustavderdrache in [DeterminateSystems/nix-src#70](https://github.com/DeterminateSystems/nix-src/pull/70)
<!-- Determinate Nix version 3.6.1 -->
* Fix nlohmann error in fromStructuredAttrs() by @edolstra in [DeterminateSystems/nix-src#73](https://github.com/DeterminateSystems/nix-src/pull/73)

View file

@ -0,0 +1,11 @@
# Release 3.6.0 (2025-05-22)
* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
## What's Changed
* Install 'nix profile add' manpage by @edolstra in [DeterminateSystems/nix-src#69](https://github.com/DeterminateSystems/nix-src/pull/69)
* Sync with upstream 2.29.0 by @edolstra in [DeterminateSystems/nix-src#67](https://github.com/DeterminateSystems/nix-src/pull/67)
* Emit warnings when using import-from-derivation by setting the `trace-import-from-derivation` option to `true` by @gustavderdrache in [DeterminateSystems/nix-src#70](https://github.com/DeterminateSystems/nix-src/pull/70)
**Full Changelog**: [v3.5.2...v3.6.0](https://github.com/DeterminateSystems/nix-src/compare/v3.5.2...v3.6.0)

View file

@ -0,0 +1,9 @@
# Release 3.6.1 (2025-05-24)
* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
## What's Changed
* Fix nlohmann error in fromStructuredAttrs() by @edolstra in [DeterminateSystems/nix-src#73](https://github.com/DeterminateSystems/nix-src/pull/73)
**Full Changelog**: [v3.6.0...v3.6.1](https://github.com/DeterminateSystems/nix-src/compare/v3.6.0...v3.6.1)

View file

@ -31,7 +31,7 @@
- To operate on a flake outside the current directory, you must now pass `--flake path/to/flake`. - To operate on a flake outside the current directory, you must now pass `--flake path/to/flake`.
- The flake-specific flags `--recreate-lock-file` and `--update-input` have been removed from all commands operating on installables. - The flake-specific flags `--recreate-lock-file` and `--update-input` have been removed from all commands operating on installables.
They are superceded by `nix flake update`. They are superseded by `nix flake update`.
- Commit signature verification for the [`builtins.fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit) is added as the new [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches). - Commit signature verification for the [`builtins.fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit) is added as the new [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches).

View file

@ -15,7 +15,7 @@
- Modify `nix derivation {add,show}` JSON format [#9866](https://github.com/NixOS/nix/issues/9866) [#10722](https://github.com/NixOS/nix/pull/10722) - Modify `nix derivation {add,show}` JSON format [#9866](https://github.com/NixOS/nix/issues/9866) [#10722](https://github.com/NixOS/nix/pull/10722)
The JSON format for derivations has been slightly revised to better conform to our [JSON guidelines](@docroot@/development/cli-guideline.md#returning-future-proof-json). The JSON format for derivations has been slightly revised to better conform to our [JSON guidelines](@docroot@/development/cli-guideline.md#returning-future-proof-json).
In particular, the hash algorithm and content addressing method of content-addresed derivation outputs are now separated into two fields `hashAlgo` and `method`, In particular, the hash algorithm and content addressing method of content-addressed derivation outputs are now separated into two fields `hashAlgo` and `method`,
rather than one field with an arcane `:`-separated format. rather than one field with an arcane `:`-separated format.
This JSON format is only used by the experimental `nix derivation` family of commands, at this time. This JSON format is only used by the experimental `nix derivation` family of commands, at this time.

View file

@ -173,7 +173,7 @@
**Deprecation**: Use `nix32` instead of `base32` as `toHashFormat` **Deprecation**: Use `nix32` instead of `base32` as `toHashFormat`
For the builtin `convertHash`, the `toHashFormat` parameter now accepts the same hash formats as the `--to`/`--from` For the builtin `convertHash`, the `toHashFormat` parameter now accepts the same hash formats as the `--to`/`--from`
parameters of the `nix hash conert` command: `"base16"`, `"nix32"`, `"base64"`, and `"sri"`. The former `"base32"` value parameters of the `nix hash convert` command: `"base16"`, `"nix32"`, `"base64"`, and `"sri"`. The former `"base32"` value
remains as a deprecated alias for `"nix32"`. Please convert your code from: remains as a deprecated alias for `"nix32"`. Please convert your code from:
```nix ```nix

View file

@ -0,0 +1,160 @@
# Release 2.29.0 (2025-05-14)
After the special backport-based release of Nix 2.28 (timed to coincide with Nixpkgs 25.05), the release process is back to normal with 2.29.
As such, we have slightly more weeks of work from `master` (since 2.28 was branched from 2.27) than usual.
This fact is counterbalanced by the fact that most of those changes are bug fixes rather than larger new features.
- Prettified JSON output on the terminal [#12555](https://github.com/NixOS/nix/issues/12555) [#12652](https://github.com/NixOS/nix/pull/12652)
This makes the output easier to read.
Scripts are mostly unaffected because for those, stdout will be a file or a pipe, not a terminal, and for those, the old single-line behavior applies.
`--json --pretty` can be passed to enable it even if the output is not a terminal.
If your script creates a pseudoterminal for Nix's stdout, you can pass `--no-pretty` to disable the new behavior.
- Repl: improve continuation prompt for incomplete expressions [#12846](https://github.com/NixOS/nix/pull/12846)
Improved REPL user experience by updating the continuation prompt from invisible blank spaces to a visible `" > "`, enhancing clarity when entering multi-line expressions.
- REPL `:load-flake` and `:reload` now work together [#8753](https://github.com/NixOS/nix/issues/8753) [#13180](https://github.com/NixOS/nix/pull/13180)
Previously, `:reload` only reloaded the files specified with `:load` (or on the command line).
Now, it also works with the flakes specified with `:load-flake` (or on the command line).
This makes it correctly reload everything that was previously loaded, regardless of what sort of thing (plain file or flake) each item is.
- Increase retry delays on HTTP 429 Too Many Requests [#13052](https://github.com/NixOS/nix/pull/13052)
When downloading Nix, the retry delay was previously set to 0.25 seconds. It has now been increased to 1 minute to better handle transient CI errors, particularly on GitHub.
- S3: opt-in the STSProfileCredentialsProvider [#12646](https://github.com/NixOS/nix/pull/12646)
Added support for STS-based authentication for S3-based binary caches, i.e. enabling seamless integration with `aws sso login`.
- Reduce connect timeout for http substituter [#12876](https://github.com/NixOS/nix/pull/12876)
Previously, the Nix setting `connect-timeout` had no limit. It is now set to `5s`, offering a more practical default for users self-hosting binary caches, which may occasionally become unavailable, such as during updates.
- C API: functions for locking and loading a flake [#10435](https://github.com/NixOS/nix/issues/10435) [#12877](https://github.com/NixOS/nix/pull/12877) [#13098](https://github.com/NixOS/nix/pull/13098)
This release adds functions to the C API for handling the loading of flakes. Previously, this had to be worked around by using `builtins.getFlake`.
C API consumers and language bindings now have access to basic locking functionality.
It does not expose the full locking API, so that the implementation can evolve more freely.
Locking is controlled with the functions, which cover the common use cases for consuming a flake:
- `nix_flake_lock_flags_set_mode_check`
- `nix_flake_lock_flags_set_mode_virtual`
- `nix_flake_lock_flags_set_mode_write_as_needed`
- `nix_flake_lock_flags_add_input_override`, which also enables `virtual`
This change also introduces the new `nix-fetchers-c` library, whose single purpose for now is to manage the (`nix.conf`) settings for the built-in fetchers.
More details can be found in the [C API documentation](@docroot@/c-api.md).
- No longer copy flakes that are in the nix store [#10435](https://github.com/NixOS/nix/issues/10435) [#12877](https://github.com/NixOS/nix/pull/12877) [#13098](https://github.com/NixOS/nix/pull/13098)
Previously, we would duplicate entries like `path:/nix/store/*` back into the Nix store.
This was prominently visible for pinned system flake registry entries in NixOS, e.g., when running `nix run nixpkgs#hello`.
- Consistently preserve error messages from cached evaluation [#12762](https://github.com/NixOS/nix/issues/12762) [#12809](https://github.com/NixOS/nix/pull/12809)
In one code path, we are not returning the errors cached from prior evaluation, but instead throwing generic errors stemming from the lack of value (due to the error).
These generic error messages were far less informative.
Now we consistently return the original error message.
- Faster blake3 hashing [#12676](https://github.com/NixOS/nix/pull/12676)
The implementation for blake3 hashing is now multi-threaded and used memory-mapped IO.
Benchmark results can be found the [pull request](https://github.com/NixOS/nix/pull/12676).
- Fix progress bar for S3 binary caches and make file transfers interruptible [#12877](https://github.com/NixOS/nix/issues/12877) [#13098](https://github.com/NixOS/nix/issues/13098) [#12538](https://github.com/NixOS/nix/pull/12538)
The progress bar now correctly display upload/download progress for S3 up/downloads. S3 uploads are now interruptible.
- Add host attribute of github/gitlab flakerefs to URL serialization [#12580](https://github.com/NixOS/nix/pull/12580)
Resolved an issue where `github:` or `gitlab:` URLs lost their `host` attribute when written to a lockfile, resulting in invalid URLs.
- Multiple signatures support in store urls [#12976](https://github.com/NixOS/nix/pull/12976)
Added support for a `secretKeyFiles` URI parameter in Nix store URIs, allowing multiple signing key files to be specified as a comma-separated list.
This enables signing paths with multiple keys. This helps with [RFC #149](https://github.com/NixOS/rfcs/pull/149) to enable binary cache key rotation in the NixOS infra.
Example usage:
```bash
nix copy --to "file:///tmp/store?secret-keys=/tmp/key1,/tmp/key2" \
"$(nix build --print-out-paths nixpkgs#hello)"
```
- nix flake show now skips over import-from-derivation [#4265](https://github.com/NixOS/nix/issues/4265) [#12583](https://github.com/NixOS/nix/pull/12583)
Previously, if a flake contained outputs relying on [import from derivation](@docroot@/language/import-from-derivation.md) during evaluation, `nix flake show` would fail to display the rest of the flake. The updated behavior skips such outputs, allowing the rest of the flake to be shown.
- Add `nix formatter build` and `nix formatter run` commands [#13063](https://github.com/NixOS/nix/pull/13063)
`nix formatter run` is an alias for `nix fmt`. Nothing new there.
`nix formatter build` is sort of like `nix build`: it builds, links, and prints a path to the formatter program:
```
$ nix formatter build
/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt
```
Note that unlike `nix build`, this prints the full path to the program, not just the store path (in the example above that would be `/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).
- Amend OSC 8 escape stripping for xterm-style separator [#13109](https://github.com/NixOS/nix/pull/13109)
Improve terminal escape code filtering to understand a second type of hyperlink escape codes.
This in particular prevents parts of GCC 14's diagnostics from being improperly filtered away.
# Contributors
This release was made possible by the following 40 contributors:
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)
- The Tumultuous Unicorn Of Darkness [**(@TheTumultuousUnicornOfDarkness)**](https://github.com/TheTumultuousUnicornOfDarkness)
- Robert Hensing [**(@roberth)**](https://github.com/roberth)
- Félix [**(@picnoir)**](https://github.com/picnoir)
- Valentin Gagarin [**(@fricklerhandwerk)**](https://github.com/fricklerhandwerk)
- Eelco Dolstra [**(@edolstra)**](https://github.com/edolstra)
- Vincent Breitmoser [**(@Valodim)**](https://github.com/Valodim)
- Brian McKenna [**(@puffnfresh)**](https://github.com/puffnfresh)
- ulucs [**(@ulucs)**](https://github.com/ulucs)
- John Ericson [**(@Ericson2314)**](https://github.com/Ericson2314)
- Andrey Butirsky [**(@bam80)**](https://github.com/bam80)
- Dean De Leo [**(@whatsthecraic)**](https://github.com/whatsthecraic)
- Las Safin [**(@L-as)**](https://github.com/L-as)
- Sergei Zimmerman [**(@xokdvium)**](https://github.com/xokdvium)
- Shahar "Dawn" Or [**(@mightyiam)**](https://github.com/mightyiam)
- Ryan Hendrickson [**(@rhendric)**](https://github.com/rhendric)
- Rodney Lorrimar [**(@rvl)**](https://github.com/rvl)
- Erik Nygren [**(@Kirens)**](https://github.com/Kirens)
- Cole Helbling [**(@cole-h)**](https://github.com/cole-h)
- Martin Fischer [**(@not-my-profile)**](https://github.com/not-my-profile)
- Graham Christensen [**(@grahamc)**](https://github.com/grahamc)
- Vit Gottwald [**(@VitGottwald)**](https://github.com/VitGottwald)
- silvanshade [**(@silvanshade)**](https://github.com/silvanshade)
- Illia Bobyr [**(@ilya-bobyr)**](https://github.com/ilya-bobyr)
- Jeremy Fleischman [**(@jfly)**](https://github.com/jfly)
- Ruby Rose [**(@oldshensheep)**](https://github.com/oldshensheep)
- Sergei Trofimovich [**(@trofi)**](https://github.com/trofi)
- Tim [**(@Jaculabilis)**](https://github.com/Jaculabilis)
- Anthony Wang [**(@anthowan)**](https://github.com/anthowan)
- Jörg Thalheim [**(@Mic92)**](https://github.com/Mic92)
- Sandro [**(@SuperSandro2000)**](https://github.com/SuperSandro2000)
- tomberek [**(@tomberek)**](https://github.com/tomberek)
- Dmitry Bogatov [**(@KAction)**](https://github.com/KAction)
- Sizhe Zhao [**(@Prince213)**](https://github.com/Prince213)
- jade [**(@lf-)**](https://github.com/lf-)
- Pierre-Etienne Meunier [**(@P-E-Meunier)**](https://github.com/P-E-Meunier)
- Alexander Romanov [**(@ajlekcahdp4)**](https://github.com/ajlekcahdp4)
- Domagoj Mišković [**(@allrealmsoflife)**](https://github.com/allrealmsoflife)
- Thomas Miedema [**(@thomie)**](https://github.com/thomie)
- Yannik Sander [**(@ysndr)**](https://github.com/ysndr)
- Philipp Otterbein
- Dmitry Bogatov

View file

@ -13,7 +13,7 @@
* New command `nix store copy-log` to copy build logs from one store * New command `nix store copy-log` to copy build logs from one store
to another. to another.
* The `commit-lockfile-summary` option can be set to a non-empty * The `commit-lockfile-summary` option can be set to a non-empty
string to override the commit summary used when commiting an updated string to override the commit summary used when committing an updated
lockfile. This may be used in conjunction with the `nixConfig` lockfile. This may be used in conjunction with the `nixConfig`
attribute in `flake.nix` to better conform to repository attribute in `flake.nix` to better conform to repository
conventions. conventions.

View file

@ -23,7 +23,7 @@ The output spec for an output with a fixed content addresses additionally contai
> **Design note** > **Design note**
> >
> In principle, the output spec could also specify the references the store object should have, since the references and file system objects are equally parts of a content-addressed store object proper that contribute to its content-addressed. > In principle, the output spec could also specify the references the store object should have, since the references and file system objects are equally parts of a content-addressed store object proper that contribute to its content-addressed.
> However, at this time, the references are not not done because all fixed content-addressed outputs are required to have no references (including no self-reference). > However, at this time, the references are not done because all fixed content-addressed outputs are required to have no references (including no self-reference).
> >
> Also in principle, rather than specifying the references and file system object data with separate hashes, a single hash that constraints both could be used. > Also in principle, rather than specifying the references and file system object data with separate hashes, a single hash that constraints both could be used.
> This could be done with the final store path's digest, or better yet, the hash that will become the store path's digest before it is truncated. > This could be done with the final store path's digest, or better yet, the hash that will become the store path's digest before it is truncated.
@ -110,18 +110,18 @@ Because the derivation output is not fixed (just like with [input addressing]),
> >
> Strictly speaking, the extent to which sandboxing and deprivilaging is possible varies with the environment Nix is running in. > Strictly speaking, the extent to which sandboxing and deprivilaging is possible varies with the environment Nix is running in.
> Nix's configuration settings indicate what level of sandboxing is required or enabled. > Nix's configuration settings indicate what level of sandboxing is required or enabled.
> Builds of derivations will fail if they request an absense of sandboxing which is not allowed. > Builds of derivations will fail if they request an absence of sandboxing which is not allowed.
> Builds of derivations will also fail if the level of sandboxing specified in the configure exceeds what is possible in teh given environment. > Builds of derivations will also fail if the level of sandboxing specified in the configure exceeds what is possible in the given environment.
> >
> (The "environment", in this case, consists of attributes such as the Operating System Nix runs atop, along with the operating-system-specific privilages that Nix has been granted. > (The "environment", in this case, consists of attributes such as the Operating System Nix runs atop, along with the operating-system-specific privileges that Nix has been granted.
> Because of how conventional operating systems like macos, Linux, etc. work, granting builders *fewer* privilages may ironically require that Nix be run with *more* privilages.) > Because of how conventional operating systems like macos, Linux, etc. work, granting builders *fewer* privileges may ironically require that Nix be run with *more* privileges.)
That said, derivations producing floating content-addressed outputs may declare their builders as impure (like the builders of derivations producing producing fixed outputs). That said, derivations producing floating content-addressed outputs may declare their builders as impure (like the builders of derivations producing fixed outputs).
This is provisionally supported as part of the [`impure-derivations`][xp-feature-impure-derivations] experimental feature. This is provisionally supported as part of the [`impure-derivations`][xp-feature-impure-derivations] experimental feature.
### Compatibility negotiation ### Compatibility negotiation
Any derivation producing a floating content-addresssed output implicitly requires the `ca-derivations` [system feature](@docroot@/command-ref/conf-file.md#conf-system-features). Any derivation producing a floating content-addressed output implicitly requires the `ca-derivations` [system feature](@docroot@/command-ref/conf-file.md#conf-system-features).
This prevents scheduling the building of the derivation on a machine without the experimental feature enabled. This prevents scheduling the building of the derivation on a machine without the experimental feature enabled.
Even once the experimental feature is stabilized, this is still useful in order to be allow using remote builder running odler versions of Nix, or alternative implementations that do not support floating content addressing. Even once the experimental feature is stabilized, this is still useful in order to be allow using remote builder running odler versions of Nix, or alternative implementations that do not support floating content addressing.
@ -132,7 +132,7 @@ For store objects produced by manually inserting into the store to create a stor
But for store objects produced by derivation, the "method is quite formal" --- the whole point of derivations is to be a formal notion of building, after all. But for store objects produced by derivation, the "method is quite formal" --- the whole point of derivations is to be a formal notion of building, after all.
In this case, we can elevate this informal property to a formal one. In this case, we can elevate this informal property to a formal one.
A *determinstic* content-addressing derivation should produce outputs with the same content addresses: A *deterministic* content-addressing derivation should produce outputs with the same content addresses:
1. Every time the builder is run 1. Every time the builder is run
@ -144,7 +144,7 @@ A *determinstic* content-addressing derivation should produce outputs with the s
The choice of provisional store path can be thought of as an impurity, since it is an arbitrary choice. The choice of provisional store path can be thought of as an impurity, since it is an arbitrary choice.
If provisional outputs paths are deterministically chosen, we are in the first branch of part (1). If provisional outputs paths are deterministically chosen, we are in the first branch of part (1).
The builder the data it produces based on it in arbitrary ways, but this gets us closer to to [input addressing]. The builder the data it produces based on it in arbitrary ways, but this gets us closer to [input addressing].
Deterministically choosing the provisional path may be considered "complete sandboxing" by removing an impurity, but this is unsatisfactory Deterministically choosing the provisional path may be considered "complete sandboxing" by removing an impurity, but this is unsatisfactory
<!-- <!--

View file

@ -2,7 +2,7 @@
As stated on the [main pages on derivations](../index.md#store-derivation), As stated on the [main pages on derivations](../index.md#store-derivation),
a derivation produces [store objects](@docroot@/store/store-object.md), which are known as the *outputs* of the derivation. a derivation produces [store objects](@docroot@/store/store-object.md), which are known as the *outputs* of the derivation.
Indeed, the entire point of derivations is to produce these outputs, and to reliably and reproducably produce these derivations each time the derivation is run. Indeed, the entire point of derivations is to produce these outputs, and to reliably and reproducibly produce these derivations each time the derivation is run.
One of the parts of a derivation is its *outputs specification*, which specifies certain information about the outputs the derivation produces when run. One of the parts of a derivation is its *outputs specification*, which specifies certain information about the outputs the derivation produces when run.
The outputs specification is a map, from names to specifications for individual outputs. The outputs specification is a map, from names to specifications for individual outputs.
@ -83,11 +83,11 @@ The rules for this are fairly concise:
- A content-addressing derivation may be pure or impure - A content-addressing derivation may be pure or impure
- If it is impure, it may be be fixed (typical), or it may be floating if the additional [`impure-derivations`][xp-feature-impure-derivations] experimental feature is enabled. - If it is impure, it may be fixed (typical), or it may be floating if the additional [`impure-derivations`][xp-feature-impure-derivations] experimental feature is enabled.
- If it is pure, it must be floating. - If it is pure, it must be floating.
- Pure, fixed content-addressing derivations are not suppported - Pure, fixed content-addressing derivations are not supported
> There is no use for this forth combination. > There is no use for this forth combination.
> The sole purpose of an output's store path being fixed is to support the derivation being impure. > The sole purpose of an output's store path being fixed is to support the derivation being impure.

View file

@ -4,7 +4,64 @@ A Nix store is a collection of *store objects* with *references* between them.
A store object consists of A store object consists of
- A [file system object](./file-system-object.md) as data - A [file system object](./file-system-object.md) as data
- A set of [store paths](./store-path.md) as references to other store objects
- A set of [store paths](./store-path.md) as references to store objects
### References
Store objects can refer to both other store objects and themselves.
References from a store object to itself are called *self-references*.
Store objects and their references form a directed graph, where the store objects are the vertices, and the references are the edges.
In particular, the edge corresponding to a reference is from the store object that contains the reference, and to the store object that the store path (which is the reference) refers to.
References other than a self-reference must not form a cycle.
The graph of references excluding self-references thus forms a [directed acyclic graph].
[directed acyclic graph]: @docroot@/glossary.md#gloss-directed acyclic graph
We can take the [transitive closure] of the references graph, which any pair of store objects have an edge not if there is a single reference from the first to the second, but a path of one or more references from the first to the second.
The *requisites* of a store object are all store objects reachable by paths of references which start with given store object's references.
[transitive closure]: https://en.wikipedia.org/wiki/Transitive_closure
We can also take the [transpose graph] ofthe references graph, where we reverse the orientation of all edges.
The *referrers* of a store object are the store objects that reference it.
[transpose graph]: https://en.wikipedia.org/wiki/Transpose_graph
One can also combine both concepts: taking the transitive closure of the transposed references graph.
The *referrers closure* of a store object are the store objects that can reach the given store object via paths of references.
> **Note**
>
> Care must be taken to distinguish between the intrinsic and extrinsic properties of store objects.
> We can create graphs from the store objects in a store, but the contents of the store is not, in general fixed, and may instead change over time.
>
> - The references of a store object --- the set of store paths called the references --- is a field of a store object, and thus intrinsic by definition.
Regardless of what store contains the store object in question, and what else that store may or may not contain, the references are the same.
>
> - The requisites of a store object are almost intrinsic --- some store paths due not precisely refer to a unique single store object.
> Exactly what store object is being referenced, and what in turn *its* references are, depends on the store in question.
> Different stores that disagree.
>
> - The referrers of a store object are completely extrinsic, and depends solely on the store which contains that store object, not the store object itself.
> Other store objects which refer to the store object in question may be added or removed from the store.
### Immutability
Store objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object): Store objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object):
Once created, they do not change until they are deleted. Once created, they do not change nor can any store object they reference be changed.
> **Note**
>
> Stores which support atomically deleting multiple store objects allow more flexibility while still upholding this property.
### Closure property
A store can only contain a store object if it also contains all the store objects it refers to.
> **Note**
>
> The "closure property" isn't meant to prohibit, for example, [lazy loading](https://en.wikipedia.org/wiki/Lazy_loading) of store objects.
> However, the "closure property" and immutability in conjunction imply that any such lazy loading ought to be deterministic.

View file

@ -45,7 +45,7 @@ Self-references however cannot be referred to by their path, because we are in t
> As far as we know, this is equivalent to finding a hash collision. > As far as we know, this is equivalent to finding a hash collision.
Instead we have a "has self-reference" boolean, which ends up affecting the digest: Instead we have a "has self-reference" boolean, which ends up affecting the digest:
In all currently-supported store object content-addressing methods, when hashing the file system object data, any occurence of store object's own store path in the digested data is replaced with a [sentinel value](https://en.wikipedia.org/wiki/Sentinel_value). In all currently-supported store object content-addressing methods, when hashing the file system object data, any occurrence of store object's own store path in the digested data is replaced with a [sentinel value](https://en.wikipedia.org/wiki/Sentinel_value).
The hashes of these modified input streams are used instead. The hashes of these modified input streams are used instead.
When validating the content address of a store object after the fact, the above process works as written. When validating the content address of a store object after the fact, the above process works as written.

View file

@ -57,6 +57,9 @@ def recursive_replace(data: dict[str, t.Any], book_root: Path, search_path: Path
).replace( ).replace(
'@docroot@', '@docroot@',
("../" * len(path_to_chapter.parent.parts) or "./")[:-1] ("../" * len(path_to_chapter.parent.parts) or "./")[:-1]
).replace(
'@_at_',
'@'
), ),
sub_items = [ sub_items = [
recursive_replace(sub_item, book_root, search_path) recursive_replace(sub_item, book_root, search_path)

View file

@ -7,7 +7,7 @@
channelName ? "nixpkgs", channelName ? "nixpkgs",
channelURL ? "https://nixos.org/channels/nixpkgs-unstable", channelURL ? "https://nixos.org/channels/nixpkgs-unstable",
extraPkgs ? [ ], extraPkgs ? [ ],
maxLayers ? 100, maxLayers ? 70,
nixConf ? { }, nixConf ? { },
flake-registry ? null, flake-registry ? null,
uid ? 0, uid ? 0,

8
flake.lock generated
View file

@ -63,16 +63,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1734359947, "lastModified": 1747179050,
"narHash": "sha256-1Noao/H+N8nFB4Beoy8fgwrcOQLVm9o4zKW1ODaqK9E=", "narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "48d12d5e70ee91fe8481378e540433a7303dbf6a", "rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "release-24.11", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View file

@ -1,7 +1,7 @@
{ {
description = "The purely functional package manager"; description = "The purely functional package manager";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2"; inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446"; inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
@ -42,12 +42,12 @@
systems = linuxSystems ++ darwinSystems; systems = linuxSystems ++ darwinSystems;
crossSystems = [ crossSystems = [
"armv6l-unknown-linux-gnueabihf" #"armv6l-unknown-linux-gnueabihf"
"armv7l-unknown-linux-gnueabihf" #"armv7l-unknown-linux-gnueabihf"
"riscv64-unknown-linux-gnu" #"riscv64-unknown-linux-gnu"
# Disabled because of https://github.com/NixOS/nixpkgs/issues/344423 # Disabled because of https://github.com/NixOS/nixpkgs/issues/344423
# "x86_64-unknown-netbsd" # "x86_64-unknown-netbsd"
"x86_64-unknown-freebsd" #"x86_64-unknown-freebsd"
]; ];
stdenvs = [ stdenvs = [
@ -384,6 +384,7 @@
"nix-store-tests" = { }; "nix-store-tests" = { };
"nix-fetchers" = { }; "nix-fetchers" = { };
"nix-fetchers-c" = { };
"nix-fetchers-tests" = { }; "nix-fetchers-tests" = { };
"nix-expr" = { }; "nix-expr" = { };
@ -392,6 +393,7 @@
"nix-expr-tests" = { }; "nix-expr-tests" = { };
"nix-flake" = { }; "nix-flake" = { };
"nix-flake-c" = { };
"nix-flake-tests" = { }; "nix-flake-tests" = { };
"nix-main" = { }; "nix-main" = { };

View file

@ -37,7 +37,7 @@ The team is on Github as [@NixOS/nix-team](https://github.com/orgs/NixOS/teams/n
The team meets twice a week (times are denoted in the [Europe/Amsterdam](https://en.m.wikipedia.org/wiki/Time_in_the_Netherlands) time zone): The team meets twice a week (times are denoted in the [Europe/Amsterdam](https://en.m.wikipedia.org/wiki/Time_in_the_Netherlands) time zone):
- Discussion meeting: [Wednesday 21:00-22:00 Europe/Amsterdam](https://www.google.com/calendar/event?eid=ZG5rZzNyajRjajducGV2NGY5aGkzYWIwdnJfMjAyNDA1MDhUMTkwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn) - Discussion meeting: Wednesday 21:00-22:00 Europe/Amsterdam see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
1. Triage issues and pull requests from the [No Status](#no-status) column (30 min) 1. Triage issues and pull requests from the [No Status](#no-status) column (30 min)
2. Discuss issues and pull requests from the [To discuss](#to-discuss) column (30 min). 2. Discuss issues and pull requests from the [To discuss](#to-discuss) column (30 min).
@ -46,7 +46,7 @@ The team meets twice a week (times are denoted in the [Europe/Amsterdam](https:/
- mark it as draft if it is blocked on the contributor - mark it as draft if it is blocked on the contributor
- escalate it back to the team by moving it to To discuss, and leaving a comment as to why the issue needs to be discussed again. - escalate it back to the team by moving it to To discuss, and leaving a comment as to why the issue needs to be discussed again.
- Work meeting: [Mondays 14:00-16:00 Europe/Amsterdam](https://www.google.com/calendar/event?eid=Ym52NDdzYnRic2NzcDcybjZiNDhpNzhpa3NfMjAyNDA1MTNUMTIwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn) - Work meeting: Mondays 14:00-16:00 Europe/Amsterdam see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
1. Code review on pull requests from [In review](#in-review). 1. Code review on pull requests from [In review](#in-review).
2. Other chores and tasks. 2. Other chores and tasks.

View file

@ -152,5 +152,19 @@
"kaction@disroot.org": "KAction", "kaction@disroot.org": "KAction",
"serenity@kaction.cc": null, "serenity@kaction.cc": null,
"dev@erik.work": "Kirens", "dev@erik.work": "Kirens",
"felix@alternativebit.fr": "picnoir" "felix@alternativebit.fr": "picnoir",
"butirsky@gmail.com": "bam80",
"look@my.amazin.horse": "Valodim",
"jeremyfleischman@gmail.com": "jfly",
"vit.gottwald@gmail.com": "VitGottwald",
"a@unnamed.website": "anthowan",
"hello@whatsthecraic.net": "whatsthecraic",
"alex.rom23@mail.ru": "ajlekcahdp4",
"domagoj@tuta.com": "allrealmsoflife",
"uluc.sengil@gmail.com": "ulucs",
"prc.zhao@outlook.com": "Prince213",
"the-tumultuous-unicorn-of-darkness@gmx.com": "TheTumultuousUnicornOfDarkness",
"dev@rodney.id.au": "rvl",
"pe@pijul.org": "P-E-Meunier",
"yannik@floxdev.com": "ysndr"
} }

View file

@ -133,5 +133,18 @@
"oldshensheep": "Ruby Rose", "oldshensheep": "Ruby Rose",
"KAction": "Dmitry Bogatov", "KAction": "Dmitry Bogatov",
"thomie": "Thomas Miedema", "thomie": "Thomas Miedema",
"Kirens": "Erik Nygren" "Kirens": "Erik Nygren",
"Prince213": "Sizhe Zhao",
"anthowan": "Anthony Wang",
"jfly": "Jeremy Fleischman",
"VitGottwald": "Vit Gottwald",
"bam80": "Andrey Butirsky",
"ulucs": null,
"P-E-Meunier": "Pierre-Etienne Meunier",
"ysndr": "Yannik Sander",
"TheTumultuousUnicornOfDarkness": "The Tumultuous Unicorn Of Darkness",
"ajlekcahdp4": "Alexander Romanov",
"Valodim": "Vincent Breitmoser",
"rvl": "Rodney Lorrimar",
"whatsthecraic": "Dean De Leo"
} }

View file

@ -284,8 +284,8 @@
''^src/libstore/build/goal\.cc$'' ''^src/libstore/build/goal\.cc$''
''^src/libstore/include/nix/store/build/goal\.hh$'' ''^src/libstore/include/nix/store/build/goal\.hh$''
''^src/libstore/unix/build/hook-instance\.cc$'' ''^src/libstore/unix/build/hook-instance\.cc$''
''^src/libstore/unix/build/local-derivation-goal\.cc$'' ''^src/libstore/unix/build/derivation-builder\.cc$''
''^src/libstore/unix/include/nix/store/build/local-derivation-goal\.hh$'' ''^src/libstore/unix/include/nix/store/build/derivation-builder\.hh$''
''^src/libstore/build/substitution-goal\.cc$'' ''^src/libstore/build/substitution-goal\.cc$''
''^src/libstore/include/nix/store/build/substitution-goal\.hh$'' ''^src/libstore/include/nix/store/build/substitution-goal\.hh$''
''^src/libstore/build/worker\.cc$'' ''^src/libstore/build/worker\.cc$''
@ -360,7 +360,6 @@
''^src/libutil/linux/namespaces\.cc$'' ''^src/libutil/linux/namespaces\.cc$''
''^src/libutil/logging\.cc$'' ''^src/libutil/logging\.cc$''
''^src/libutil/include/nix/util/logging\.hh$'' ''^src/libutil/include/nix/util/logging\.hh$''
''^src/libutil/include/nix/util/lru-cache\.hh$''
''^src/libutil/memory-source-accessor\.cc$'' ''^src/libutil/memory-source-accessor\.cc$''
''^src/libutil/include/nix/util/memory-source-accessor\.hh$'' ''^src/libutil/include/nix/util/memory-source-accessor\.hh$''
''^src/libutil/include/nix/util/pool\.hh$'' ''^src/libutil/include/nix/util/pool\.hh$''
@ -605,8 +604,8 @@
''^tests/functional/flakes/prefetch\.sh$'' ''^tests/functional/flakes/prefetch\.sh$''
''^tests/functional/flakes/run\.sh$'' ''^tests/functional/flakes/run\.sh$''
''^tests/functional/flakes/show\.sh$'' ''^tests/functional/flakes/show\.sh$''
''^tests/functional/fmt\.sh$'' ''^tests/functional/formatter\.sh$''
''^tests/functional/fmt\.simple\.sh$'' ''^tests/functional/formatter\.simple\.sh$''
''^tests/functional/gc-auto\.sh$'' ''^tests/functional/gc-auto\.sh$''
''^tests/functional/gc-concurrent\.builder\.sh$'' ''^tests/functional/gc-concurrent\.builder\.sh$''
''^tests/functional/gc-concurrent\.sh$'' ''^tests/functional/gc-concurrent\.sh$''

View file

@ -6,7 +6,8 @@ project('nix-dev-shell', 'cpp',
subproject_dir : 'src', subproject_dir : 'src',
default_options : [ default_options : [
'localstatedir=/nix/var', 'localstatedir=/nix/var',
] ],
meson_version : '>= 1.1'
) )
# Internal Libraries # Internal Libraries
@ -33,6 +34,7 @@ endif
# External C wrapper libraries # External C wrapper libraries
subproject('libutil-c') subproject('libutil-c')
subproject('libstore-c') subproject('libstore-c')
subproject('libfetchers-c')
subproject('libexpr-c') subproject('libexpr-c')
subproject('libflake-c') subproject('libflake-c')
subproject('libmain-c') subproject('libmain-c')

View file

@ -12,6 +12,7 @@ add_project_arguments(
'-Werror=switch-enum', '-Werror=switch-enum',
'-Werror=undef', '-Werror=undef',
'-Werror=unused-result', '-Werror=unused-result',
'-Werror=sign-compare',
'-Wignored-qualifiers', '-Wignored-qualifiers',
'-Wimplicit-fallthrough', '-Wimplicit-fallthrough',
'-Wno-deprecated-declarations', '-Wno-deprecated-declarations',

View file

@ -151,13 +151,6 @@ let
]; ];
separateDebugInfo = !stdenv.hostPlatform.isStatic; separateDebugInfo = !stdenv.hostPlatform.isStatic;
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie"; hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
env =
prevAttrs.env or { }
// lib.optionalAttrs (
stdenv.isLinux
&& !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")
&& !(stdenv.hostPlatform.useLLVM or false)
) { LDFLAGS = "-fuse-ld=gold"; };
}; };
mesonLibraryLayer = finalAttrs: prevAttrs: { mesonLibraryLayer = finalAttrs: prevAttrs: {
@ -209,6 +202,7 @@ in
{ {
version = baseVersion + versionSuffix; version = baseVersion + versionSuffix;
inherit versionSuffix; inherit versionSuffix;
inherit officialRelease;
inherit maintainers; inherit maintainers;
inherit filesetToSource; inherit filesetToSource;
@ -331,6 +325,7 @@ in
nix-store-tests = callPackage ../src/libstore-tests/package.nix { }; nix-store-tests = callPackage ../src/libstore-tests/package.nix { };
nix-fetchers = callPackage ../src/libfetchers/package.nix { }; nix-fetchers = callPackage ../src/libfetchers/package.nix { };
nix-fetchers-c = callPackage ../src/libfetchers-c/package.nix { };
nix-fetchers-tests = callPackage ../src/libfetchers-tests/package.nix { }; nix-fetchers-tests = callPackage ../src/libfetchers-tests/package.nix { };
nix-expr = callPackage ../src/libexpr/package.nix { }; nix-expr = callPackage ../src/libexpr/package.nix { };

View file

@ -38,6 +38,7 @@ scope: {
aws-sdk-cpp = aws-sdk-cpp =
(pkgs.aws-sdk-cpp.override { (pkgs.aws-sdk-cpp.override {
apis = [ apis = [
"identity-management"
"s3" "s3"
"transfer" "transfer"
]; ];
@ -60,7 +61,9 @@ scope: {
"--with-container" "--with-container"
"--with-context" "--with-context"
"--with-coroutine" "--with-coroutine"
"--with-iostreams"
]; ];
enableIcu = false;
}).overrideAttrs }).overrideAttrs
(old: { (old: {
# Need to remove `--with-*` to use `--with-libraries=...` # Need to remove `--with-*` to use `--with-libraries=...`

View file

@ -71,11 +71,16 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
# We use this shell with the local checkout, not unpackPhase. # We use this shell with the local checkout, not unpackPhase.
src = null; src = null;
env = { env =
{
# For `make format`, to work without installing pre-commit # For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml" _NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
modular.pre-commit.settings.rawConfig modular.pre-commit.settings.rawConfig
}"; }";
}
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
CC_LD = "mold";
CXX_LD = "mold";
}; };
mesonFlags = mesonFlags =
@ -114,12 +119,10 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript) (pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
pkgs.buildPackages.nixfmt-rfc-style pkgs.buildPackages.nixfmt-rfc-style
] ]
# TODO: Remove the darwin check once
# https://github.com/NixOS/nixpkgs/pull/291814 is available
++ lib.optional (stdenv.cc.isClang && !stdenv.buildPlatform.isDarwin) pkgs.buildPackages.bear
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) ( ++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
lib.hiPrio pkgs.buildPackages.clang-tools lib.hiPrio pkgs.buildPackages.clang-tools
); )
++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped;
buildInputs = buildInputs =
attrs.buildInputs or [ ] attrs.buildInputs or [ ]

View file

@ -15,6 +15,7 @@
nix-store-tests, nix-store-tests,
nix-fetchers, nix-fetchers,
nix-fetchers-c,
nix-fetchers-tests, nix-fetchers-tests,
nix-expr, nix-expr,
@ -54,6 +55,7 @@ let
nix-store nix-store
nix-store-c nix-store-c
nix-fetchers nix-fetchers
nix-fetchers-c
nix-expr nix-expr
nix-expr-c nix-expr-c
nix-flake nix-flake
@ -230,6 +232,7 @@ stdenv.mkDerivation (finalAttrs: {
"nix-expr" "nix-expr"
"nix-expr-c" "nix-expr-c"
"nix-fetchers" "nix-fetchers"
"nix-fetchers-c"
"nix-flake" "nix-flake"
"nix-flake-c" "nix-flake-c"
"nix-main" "nix-main"

View file

@ -48,6 +48,7 @@ let
"nix-store-test-support" "nix-store-test-support"
"nix-store-tests" "nix-store-tests"
"nix-fetchers" "nix-fetchers"
"nix-fetchers-c"
"nix-fetchers-tests" "nix-fetchers-tests"
"nix-expr" "nix-expr"
"nix-expr-c" "nix-expr-c"

View file

@ -62,6 +62,13 @@ else
end end
end end
# Only use MANPATH if it is already set. In general `man` will just simply
# pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin`
# which is in the $PATH. For more info, run `manpath -d`.
if set --query MANPATH
set --export --prepend --path MANPATH "$NIX_LINK/share/man"
end
add_path "@localstatedir@/nix/profiles/default/bin" add_path "@localstatedir@/nix/profiles/default/bin"
add_path "$NIX_LINK/bin" add_path "$NIX_LINK/bin"

View file

@ -1,5 +1,5 @@
# Only execute this file once per shell. # Only execute this file once per shell.
if test -z "$HOME" || test -z "$USER" || \ if test -z "$HOME" || \
test -n "$__ETC_PROFILE_NIX_SOURCED" test -n "$__ETC_PROFILE_NIX_SOURCED"
exit exit
end end
@ -53,6 +53,13 @@ else if test -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" # fall back to cacert in
set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt"
else if test -e "$NIX_LINK/etc/ca-bundle.crt" # old cacert in Nix profile else if test -e "$NIX_LINK/etc/ca-bundle.crt" # old cacert in Nix profile
set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt" set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt"
else
# Fall back to what is in the nix profiles, favouring whatever is defined last.
for i in (string split ' ' $NIX_PROFILES)
if test -e "$i/etc/ssl/certs/ca-bundle.crt"
set --export NIX_SSL_CERT_FILE "$i/etc/ssl/certs/ca-bundle.crt"
end
end
end end
# Only use MANPATH if it is already set. In general `man` will just simply # Only use MANPATH if it is already set. In general `man` will just simply
@ -62,6 +69,7 @@ if set --query MANPATH
set --export --prepend --path MANPATH "$NIX_LINK/share/man" set --export --prepend --path MANPATH "$NIX_LINK/share/man"
end end
add_path "@localstatedir@/nix/profiles/default/bin"
add_path "$NIX_LINK/bin" add_path "$NIX_LINK/bin"
# Cleanup # Cleanup

View file

@ -16,7 +16,7 @@
#include "nix/store/globals.hh" #include "nix/store/globals.hh"
#include "nix/util/serialise.hh" #include "nix/util/serialise.hh"
#include "nix/store/build-result.hh" #include "nix/store/build-result.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-open.hh"
#include "nix/util/strings.hh" #include "nix/util/strings.hh"
#include "nix/store/derivations.hh" #include "nix/store/derivations.hh"
#include "nix/store/local-store.hh" #include "nix/store/local-store.hh"
@ -42,9 +42,9 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri.render()), slot), true); return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri.render()), slot), true);
} }
static bool allSupportedLocally(Store & store, const std::set<std::string>& requiredFeatures) { static bool allSupportedLocally(Store & store, const StringSet& requiredFeatures) {
for (auto & feature : requiredFeatures) for (auto & feature : requiredFeatures)
if (!store.systemFeatures.get().count(feature)) return false; if (!store.config.systemFeatures.get().count(feature)) return false;
return true; return true;
} }
@ -85,7 +85,7 @@ static int main_build_remote(int argc, char * * argv)
that gets cleared on reboot, but it wouldn't work on macOS. */ that gets cleared on reboot, but it wouldn't work on macOS. */
auto currentLoadName = "/current-load"; auto currentLoadName = "/current-load";
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>()) if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
currentLoad = std::string { localStore->stateDir } + currentLoadName; currentLoad = std::string { localStore->config.stateDir } + currentLoadName;
else else
currentLoad = settings.nixStateDir + currentLoadName; currentLoad = settings.nixStateDir + currentLoadName;
@ -113,7 +113,7 @@ static int main_build_remote(int argc, char * * argv)
auto amWilling = readInt(source); auto amWilling = readInt(source);
auto neededSystem = readString(source); auto neededSystem = readString(source);
drvPath = store->parseStorePath(readString(source)); drvPath = store->parseStorePath(readString(source));
auto requiredFeatures = readStrings<std::set<std::string>>(source); auto requiredFeatures = readStrings<StringSet>(source);
/* It would be possible to build locally after some builds clear out, /* It would be possible to build locally after some builds clear out,
so don't show the warning now: */ so don't show the warning now: */

View file

@ -3,7 +3,7 @@
#include "nix/cmd/command.hh" #include "nix/cmd/command.hh"
#include "nix/cmd/markdown.hh" #include "nix/cmd/markdown.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-open.hh"
#include "nix/store/local-fs-store.hh" #include "nix/store/local-fs-store.hh"
#include "nix/store/derivations.hh" #include "nix/store/derivations.hh"
#include "nix/expr/nixexpr.hh" #include "nix/expr/nixexpr.hh"
@ -14,12 +14,10 @@
namespace nix { namespace nix {
RegisterCommand::Commands * RegisterCommand::commands = nullptr;
nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix) nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
{ {
nix::Commands res; nix::Commands res;
for (auto & [name, command] : *RegisterCommand::commands) for (auto & [name, command] : RegisterCommand::commands())
if (name.size() == prefix.size() + 1) { if (name.size() == prefix.size() + 1) {
bool equal = true; bool equal = true;
for (size_t i = 0; i < prefix.size(); ++i) for (size_t i = 0; i < prefix.size(); ++i)
@ -40,7 +38,7 @@ nlohmann::json NixMultiCommand::toJSON()
void NixMultiCommand::run() void NixMultiCommand::run()
{ {
if (!command) { if (!command) {
std::set<std::string> subCommandTextLines; StringSet subCommandTextLines;
for (auto & [name, _] : commands) for (auto & [name, _] : commands)
subCommandTextLines.insert(fmt("- `%s`", name)); subCommandTextLines.insert(fmt("- `%s`", name));
std::string markdownError = std::string markdownError =
@ -397,4 +395,11 @@ void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & bu
} }
} }
void MixOutLinkBase::createOutLinksMaybe(const std::vector<BuiltPathWithResult> & buildables, ref<Store> & store)
{
if (outLink != "")
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
createOutLinks(outLink, toBuiltPaths(buildables), *store2);
}
} }

View file

@ -9,7 +9,7 @@
#include "nix/fetchers/registry.hh" #include "nix/fetchers/registry.hh"
#include "nix/flake/flakeref.hh" #include "nix/flake/flakeref.hh"
#include "nix/flake/settings.hh" #include "nix/flake/settings.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-open.hh"
#include "nix/cmd/command.hh" #include "nix/cmd/command.hh"
#include "nix/fetchers/tarball.hh" #include "nix/fetchers/tarball.hh"
#include "nix/fetchers/fetch-to-store.hh" #include "nix/fetchers/fetch-to-store.hh"
@ -18,7 +18,6 @@
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
fetchers::Settings fetchSettings; fetchers::Settings fetchSettings;
@ -122,8 +121,8 @@ MixEvalArgs::MixEvalArgs()
.category = category, .category = category,
.labels = {"original-ref", "resolved-ref"}, .labels = {"original-ref", "resolved-ref"},
.handler = {[&](std::string _from, std::string _to) { .handler = {[&](std::string _from, std::string _to) {
auto from = parseFlakeRef(fetchSettings, _from, fs::current_path().string()); auto from = parseFlakeRef(fetchSettings, _from, std::filesystem::current_path().string());
auto to = parseFlakeRef(fetchSettings, _to, fs::current_path().string()); auto to = parseFlakeRef(fetchSettings, _to, std::filesystem::current_path().string());
fetchers::Attrs extraAttrs; fetchers::Attrs extraAttrs;
if (to.subdir != "") extraAttrs["dir"] = to.subdir; if (to.subdir != "") extraAttrs["dir"] = to.subdir;
fetchers::overrideRegistry(from.input, to.input, extraAttrs); fetchers::overrideRegistry(from.input, to.input, extraAttrs);

View file

@ -18,7 +18,7 @@ extern char ** savedArgv;
class EvalState; class EvalState;
struct Pos; struct Pos;
class Store; class Store;
class LocalFSStore; struct LocalFSStore;
static constexpr Command::Category catHelp = -1; static constexpr Command::Category catHelp = -1;
static constexpr Command::Category catSecondary = 100; static constexpr Command::Category catSecondary = 100;
@ -287,13 +287,16 @@ struct StorePathCommand : public StorePathsCommand
struct RegisterCommand struct RegisterCommand
{ {
typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands; typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands;
static Commands * commands;
static Commands & commands()
{
static Commands commands;
return commands;
}
RegisterCommand(std::vector<std::string> && name, std::function<ref<Command>()> command) RegisterCommand(std::vector<std::string> && name, std::function<ref<Command>()> command)
{ {
if (!commands) commands().emplace(name, command);
commands = new Commands;
commands->emplace(name, command);
} }
static nix::Commands getCommandsFor(const std::vector<std::string> & prefix); static nix::Commands getCommandsFor(const std::vector<std::string> & prefix);
@ -365,7 +368,7 @@ void completeFlakeRefWithFragment(
const Strings & defaultFlakeAttrPaths, const Strings & defaultFlakeAttrPaths,
std::string_view prefix); std::string_view prefix);
std::string showVersions(const std::set<std::string> & versions); std::string showVersions(const StringSet & versions);
void printClosureDiff( void printClosureDiff(
ref<Store> store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent); ref<Store> store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent);
@ -376,4 +379,41 @@ void printClosureDiff(
*/ */
void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & buildables, LocalFSStore & store); void createOutLinks(const std::filesystem::path & outLink, const BuiltPaths & buildables, LocalFSStore & store);
} /** `outLink` parameter, `createOutLinksMaybe` method. See `MixOutLinkByDefault`. */
struct MixOutLinkBase : virtual Args
{
/** Prefix for any output symlinks. Empty means do not write an output symlink. */
Path outLink;
MixOutLinkBase(const std::string & defaultOutLink)
: outLink(defaultOutLink)
{
}
void createOutLinksMaybe(const std::vector<BuiltPathWithResult> & buildables, ref<Store> & store);
};
/** `--out-link`, `--no-link`, `createOutLinksMaybe` */
struct MixOutLinkByDefault : MixOutLinkBase, virtual Args
{
MixOutLinkByDefault()
: MixOutLinkBase("result")
{
addFlag({
.longName = "out-link",
.shortName = 'o',
.description = "Use *path* as prefix for the symlinks to the build results. It defaults to `result`.",
.labels = {"path"},
.handler = {&outLink},
.completer = completePath,
});
addFlag({
.longName = "no-link",
.description = "Do not create symlinks to the build results.",
.handler = {&outLink, Path("")},
});
}
};
} // namespace nix

View file

@ -21,6 +21,7 @@ struct App
struct UnresolvedApp struct UnresolvedApp
{ {
App unresolved; App unresolved;
std::vector<BuiltPathWithResult> build(ref<Store> evalStore, ref<Store> store);
App resolve(ref<Store> evalStore, ref<Store> store); App resolve(ref<Store> evalStore, ref<Store> store);
}; };

View file

@ -12,12 +12,15 @@ typedef std::function<void(int, char * *)> MainFunction;
struct RegisterLegacyCommand struct RegisterLegacyCommand
{ {
typedef std::map<std::string, MainFunction> Commands; typedef std::map<std::string, MainFunction> Commands;
static Commands * commands;
static Commands & commands() {
static Commands commands;
return commands;
}
RegisterLegacyCommand(const std::string & name, MainFunction fun) RegisterLegacyCommand(const std::string & name, MainFunction fun)
{ {
if (!commands) commands = new Commands; commands()[name] = fun;
(*commands)[name] = fun;
} }
}; };

View file

@ -72,7 +72,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
auto newOutputs = std::visit(overloaded { auto newOutputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec { [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
std::set<std::string> outputsToInstall; StringSet outputsToInstall;
for (auto & output : packageInfo.queryOutputs(false, true)) for (auto & output : packageInfo.queryOutputs(false, true))
outputsToInstall.insert(output.first); outputsToInstall.insert(output.first);
if (outputsToInstall.empty()) if (outputsToInstall.empty())

View file

@ -117,7 +117,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
.drvPath = makeConstantStorePathRef(std::move(drvPath)), .drvPath = makeConstantStorePathRef(std::move(drvPath)),
.outputs = std::visit(overloaded { .outputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec { [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
std::set<std::string> outputsToInstall; StringSet outputsToInstall;
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) { if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
if (aOutputSpecified->getBool()) { if (aOutputSpecified->getBool()) {
if (auto aOutputName = attr->maybeGetAttr("outputName")) if (auto aOutputName = attr->maybeGetAttr("outputName"))

View file

@ -31,8 +31,6 @@
namespace nix { namespace nix {
namespace fs { using namespace std::filesystem; }
void completeFlakeInputAttrPath( void completeFlakeInputAttrPath(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<EvalState> evalState,
@ -343,7 +341,7 @@ void completeFlakeRefWithFragment(
auto flakeRefS = std::string(prefix.substr(0, hash)); auto flakeRefS = std::string(prefix.substr(0, hash));
// TODO: ideally this would use the command base directory instead of assuming ".". // TODO: ideally this would use the command base directory instead of assuming ".".
auto flakeRef = parseFlakeRef(fetchSettings, expandTilde(flakeRefS), fs::current_path().string()); auto flakeRef = parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string());
auto evalCache = openEvalCache(*evalState, auto evalCache = openEvalCache(*evalState,
std::make_shared<flake::LockedFlake>(lockFlake( std::make_shared<flake::LockedFlake>(lockFlake(
@ -488,7 +486,11 @@ Installables SourceExprCommand::parseInstallables(
throw UsageError("'--file' and '--expr' are exclusive"); throw UsageError("'--file' and '--expr' are exclusive");
// FIXME: backward compatibility hack // FIXME: backward compatibility hack
if (file) evalSettings.pureEval = false; if (file) {
if (evalSettings.pureEval && evalSettings.pureEval.overridden)
throw UsageError("'--file' is not compatible with '--pure-eval'");
evalSettings.pureEval = false;
}
auto state = getEvalState(); auto state = getEvalState();
auto vFile = state->allocValue(); auto vFile = state->allocValue();

View file

@ -1,7 +0,0 @@
#include "nix/cmd/legacy.hh"
namespace nix {
RegisterLegacyCommand::Commands * RegisterLegacyCommand::commands = 0;
}

View file

@ -71,7 +71,6 @@ sources = files(
'installable-flake.cc', 'installable-flake.cc',
'installable-value.cc', 'installable-value.cc',
'installables.cc', 'installables.cc',
'legacy.cc',
'markdown.cc', 'markdown.cc',
'misc-store-flags.cc', 'misc-store-flags.cc',
'network-proxy.cc', 'network-proxy.cc',

View file

@ -135,7 +135,7 @@ static constexpr const char * promptForType(ReplPromptType promptType)
case ReplPromptType::ReplPrompt: case ReplPromptType::ReplPrompt:
return "nix-repl> "; return "nix-repl> ";
case ReplPromptType::ContinuationPrompt: case ReplPromptType::ContinuationPrompt:
return " "; return " > "; // 9 spaces + >
} }
assert(false); assert(false);
} }

View file

@ -12,7 +12,7 @@
#include "nix/expr/eval-settings.hh" #include "nix/expr/eval-settings.hh"
#include "nix/expr/attr-path.hh" #include "nix/expr/attr-path.hh"
#include "nix/util/signals.hh" #include "nix/util/signals.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-open.hh"
#include "nix/store/log-store.hh" #include "nix/store/log-store.hh"
#include "nix/cmd/common-eval-args.hh" #include "nix/cmd/common-eval-args.hh"
#include "nix/expr/get-drvs.hh" #include "nix/expr/get-drvs.hh"
@ -61,7 +61,10 @@ struct NixRepl
{ {
size_t debugTraceIndex; size_t debugTraceIndex;
// Arguments passed to :load, saved so they can be reloaded with :reload
Strings loadedFiles; Strings loadedFiles;
// Arguments passed to :load-flake, saved so they can be reloaded with :reload
Strings loadedFlakes;
std::function<AnnotatedValues()> getValues; std::function<AnnotatedValues()> getValues;
const static int envSize = 32768; const static int envSize = 32768;
@ -90,7 +93,8 @@ struct NixRepl
void loadFile(const Path & path); void loadFile(const Path & path);
void loadFlake(const std::string & flakeRef); void loadFlake(const std::string & flakeRef);
void loadFiles(); void loadFiles();
void reloadFiles(); void loadFlakes();
void reloadFilesAndFlakes();
void addAttrsToScope(Value & attrs); void addAttrsToScope(Value & attrs);
void addVarToScope(const Symbol name, Value & v); void addVarToScope(const Symbol name, Value & v);
Expr * parseString(std::string s); Expr * parseString(std::string s);
@ -244,14 +248,13 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
try { try {
auto dir = std::string(cur, 0, slash); auto dir = std::string(cur, 0, slash);
auto prefix2 = std::string(cur, slash + 1); auto prefix2 = std::string(cur, slash + 1);
for (auto & entry : std::filesystem::directory_iterator{dir == "" ? "/" : dir}) { for (auto & entry : DirectoryIterator{dir == "" ? "/" : dir}) {
checkInterrupt(); checkInterrupt();
auto name = entry.path().filename().string(); auto name = entry.path().filename().string();
if (name[0] != '.' && hasPrefix(name, prefix2)) if (name[0] != '.' && hasPrefix(name, prefix2))
completions.insert(prev + entry.path().string()); completions.insert(prev + entry.path().string());
} }
} catch (Error &) { } catch (Error &) {
} catch (std::filesystem::filesystem_error &) {
} }
} else if ((dot = cur.rfind('.')) == std::string::npos) { } else if ((dot = cur.rfind('.')) == std::string::npos) {
/* This is a variable name; look it up in the current scope. */ /* This is a variable name; look it up in the current scope. */
@ -467,7 +470,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
else if (command == ":r" || command == ":reload") { else if (command == ":r" || command == ":reload") {
state->resetFileCache(); state->resetFileCache();
reloadFiles(); reloadFilesAndFlakes();
} }
else if (command == ":e" || command == ":edit") { else if (command == ":e" || command == ":edit") {
@ -502,7 +505,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
// Reload right after exiting the editor // Reload right after exiting the editor
state->resetFileCache(); state->resetFileCache();
reloadFiles(); reloadFilesAndFlakes();
} }
else if (command == ":t") { else if (command == ":t") {
@ -717,6 +720,9 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
if (flakeRefS.empty()) if (flakeRefS.empty())
throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)");
loadedFlakes.remove(flakeRefS);
loadedFlakes.push_back(flakeRefS);
std::filesystem::path cwd; std::filesystem::path cwd;
try { try {
cwd = std::filesystem::current_path(); cwd = std::filesystem::current_path();
@ -755,11 +761,12 @@ void NixRepl::initEnv()
} }
void NixRepl::reloadFiles() void NixRepl::reloadFilesAndFlakes()
{ {
initEnv(); initEnv();
loadFiles(); loadFiles();
loadFlakes();
} }
@ -780,6 +787,18 @@ void NixRepl::loadFiles()
} }
void NixRepl::loadFlakes()
{
Strings old = loadedFlakes;
loadedFlakes.clear();
for (auto & i : old) {
notice("Loading flake '%1%'...", i);
loadFlake(i);
}
}
void NixRepl::addAttrsToScope(Value & attrs) void NixRepl::addAttrsToScope(Value & attrs)
{ {
state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }, "while evaluating an attribute set to be merged in the global scope"); state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }, "while evaluating an attribute set to be merged in the global scope");

View file

@ -37,13 +37,11 @@ include_dirs = [include_directories('.')]
headers = files( headers = files(
'nix_api_expr.h', 'nix_api_expr.h',
'nix_api_expr_internal.h',
'nix_api_external.h', 'nix_api_external.h',
'nix_api_value.h', 'nix_api_value.h',
) )
# TODO move this header to libexpr, maybe don't use it in tests?
headers += files('nix_api_expr_internal.h')
subdir('nix-meson-build-support/export-all-symbols') subdir('nix-meson-build-support/export-all-symbols')
subdir('nix-meson-build-support/windows-version') subdir('nix-meson-build-support/windows-version')

View file

@ -199,7 +199,9 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
!= NIX_OK) != NIX_OK)
return nullptr; return nullptr;
return nix_eval_state_build(context, builder); auto *state = nix_eval_state_build(context, builder);
nix_eval_state_builder_free(builder);
return state;
} }
void nix_state_free(EvalState * state) void nix_state_free(EvalState * state)

View file

@ -286,6 +286,11 @@ nix_err nix_gc_incref(nix_c_context * context, const void * object);
/** /**
* @brief Decrement the garbage collector reference counter for the given object * @brief Decrement the garbage collector reference counter for the given object
* *
* We also provide typed `nix_*_decref` functions, which are
* - safer to use
* - easier to integrate when deriving bindings
* - allow more flexibility
*
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] object The object to stop referencing * @param[in] object The object to stop referencing
*/ */

View file

@ -33,7 +33,7 @@ namespace nix {
ASSERT_EQ(PrintToString(e.info().msg), ASSERT_EQ(PrintToString(e.info().msg),
PrintToString(HintFmt("puppy"))); PrintToString(HintFmt("puppy")));
auto trace = e.info().traces.rbegin(); auto trace = e.info().traces.rbegin();
ASSERT_EQ(e.info().traces.size(), 2); ASSERT_EQ(e.info().traces.size(), 2u);
ASSERT_EQ(PrintToString(trace->hint), ASSERT_EQ(PrintToString(trace->hint),
PrintToString(HintFmt("doggy"))); PrintToString(HintFmt("doggy")));
trace++; trace++;
@ -54,8 +54,8 @@ namespace nix {
} catch (Error & e2) { } catch (Error & e2) {
e.addTrace(state.positions[noPos], "beans2"); e.addTrace(state.positions[noPos], "beans2");
//e2.addTrace(state.positions[noPos], "Something", ""); //e2.addTrace(state.positions[noPos], "Something", "");
ASSERT_TRUE(e.info().traces.size() == 2); ASSERT_TRUE(e.info().traces.size() == 2u);
ASSERT_TRUE(e2.info().traces.size() == 0); ASSERT_TRUE(e2.info().traces.size() == 0u);
ASSERT_FALSE(&e.info() == &e2.info()); ASSERT_FALSE(&e.info() == &e2.info());
} }
} }
@ -71,7 +71,7 @@ namespace nix {
} catch (BaseError & e) { \ } catch (BaseError & e) { \
ASSERT_EQ(PrintToString(e.info().msg), \ ASSERT_EQ(PrintToString(e.info().msg), \
PrintToString(message)); \ PrintToString(message)); \
ASSERT_EQ(e.info().traces.size(), 1) << "while testing " args << std::endl << e.what(); \ ASSERT_EQ(e.info().traces.size(), 1u) << "while testing " args << std::endl << e.what(); \
auto trace = e.info().traces.rbegin(); \ auto trace = e.info().traces.rbegin(); \
ASSERT_EQ(PrintToString(trace->hint), \ ASSERT_EQ(PrintToString(trace->hint), \
PrintToString(HintFmt("while calling the '%s' builtin", name))); \ PrintToString(HintFmt("while calling the '%s' builtin", name))); \
@ -90,7 +90,7 @@ namespace nix {
} catch (BaseError & e) { \ } catch (BaseError & e) { \
ASSERT_EQ(PrintToString(e.info().msg), \ ASSERT_EQ(PrintToString(e.info().msg), \
PrintToString(message)); \ PrintToString(message)); \
ASSERT_EQ(e.info().traces.size(), 2) << "while testing " args << std::endl << e.what(); \ ASSERT_EQ(e.info().traces.size(), 2u) << "while testing " args << std::endl << e.what(); \
auto trace = e.info().traces.rbegin(); \ auto trace = e.info().traces.rbegin(); \
ASSERT_EQ(PrintToString(trace->hint), \ ASSERT_EQ(PrintToString(trace->hint), \
PrintToString(context)); \ PrintToString(context)); \
@ -112,7 +112,7 @@ namespace nix {
} catch (BaseError & e) { \ } catch (BaseError & e) { \
ASSERT_EQ(PrintToString(e.info().msg), \ ASSERT_EQ(PrintToString(e.info().msg), \
PrintToString(message)); \ PrintToString(message)); \
ASSERT_EQ(e.info().traces.size(), 3) << "while testing " args << std::endl << e.what(); \ ASSERT_EQ(e.info().traces.size(), 3u) << "while testing " args << std::endl << e.what(); \
auto trace = e.info().traces.rbegin(); \ auto trace = e.info().traces.rbegin(); \
ASSERT_EQ(PrintToString(trace->hint), \ ASSERT_EQ(PrintToString(trace->hint), \
PrintToString(context1)); \ PrintToString(context1)); \
@ -137,7 +137,7 @@ namespace nix {
} catch (BaseError & e) { \ } catch (BaseError & e) { \
ASSERT_EQ(PrintToString(e.info().msg), \ ASSERT_EQ(PrintToString(e.info().msg), \
PrintToString(message)); \ PrintToString(message)); \
ASSERT_EQ(e.info().traces.size(), 4) << "while testing " args << std::endl << e.what(); \ ASSERT_EQ(e.info().traces.size(), 4u) << "while testing " args << std::endl << e.what(); \
auto trace = e.info().traces.rbegin(); \ auto trace = e.info().traces.rbegin(); \
ASSERT_EQ(PrintToString(trace->hint), \ ASSERT_EQ(PrintToString(trace->hint), \
PrintToString(context1)); \ PrintToString(context1)); \

View file

@ -222,7 +222,7 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context)
names.push_back(name); names.push_back(name);
} }
std::sort(names.begin(), names.end()); std::sort(names.begin(), names.end());
ASSERT_EQ(3, names.size()); ASSERT_EQ(3u, names.size());
EXPECT_THAT(names[0], testing::StrEq("just-a-file")); EXPECT_THAT(names[0], testing::StrEq("just-a-file"));
EXPECT_THAT(names[1], testing::StrEq("letsbuild")); EXPECT_THAT(names[1], testing::StrEq("letsbuild"));
EXPECT_THAT(names[2], testing::StrEq("not-actually-built-yet.drv")); EXPECT_THAT(names[2], testing::StrEq("not-actually-built-yet.drv"));

View file

@ -63,6 +63,9 @@ TEST_F(nix_api_expr_test, nix_expr_eval_external)
std::string string_value; std::string string_value;
nix_get_string(nullptr, valueResult, OBSERVE_STRING(string_value)); nix_get_string(nullptr, valueResult, OBSERVE_STRING(string_value));
ASSERT_STREQ("nix-external<MyExternalValueDesc( 42 )>", string_value.c_str()); ASSERT_STREQ("nix-external<MyExternalValueDesc( 42 )>", string_value.c_str());
nix_state_free(stateResult);
nix_state_free(stateFn);
} }
} }

View file

@ -134,12 +134,12 @@ TEST_F(nix_api_expr_test, nix_build_and_init_list_invalid)
{ {
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, nullptr, state, 0)); ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, nullptr, state, 0));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(0, nix_get_list_size(ctx, nullptr)); ASSERT_EQ(0u, nix_get_list_size(ctx, nullptr));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 0)); ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 0));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(0, nix_get_list_size(ctx, value)); ASSERT_EQ(0u, nix_get_list_size(ctx, value));
assert_ctx_err(); assert_ctx_err();
} }
@ -163,7 +163,7 @@ TEST_F(nix_api_expr_test, nix_build_and_init_list)
ASSERT_EQ(42, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 0))); ASSERT_EQ(42, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 0)));
ASSERT_EQ(43, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 1))); ASSERT_EQ(43, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 1)));
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 2)); ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 2));
ASSERT_EQ(10, nix_get_list_size(ctx, value)); ASSERT_EQ(10u, nix_get_list_size(ctx, value));
ASSERT_STREQ("a list", nix_get_typename(ctx, value)); ASSERT_STREQ("a list", nix_get_typename(ctx, value));
ASSERT_EQ(NIX_TYPE_LIST, nix_get_type(ctx, value)); ASSERT_EQ(NIX_TYPE_LIST, nix_get_type(ctx, value));
@ -180,7 +180,7 @@ TEST_F(nix_api_expr_test, nix_build_and_init_attr_invalid)
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, nullptr, state, 0)); ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, nullptr, state, 0));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(0, nix_get_attrs_size(ctx, nullptr)); ASSERT_EQ(0u, nix_get_attrs_size(ctx, nullptr));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(false, nix_has_attr_byname(ctx, nullptr, state, "no-value")); ASSERT_EQ(false, nix_has_attr_byname(ctx, nullptr, state, "no-value"));
assert_ctx_err(); assert_ctx_err();
@ -191,7 +191,7 @@ TEST_F(nix_api_expr_test, nix_build_and_init_attr_invalid)
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, 0)); ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, 0));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(0, nix_get_attrs_size(ctx, value)); ASSERT_EQ(0u, nix_get_attrs_size(ctx, value));
assert_ctx_err(); assert_ctx_err();
ASSERT_EQ(false, nix_has_attr_byname(ctx, value, state, "no-value")); ASSERT_EQ(false, nix_has_attr_byname(ctx, value, state, "no-value"));
assert_ctx_err(); assert_ctx_err();
@ -215,7 +215,7 @@ TEST_F(nix_api_expr_test, nix_build_and_init_attr)
nix_make_attrs(ctx, value, builder); nix_make_attrs(ctx, value, builder);
nix_bindings_builder_free(builder); nix_bindings_builder_free(builder);
ASSERT_EQ(2, nix_get_attrs_size(ctx, value)); ASSERT_EQ(2u, nix_get_attrs_size(ctx, value));
nix_value * out_value = nix_get_attr_byname(ctx, value, state, "a"); nix_value * out_value = nix_get_attr_byname(ctx, value, state, "a");
ASSERT_EQ(42, nix_get_int(ctx, out_value)); ASSERT_EQ(42, nix_get_int(ctx, out_value));
@ -374,7 +374,7 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_lazy_arg)
auto n = nix_get_attrs_size(ctx, r); auto n = nix_get_attrs_size(ctx, r);
assert_ctx_ok(); assert_ctx_ok();
ASSERT_EQ(1, n); ASSERT_EQ(1u, n);
// nix_get_attr_byname isn't lazy (it could have been) so it will throw the exception // nix_get_attr_byname isn't lazy (it could have been) so it will throw the exception
nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo"); nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo");

View file

@ -56,11 +56,31 @@ namespace nix {
TEST_F(PrimOpTest, ceil) { TEST_F(PrimOpTest, ceil) {
auto v = eval("builtins.ceil 1.9"); auto v = eval("builtins.ceil 1.9");
ASSERT_THAT(v, IsIntEq(2)); ASSERT_THAT(v, IsIntEq(2));
auto intMin = eval("builtins.ceil (-4611686018427387904 - 4611686018427387904)");
ASSERT_THAT(intMin, IsIntEq(std::numeric_limits<NixInt::Inner>::min()));
ASSERT_THROW(eval("builtins.ceil 1.0e200"), EvalError);
ASSERT_THROW(eval("builtins.ceil -1.0e200"), EvalError);
ASSERT_THROW(eval("builtins.ceil (1.0e200 * 1.0e200)"), EvalError); // inf
ASSERT_THROW(eval("builtins.ceil (-1.0e200 * 1.0e200)"), EvalError); // -inf
ASSERT_THROW(eval("builtins.ceil (1.0e200 * 1.0e200 - 1.0e200 * 1.0e200)"), EvalError); // nan
// bugs in previous Nix versions
ASSERT_THROW(eval("builtins.ceil (4611686018427387904 + 4611686018427387903)"), EvalError);
ASSERT_THROW(eval("builtins.ceil (-4611686018427387904 - 4611686018427387903)"), EvalError);
} }
TEST_F(PrimOpTest, floor) { TEST_F(PrimOpTest, floor) {
auto v = eval("builtins.floor 1.9"); auto v = eval("builtins.floor 1.9");
ASSERT_THAT(v, IsIntEq(1)); ASSERT_THAT(v, IsIntEq(1));
auto intMin = eval("builtins.ceil (-4611686018427387904 - 4611686018427387904)");
ASSERT_THAT(intMin, IsIntEq(std::numeric_limits<NixInt::Inner>::min()));
ASSERT_THROW(eval("builtins.ceil 1.0e200"), EvalError);
ASSERT_THROW(eval("builtins.ceil -1.0e200"), EvalError);
ASSERT_THROW(eval("builtins.ceil (1.0e200 * 1.0e200)"), EvalError); // inf
ASSERT_THROW(eval("builtins.ceil (-1.0e200 * 1.0e200)"), EvalError); // -inf
ASSERT_THROW(eval("builtins.ceil (1.0e200 * 1.0e200 - 1.0e200 * 1.0e200)"), EvalError); // nan
// bugs in previous Nix versions
ASSERT_THROW(eval("builtins.ceil (4611686018427387904 + 4611686018427387903)"), EvalError);
ASSERT_THROW(eval("builtins.ceil (-4611686018427387904 - 4611686018427387903)"), EvalError);
} }
TEST_F(PrimOpTest, tryEvalFailure) { TEST_F(PrimOpTest, tryEvalFailure) {
@ -204,7 +224,7 @@ namespace nix {
auto v = eval("builtins.listToAttrs []"); auto v = eval("builtins.listToAttrs []");
ASSERT_THAT(v, IsAttrsOfSize(0)); ASSERT_THAT(v, IsAttrsOfSize(0));
ASSERT_EQ(v.type(), nAttrs); ASSERT_EQ(v.type(), nAttrs);
ASSERT_EQ(v.attrs()->size(), 0); ASSERT_EQ(v.attrs()->size(), 0u);
} }
TEST_F(PrimOpTest, listToAttrsNotFieldName) { TEST_F(PrimOpTest, listToAttrsNotFieldName) {
@ -383,7 +403,7 @@ namespace nix {
TEST_F(PrimOpTest, genList) { TEST_F(PrimOpTest, genList) {
auto v = eval("builtins.genList (x: x + 1) 3"); auto v = eval("builtins.genList (x: x + 1) 3");
ASSERT_EQ(v.type(), nList); ASSERT_EQ(v.type(), nList);
ASSERT_EQ(v.listSize(), 3); ASSERT_EQ(v.listSize(), 3u);
for (const auto [i, elem] : enumerate(v.listItems())) { for (const auto [i, elem] : enumerate(v.listItems())) {
ASSERT_THAT(*elem, IsThunk()); ASSERT_THAT(*elem, IsThunk());
state.forceValue(*elem, noPos); state.forceValue(*elem, noPos);
@ -394,7 +414,7 @@ namespace nix {
TEST_F(PrimOpTest, sortLessThan) { TEST_F(PrimOpTest, sortLessThan) {
auto v = eval("builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]"); auto v = eval("builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]");
ASSERT_EQ(v.type(), nList); ASSERT_EQ(v.type(), nList);
ASSERT_EQ(v.listSize(), 6); ASSERT_EQ(v.listSize(), 6u);
const std::vector<int> numbers = { 42, 77, 147, 249, 483, 526 }; const std::vector<int> numbers = { 42, 77, 147, 249, 483, 526 };
for (const auto [n, elem] : enumerate(v.listItems())) for (const auto [n, elem] : enumerate(v.listItems()))
@ -414,7 +434,7 @@ namespace nix {
auto wrong = v.attrs()->get(createSymbol("wrong")); auto wrong = v.attrs()->get(createSymbol("wrong"));
ASSERT_NE(wrong, nullptr); ASSERT_NE(wrong, nullptr);
ASSERT_EQ(wrong->value->type(), nList); ASSERT_EQ(wrong->value->type(), nList);
ASSERT_EQ(wrong->value->listSize(), 3); ASSERT_EQ(wrong->value->listSize(), 3u);
ASSERT_THAT(*wrong->value, IsListOfSize(3)); ASSERT_THAT(*wrong->value, IsListOfSize(3));
ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1)); ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1));
ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9)); ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9));
@ -424,7 +444,7 @@ namespace nix {
TEST_F(PrimOpTest, concatMap) { TEST_F(PrimOpTest, concatMap) {
auto v = eval("builtins.concatMap (x: x ++ [0]) [ [1 2] [3 4] ]"); auto v = eval("builtins.concatMap (x: x ++ [0]) [ [1 2] [3 4] ]");
ASSERT_EQ(v.type(), nList); ASSERT_EQ(v.type(), nList);
ASSERT_EQ(v.listSize(), 6); ASSERT_EQ(v.listSize(), 6u);
const std::vector<int> numbers = { 1, 2, 0, 3, 4, 0 }; const std::vector<int> numbers = { 1, 2, 0, 3, 4, 0 };
for (const auto [n, elem] : enumerate(v.listItems())) for (const auto [n, elem] : enumerate(v.listItems()))

View file

@ -74,7 +74,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
auto a = v->attrs()->get(state.symbols.create(attr)); auto a = v->attrs()->get(state.symbols.create(attr));
if (!a) { if (!a) {
std::set<std::string> attrNames; StringSet attrNames;
for (auto & attr : *v->attrs()) for (auto & attr : *v->attrs())
attrNames.insert(std::string(state.symbols[attr.name])); attrNames.insert(std::string(state.symbols[attr.name]));

View file

@ -492,7 +492,7 @@ Value & AttrCursor::forceValue()
Suggestions AttrCursor::getSuggestionsForAttr(Symbol name) Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
{ {
auto attrNames = getAttrs(); auto attrNames = getAttrs();
std::set<std::string> strAttrNames; StringSet strAttrNames;
for (auto & name : attrNames) for (auto & name : attrNames)
strAttrNames.insert(std::string(root->state.symbols[name])); strAttrNames.insert(std::string(root->state.symbols[name]));

View file

@ -110,5 +110,6 @@ template class EvalErrorBuilder<UndefinedVarError>;
template class EvalErrorBuilder<MissingArgumentError>; template class EvalErrorBuilder<MissingArgumentError>;
template class EvalErrorBuilder<InfiniteRecursionError>; template class EvalErrorBuilder<InfiniteRecursionError>;
template class EvalErrorBuilder<InvalidPathError>; template class EvalErrorBuilder<InvalidPathError>;
template class EvalErrorBuilder<IFDError>;
} }

View file

@ -252,6 +252,24 @@ EvalState::EvalState(
makeMountedSourceAccessor( makeMountedSourceAccessor(
{ {
{CanonPath::root, makeEmptySourceAccessor()}, {CanonPath::root, makeEmptySourceAccessor()},
/* In the pure eval case, we can simply require
valid paths. However, in the *impure* eval
case this gets in the way of the union
mechanism, because an invalid access in the
upper layer will *not* be caught by the union
source accessor, but instead abort the entire
lookup.
This happens when the store dir in the
ambient file system has a path (e.g. because
another Nix store there), but the relocated
store does not.
TODO make the various source accessors doing
access control all throw the same type of
exception, and make union source accessor
catch it, so we don't need to do this hack.
*/
{CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))} {CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))}
})) }))
, rootFS( , rootFS(
@ -1435,7 +1453,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} else { } else {
state.forceAttrs(*vAttrs, pos, "while selecting an attribute"); state.forceAttrs(*vAttrs, pos, "while selecting an attribute");
if (!(j = vAttrs->attrs()->get(name))) { if (!(j = vAttrs->attrs()->get(name))) {
std::set<std::string> allAttrNames; StringSet allAttrNames;
for (auto & attr : *vAttrs->attrs()) for (auto & attr : *vAttrs->attrs())
allAttrNames.insert(std::string(state.symbols[attr.name])); allAttrNames.insert(std::string(state.symbols[attr.name]));
auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]); auto suggestions = Suggestions::bestMatches(allAttrNames, state.symbols[name]);
@ -1592,7 +1610,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
user. */ user. */
for (auto & i : *args[0]->attrs()) for (auto & i : *args[0]->attrs())
if (!lambda.formals->has(i.name)) { if (!lambda.formals->has(i.name)) {
std::set<std::string> formalNames; StringSet formalNames;
for (auto & formal : lambda.formals->formals) for (auto & formal : lambda.formals->formals)
formalNames.insert(std::string(symbols[formal.name])); formalNames.insert(std::string(symbols[formal.name]));
auto suggestions = Suggestions::bestMatches(formalNames, symbols[i.name]); auto suggestions = Suggestions::bestMatches(formalNames, symbols[i.name]);

View file

@ -54,6 +54,7 @@ MakeError(TypeError, EvalError);
MakeError(UndefinedVarError, EvalError); MakeError(UndefinedVarError, EvalError);
MakeError(MissingArgumentError, EvalError); MakeError(MissingArgumentError, EvalError);
MakeError(InfiniteRecursionError, EvalError); MakeError(InfiniteRecursionError, EvalError);
MakeError(IFDError, EvalBaseError);
struct InvalidPathError : public EvalError struct InvalidPathError : public EvalError
{ {

View file

@ -151,6 +151,16 @@ struct EvalSettings : Config
)" )"
}; };
Setting<bool> traceImportFromDerivation{
this, false, "trace-import-from-derivation",
R"(
By default, Nix allows [Import from Derivation](@docroot@/language/import-from-derivation.md).
When this setting is `true`, Nix will log a warning indicating that it performed such an import.
This option has no effect if `allow-import-from-derivation` is disabled.
)"
};
Setting<bool> enableImportFromDerivation{ Setting<bool> enableImportFromDerivation{
this, true, "allow-import-from-derivation", this, true, "allow-import-from-derivation",
R"( R"(

View file

@ -27,7 +27,12 @@ constexpr size_t conservativeStackReservation = 16;
struct RegisterPrimOp struct RegisterPrimOp
{ {
typedef std::vector<PrimOp> PrimOps; typedef std::vector<PrimOp> PrimOps;
static PrimOps * primOps;
static PrimOps & primOps()
{
static PrimOps primOps;
return primOps;
}
/** /**
* You can register a constant by passing an arity of 0. fun * You can register a constant by passing an arity of 0. fun

View file

@ -81,26 +81,29 @@ public:
class SymbolTable class SymbolTable
{ {
private: private:
std::unordered_map<std::string_view, std::pair<const std::string *, uint32_t>> symbols; /**
* Map from string view (backed by ChunkedVector) -> offset into the store.
* ChunkedVector references are never invalidated.
*/
std::unordered_map<std::string_view, uint32_t> symbols;
ChunkedVector<std::string, 8192> store{16}; ChunkedVector<std::string, 8192> store{16};
public: public:
/** /**
* converts a string into a symbol. * Converts a string into a symbol.
*/ */
Symbol create(std::string_view s) Symbol create(std::string_view s)
{ {
// Most symbols are looked up more than once, so we trade off insertion performance // Most symbols are looked up more than once, so we trade off insertion performance
// for lookup performance. // for lookup performance.
// TODO: could probably be done more efficiently with transparent Hash and Equals
// on the original implementation using unordered_set
// FIXME: make this thread-safe. // FIXME: make this thread-safe.
auto it = symbols.find(s); auto it = symbols.find(s);
if (it != symbols.end()) return Symbol(it->second.second + 1); if (it != symbols.end())
return Symbol(it->second + 1);
const auto & [rawSym, idx] = store.add(std::string(s)); const auto & [rawSym, idx] = store.add(s);
symbols.emplace(rawSym, std::make_pair(&rawSym, idx)); symbols.emplace(rawSym, idx);
return Symbol(idx + 1); return Symbol(idx + 1);
} }

View file

@ -1,3 +1,4 @@
%option 8bit
%option reentrant bison-bridge bison-locations %option reentrant bison-bridge bison-locations
%option align %option align
%option noyywrap %option noyywrap

View file

@ -112,6 +112,7 @@ lexer_tab = custom_target(
], ],
command : [ command : [
'flex', 'flex',
'-Cf', # Use full scanner tables
'--outfile', '--outfile',
'@OUTPUT0@', '@OUTPUT0@',
'--header-file=' + '@OUTPUT1@', '--header-file=' + '@OUTPUT1@',

View file

@ -179,7 +179,12 @@ static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
%% %%
start: expr { state->result = $1; }; start: expr {
state->result = $1;
// This parser does not use yynerrs; suppress the warning.
(void) yynerrs;
};
expr: expr_function; expr: expr_function;

View file

@ -97,12 +97,20 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS
if (drvs.empty()) return {}; if (drvs.empty()) return {};
if (isIFD && !settings.enableImportFromDerivation) if (isIFD) {
error<EvalBaseError>( if (!settings.enableImportFromDerivation)
error<IFDError>(
"cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled",
drvs.begin()->to_string(*store) drvs.begin()->to_string(*store)
).debugThrow(); ).debugThrow();
if (settings.traceImportFromDerivation)
warn(
"built '%1%' during evaluation due to an import from derivation",
drvs.begin()->to_string(*store)
);
}
/* Build/substitute the context. */ /* Build/substitute the context. */
std::vector<DerivedPath> buildReqs; std::vector<DerivedPath> buildReqs;
buildReqs.reserve(drvs.size()); buildReqs.reserve(drvs.size());
@ -895,18 +903,40 @@ static void prim_ceil(EvalState & state, const PosIdx pos, Value * * args, Value
{ {
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), auto value = state.forceFloat(*args[0], args[0]->determinePos(pos),
"while evaluating the first argument passed to builtins.ceil"); "while evaluating the first argument passed to builtins.ceil");
v.mkInt(ceil(value)); auto ceilValue = ceil(value);
bool isInt = args[0]->type() == nInt;
constexpr NixFloat int_min = std::numeric_limits<NixInt::Inner>::min(); // power of 2, so that no rounding occurs
if (ceilValue >= int_min && ceilValue < -int_min) {
v.mkInt(ceilValue);
} else if (isInt) {
// a NixInt, e.g. INT64_MAX, can be rounded to -int_min due to the cast to NixFloat
state.error<EvalError>("Due to a bug (see https://github.com/NixOS/nix/issues/12899) the NixInt argument %1% caused undefined behavior in previous Nix versions.\n\tFuture Nix versions might implement the correct behavior.", args[0]->integer().value).atPos(pos).debugThrow();
} else {
state.error<EvalError>("NixFloat argument %1% is not in the range of NixInt", args[0]->fpoint()).atPos(pos).debugThrow();
}
// `forceFloat` casts NixInt to NixFloat, but instead NixInt args shall be returned unmodified
if (isInt) {
auto arg = args[0]->integer();
auto res = v.integer();
if (arg != res) {
state.error<EvalError>("Due to a bug (see https://github.com/NixOS/nix/issues/12899) a loss of precision occured in previous Nix versions because the NixInt argument %1% was rounded to %2%.\n\tFuture Nix versions might implement the correct behavior.", arg, res).atPos(pos).debugThrow();
}
}
} }
static RegisterPrimOp primop_ceil({ static RegisterPrimOp primop_ceil({
.name = "__ceil", .name = "__ceil",
.args = {"double"}, .args = {"number"},
.doc = R"( .doc = R"(
Converts an IEEE-754 double-precision floating-point number (*double*) to Rounds and converts *number* to the next higher NixInt value if possible, i.e. `ceil *number* >= *number*` and
the next higher integer. `ceil *number* - *number* < 1`.
If the datatype is neither an integer nor a "float", an evaluation error will be An evaluation error is thrown, if there exists no such NixInt value `ceil *number*`.
thrown. Due to bugs in previous Nix versions an evaluation error might be thrown, if the datatype of *number* is
a NixInt and if `*number* < -9007199254740992` or `*number* > 9007199254740992`.
If the datatype of *number* is neither a NixInt (signed 64-bit integer) nor a NixFloat
(IEEE-754 double-precision floating-point number), an evaluation error will be thrown.
)", )",
.fun = prim_ceil, .fun = prim_ceil,
}); });
@ -914,18 +944,40 @@ static RegisterPrimOp primop_ceil({
static void prim_floor(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_floor(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "while evaluating the first argument passed to builtins.floor"); auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "while evaluating the first argument passed to builtins.floor");
v.mkInt(floor(value)); auto floorValue = floor(value);
bool isInt = args[0]->type() == nInt;
constexpr NixFloat int_min = std::numeric_limits<NixInt::Inner>::min(); // power of 2, so that no rounding occurs
if (floorValue >= int_min && floorValue < -int_min) {
v.mkInt(floorValue);
} else if (isInt) {
// a NixInt, e.g. INT64_MAX, can be rounded to -int_min due to the cast to NixFloat
state.error<EvalError>("Due to a bug (see https://github.com/NixOS/nix/issues/12899) the NixInt argument %1% caused undefined behavior in previous Nix versions.\n\tFuture Nix versions might implement the correct behavior.", args[0]->integer().value).atPos(pos).debugThrow();
} else {
state.error<EvalError>("NixFloat argument %1% is not in the range of NixInt", args[0]->fpoint()).atPos(pos).debugThrow();
}
// `forceFloat` casts NixInt to NixFloat, but instead NixInt args shall be returned unmodified
if (isInt) {
auto arg = args[0]->integer();
auto res = v.integer();
if (arg != res) {
state.error<EvalError>("Due to a bug (see https://github.com/NixOS/nix/issues/12899) a loss of precision occured in previous Nix versions because the NixInt argument %1% was rounded to %2%.\n\tFuture Nix versions might implement the correct behavior.", arg, res).atPos(pos).debugThrow();
}
}
} }
static RegisterPrimOp primop_floor({ static RegisterPrimOp primop_floor({
.name = "__floor", .name = "__floor",
.args = {"double"}, .args = {"number"},
.doc = R"( .doc = R"(
Converts an IEEE-754 double-precision floating-point number (*double*) to Rounds and converts *number* to the next lower NixInt value if possible, i.e. `floor *number* <= *number*` and
the next lower integer. `*number* - floor *number* < 1`.
If the datatype is neither an integer nor a "float", an evaluation error will be An evaluation error is thrown, if there exists no such NixInt value `floor *number*`.
thrown. Due to bugs in previous Nix versions an evaluation error might be thrown, if the datatype of *number* is
a NixInt and if `*number* < -9007199254740992` or `*number* > 9007199254740992`.
If the datatype of *number* is neither a NixInt (signed 64-bit integer) nor a NixFloat
(IEEE-754 double-precision floating-point number), an evaluation error will be thrown.
)", )",
.fun = prim_floor, .fun = prim_floor,
}); });
@ -2813,7 +2865,13 @@ static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * *
static RegisterPrimOp primop_unsafeGetAttrPos(PrimOp { static RegisterPrimOp primop_unsafeGetAttrPos(PrimOp {
.name = "__unsafeGetAttrPos", .name = "__unsafeGetAttrPos",
.args = {"s", "set"},
.arity = 2, .arity = 2,
.doc = R"(
`unsafeGetAttrPos` returns the position of the attribute named *s*
from *set*. This is used by Nixpkgs to provide location information
in error messages.
)",
.fun = prim_unsafeGetAttrPos, .fun = prim_unsafeGetAttrPos,
}); });
@ -4299,9 +4357,7 @@ struct RegexCache
{ {
struct State struct State
{ {
// TODO use C++20 transparent comparison when available std::unordered_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache;
std::unordered_map<std::string_view, std::regex> cache;
std::list<std::string> keys;
}; };
Sync<State> state_; Sync<State> state_;
@ -4312,8 +4368,14 @@ struct RegexCache
auto it = state->cache.find(re); auto it = state->cache.find(re);
if (it != state->cache.end()) if (it != state->cache.end())
return it->second; return it->second;
state->keys.emplace_back(re); /* No std::regex constructor overload from std::string_view, but can be constructed
return state->cache.emplace(state->keys.back(), std::regex(state->keys.back(), std::regex::extended)).first->second; from a pointer + size or an iterator range. */
return state->cache
.emplace(
std::piecewise_construct,
std::forward_as_tuple(re),
std::forward_as_tuple(/*s=*/re.data(), /*count=*/re.size(), std::regex::extended))
.first->second;
} }
}; };
@ -4697,13 +4759,9 @@ static RegisterPrimOp primop_splitVersion({
*************************************************************/ *************************************************************/
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
RegisterPrimOp::RegisterPrimOp(PrimOp && primOp) RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
{ {
if (!primOps) primOps = new PrimOps; primOps().push_back(std::move(primOp));
primOps->push_back(std::move(primOp));
} }
@ -4957,10 +5015,14 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
)", )",
}); });
if (RegisterPrimOp::primOps) for (auto & primOp : RegisterPrimOp::primOps())
for (auto & primOp : *RegisterPrimOp::primOps) if (experimentalFeatureSettings.isEnabled(primOp.experimentalFeature)) {
if (experimentalFeatureSettings.isEnabled(primOp.experimentalFeature)) auto primOpAdjusted = primOp;
{ primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity);
addPrimOp(std::move(primOpAdjusted));
}
for (auto & primOp : evalSettings.extraPrimOps) {
auto primOpAdjusted = primOp; auto primOpAdjusted = primOp;
primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity); primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity);
addPrimOp(std::move(primOpAdjusted)); addPrimOp(std::move(primOpAdjusted));

View file

@ -1,5 +1,5 @@
#include "nix/expr/primops.hh" #include "nix/expr/primops.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-open.hh"
#include "nix/store/realisation.hh" #include "nix/store/realisation.hh"
#include "nix/store/make-content-addressed.hh" #include "nix/store/make-content-addressed.hh"
#include "nix/util/url.hh" #include "nix/util/url.hh"

View file

@ -11,6 +11,7 @@ namespace nix {
using json = nlohmann::json; using json = nlohmann::json;
// TODO: rename. It doesn't print.
json printValueAsJSON(EvalState & state, bool strict, json printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, NixStringContext & context, bool copyToStore) Value & v, const PosIdx pos, NixStringContext & context, bool copyToStore)
{ {

1
src/libfetchers-c/.version Symbolic link
View file

@ -0,0 +1 @@
../../.version

View file

@ -0,0 +1,65 @@
project('nix-fetchers-c', 'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',
license : 'LGPL-2.1-or-later',
)
cxx = meson.get_compiler('cpp')
subdir('nix-meson-build-support/deps-lists')
deps_private_maybe_subproject = [
dependency('nix-util'),
dependency('nix-store'),
dependency('nix-fetchers'),
]
deps_public_maybe_subproject = [
dependency('nix-util-c'),
dependency('nix-store-c'),
]
subdir('nix-meson-build-support/subprojects')
add_project_arguments(
language : 'cpp',
)
subdir('nix-meson-build-support/common')
sources = files(
'nix_api_fetchers.cc',
)
include_dirs = [include_directories('.')]
headers = files(
'nix_api_fetchers.h',
'nix_api_fetchers_internal.hh',
)
# TODO move this header to libexpr, maybe don't use it in tests?
headers += files('nix_api_fetchers.h')
subdir('nix-meson-build-support/export-all-symbols')
subdir('nix-meson-build-support/windows-version')
this_library = library(
'nixfetchersc',
sources,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args: linker_export_flags,
prelink : true, # For C++ static initializers
install : true,
)
install_headers(headers, preserve_path : true)
libraries_private = []
subdir('nix-meson-build-support/export')

View file

@ -0,0 +1 @@
../../nix-meson-build-support

View file

@ -0,0 +1,19 @@
#include "nix_api_fetchers.h"
#include "nix_api_fetchers_internal.hh"
#include "nix_api_util_internal.h"
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context)
{
try {
auto fetchersSettings = nix::make_ref<nix::fetchers::Settings>(nix::fetchers::Settings{});
return new nix_fetchers_settings{
.settings = fetchersSettings,
};
}
NIXC_CATCH_ERRS_NULL
}
void nix_fetchers_settings_free(nix_fetchers_settings * settings)
{
delete settings;
}

View file

@ -0,0 +1,32 @@
#ifndef NIX_API_FETCHERS_H
#define NIX_API_FETCHERS_H
/** @defgroup libfetchers libfetchers
* @brief Bindings to the Nix fetchers library
* @{
*/
/** @file
* @brief Main entry for the libfetchers C bindings
*/
#include "nix_api_util.h"
#ifdef __cplusplus
extern "C" {
#endif
// cffi start
// Type definitions
/**
* @brief Shared settings object
*/
typedef struct nix_fetchers_settings nix_fetchers_settings;
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context);
void nix_fetchers_settings_free(nix_fetchers_settings * settings);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // NIX_API_FETCHERS_H

View file

@ -0,0 +1,12 @@
#pragma once
#include "nix/fetchers/fetch-settings.hh"
#include "nix/util/ref.hh"
/**
* A shared reference to `nix::fetchers::Settings`
* @see nix::fetchers::Settings
*/
struct nix_fetchers_settings
{
nix::ref<nix::fetchers::Settings> settings;
};

View file

@ -0,0 +1,50 @@
{
lib,
mkMesonLibrary,
nix-store-c,
nix-expr-c,
nix-util-c,
nix-fetchers,
# Configuration Options
version,
}:
let
inherit (lib) fileset;
in
mkMesonLibrary (finalAttrs: {
pname = "nix-fetchers-c";
inherit version;
workDir = ./.;
fileset = fileset.unions [
../../nix-meson-build-support
./nix-meson-build-support
../../.version
./.version
./meson.build
# ./meson.options
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
(fileset.fileFilter (file: file.hasExt "h") ./.)
];
propagatedBuildInputs = [
nix-util-c
nix-expr-c
nix-store-c
nix-fetchers
];
mesonFlags = [
];
meta = {
platforms = lib.platforms.unix ++ lib.platforms.windows;
};
})

View file

@ -11,14 +11,10 @@
namespace nix { namespace nix {
namespace fs {
using namespace std::filesystem;
}
class GitUtilsTest : public ::testing::Test class GitUtilsTest : public ::testing::Test
{ {
// We use a single repository for all tests. // We use a single repository for all tests.
fs::path tmpDir; std::filesystem::path tmpDir;
std::unique_ptr<AutoDelete> delTmpDir; std::unique_ptr<AutoDelete> delTmpDir;
public: public:
@ -90,11 +86,11 @@ TEST_F(GitUtilsTest, sink_basic)
auto result = repo->dereferenceSingletonDirectory(sink->flush()); auto result = repo->dereferenceSingletonDirectory(sink->flush());
auto accessor = repo->getAccessor(result, false, getRepoName()); auto accessor = repo->getAccessor(result, false, getRepoName());
auto entries = accessor->readDirectory(CanonPath::root); auto entries = accessor->readDirectory(CanonPath::root);
ASSERT_EQ(entries.size(), 5); ASSERT_EQ(entries.size(), 5u);
ASSERT_EQ(accessor->readFile(CanonPath("hello")), "hello world"); ASSERT_EQ(accessor->readFile(CanonPath("hello")), "hello world");
ASSERT_EQ(accessor->readFile(CanonPath("bye")), "thanks for all the fish"); ASSERT_EQ(accessor->readFile(CanonPath("bye")), "thanks for all the fish");
ASSERT_EQ(accessor->readLink(CanonPath("bye-link")), "bye"); ASSERT_EQ(accessor->readLink(CanonPath("bye-link")), "bye");
ASSERT_EQ(accessor->readDirectory(CanonPath("empty")).size(), 0); ASSERT_EQ(accessor->readDirectory(CanonPath("empty")).size(), 0u);
ASSERT_EQ(accessor->readFile(CanonPath("links/foo")), "hello world"); ASSERT_EQ(accessor->readFile(CanonPath("links/foo")), "hello world");
}; };

View file

@ -17,6 +17,7 @@ subdir('nix-meson-build-support/deps-lists')
deps_private_maybe_subproject = [ deps_private_maybe_subproject = [
dependency('nix-store-test-support'), dependency('nix-store-test-support'),
dependency('nix-fetchers'), dependency('nix-fetchers'),
dependency('nix-fetchers-c'),
] ]
deps_public_maybe_subproject = [ deps_public_maybe_subproject = [
] ]
@ -39,6 +40,7 @@ subdir('nix-meson-build-support/common')
sources = files( sources = files(
'access-tokens.cc', 'access-tokens.cc',
'git-utils.cc', 'git-utils.cc',
'nix_api_fetchers.cc',
'public-key.cc', 'public-key.cc',
) )

View file

@ -0,0 +1,18 @@
#include "gmock/gmock.h"
#include <gtest/gtest.h>
#include "nix_api_fetchers.h"
#include "nix/store/tests/nix_api_store.hh"
namespace nixC {
TEST_F(nix_api_store_test, nix_api_fetchers_new_free)
{
nix_fetchers_settings * settings = nix_fetchers_settings_new(ctx);
assert_ctx_ok();
ASSERT_NE(nullptr, settings);
nix_fetchers_settings_free(settings);
}
} // namespace nixC

View file

@ -5,6 +5,7 @@
mkMesonExecutable, mkMesonExecutable,
nix-fetchers, nix-fetchers,
nix-fetchers-c,
nix-store-test-support, nix-store-test-support,
libgit2, libgit2,
@ -40,6 +41,7 @@ mkMesonExecutable (finalAttrs: {
buildInputs = [ buildInputs = [
nix-fetchers nix-fetchers
nix-fetchers-c
nix-store-test-support nix-store-test-support
rapidcheck rapidcheck
gtest gtest

Some files were not shown because too many files have changed in this diff Show more