+```
+
+Every WASI module must export:
+- A `memory` object that the host can use to read/write data.
+- `_start()`, the standard WASI entry point. This function takes no parameters.
+
+The input value is passed as a command-line argument: `argv[1]` is set to the decimal representation of the `ValueId` of the input value.
+
+To return a result to Nix, the module must call the `return_to_nix` host function (see below) with the `ValueId` of the result. If `_start` finishes without calling `return_to_nix`, an error is raised.
+
+Standard output and standard error from the WASI module are captured and emitted as Nix warnings (one warning per line).
+
+## Host Functions
+
+All host functions are imported from the `env` module.
+
+### Error Handling
+
+#### `panic(ptr: u32, len: u32)`
+
+Aborts execution with an error message.
+
+**Parameters:**
+- `ptr` - Pointer to UTF-8 encoded error message in Wasm memory
+- `len` - Length of the error message in bytes
+
+#### `warn(ptr: u32, len: u32)`
+
+Emits a warning message.
+
+**Parameters:**
+- `ptr` - Pointer to UTF-8 encoded warning message in Wasm memory
+- `len` - Length of the warning message in bytes
+
+### Type Inspection
+
+#### `get_type(value: ValueId) -> u32`
+
+Returns the type of a Nix value.
+
+**Parameters:**
+- `value` - ID of a Nix value
+
+**Return values:**
+- `1` - Integer
+- `2` - Float
+- `3` - Boolean
+- `4` - String
+- `5` - Path
+- `6` - Null
+- `7` - Attribute set
+- `8` - List
+- `9` - Function
+
+**Note:** Forces evaluation of the value.
+
+### Integer Operations
+
+#### `make_int(n: i64) -> ValueId`
+
+Creates a Nix integer value.
+
+**Parameters:**
+- `n` - The integer value
+
+**Returns:** Value ID of the created integer
+
+#### `get_int(value: ValueId) -> i64`
+
+Extracts an integer from a Nix value. Throws an error if the value is not an integer.
+
+**Parameters:**
+- `value` - ID of a Nix integer value
+
+**Returns:** The integer value
+
+### Float Operations
+
+#### `make_float(x: f64) -> ValueId`
+
+Creates a Nix float value.
+
+**Parameters:**
+- `x` - The float value
+
+**Returns:** Value ID of the created float
+
+#### `get_float(value: ValueId) -> f64`
+
+Extracts a float from a Nix value. Throws an error if the value is not a float.
+
+**Parameters:**
+- `value` - ID of a Nix float value
+
+**Returns:** The float value
+
+### Boolean Operations
+
+#### `make_bool(b: i32) -> ValueId`
+
+Creates a Nix Boolean value.
+
+**Parameters:**
+- `b` - Boolean value (0 = false, non-zero = true)
+
+**Returns:** Value ID of the created Boolean
+
+#### `get_bool(value: ValueId) -> i32`
+
+Extracts a Boolean from a Nix value. Throws an error if the value is not a Boolean.
+
+**Parameters:**
+- `value` - ID of a Nix Boolean value
+
+**Returns:** 0 for false, 1 for true
+
+### Null Operations
+
+#### `make_null() -> ValueId`
+
+Creates a Nix null value.
+
+**Returns:** Value ID of the null value
+
+### String Operations
+
+#### `make_string(ptr: u32, len: u32) -> ValueId`
+
+Creates a Nix string value from Wasm memory.
+
+**Parameters:**
+- `ptr` - Pointer to a string in Wasm memory
+- `len` - Length of the string in bytes
+
+**Note:** Strings do not require a null terminator.
+
+**Returns:** Value ID of the created string
+
+#### `copy_string(value: ValueId, ptr: u32, max_len: u32) -> u32`
+
+Copies a Nix string value into Wasm memory.
+
+**Parameters:**
+- `value` - ID of a string value
+- `ptr` - Pointer to buffer in Wasm memory
+- `max_len` - Maximum number of bytes to copy
+
+**Returns:** The actual length of the string in bytes
+
+**Note:** If the returned length is greater than `max_len`, no data is copied. Call again with a larger buffer to get the full string.
+
+### Path Operations
+
+#### `make_path(base: ValueId, ptr: u32, len: u32) -> ValueId`
+
+Creates a Nix path value relative to a base path.
+
+**Parameters:**
+- `base` - ID of a path value
+- `ptr` - Pointer to a string in Wasm memory
+- `len` - Length of the path string in bytes
+
+**Returns:** ID of a new path value
+
+**Note:** The path string is interpreted relative to the base path. The resulting path is in the same source tree ("source accessor") as the original path.
+
+#### `copy_path(value: ValueId, ptr: u32, max_len: u32) -> u32`
+
+Copies a Nix path value into Wasm memory as an absolute path string.
+
+**Parameters:**
+- `value` - ID of a path value
+- `ptr` - Pointer to buffer in Wasm memory
+- `max_len` - Maximum number of bytes to copy
+
+**Returns:** The actual length of the path string in bytes
+
+**Note:** If the returned length is greater than `max_len`, no data is copied.
+
+### List Operations
+
+#### `make_list(ptr: u32, len: u32) -> ValueId`
+
+Creates a Nix list from an array of value IDs in Wasm memory.
+
+**Parameters:**
+- `ptr` - Pointer to array of `ValueId` (u32) in Wasm memory
+- `len` - Number of elements in the array
+
+**Returns:** Value ID of the created list
+
+**Note:** The array must contain `len * 4` bytes (each ValueId is 4 bytes).
+
+#### `copy_list(value: ValueId, ptr: u32, max_len: u32) -> u32`
+
+Copies a Nix list into Wasm memory as an array of value IDs.
+
+**Parameters:**
+- `value` - ID of a list value
+- `ptr` - Pointer to buffer in Wasm memory
+- `max_len` - Maximum number of elements to copy
+
+**Returns:** The actual number of elements in the list
+
+**Note:** If the returned length is greater than `max_len`, no data is copied. Each element is written as a `ValueId` (4 bytes). The buffer must be `max_len * 4` bytes large.
+
+### Attribute Set Operations
+
+#### `make_attrset(ptr: u32, len: u32) -> ValueId`
+
+Creates a Nix attribute set from an array of attributes in Wasm memory.
+
+**Parameters:**
+- `ptr` - Pointer to array of attribute structures in Wasm memory
+- `len` - Number of attributes
+
+**Returns:** Value ID of the created attribute set
+
+**Attribute structure format:**
+```c
+struct Attr {
+ name_ptr: u32, // Pointer to attribute name
+ name_len: u32, // Length of attribute name in bytes
+ value_id: u32, // ID of the attribute value
+}
+```
+
+Each `Attr` element is 12 bytes (3 × 4 bytes).
+
+#### `copy_attrset(value: ValueId, ptr: u32, max_len: u32) -> u32`
+
+Copies a Nix attribute set into Wasm memory as an array of attribute structures.
+
+**Parameters:**
+- `value` - ID of a Nix attribute set value
+- `ptr` - Pointer to buffer in Wasm memory
+- `max_len` - Maximum number of attributes to copy
+
+**Returns:** The actual number of attributes in the set
+
+**Note:** If the returned length is greater than `max_len`, no data is copied.
+
+**Output structure format:**
+```c
+struct Attr {
+ value_id: u32, // ID of the attribute value
+ name_len: u32, // Length of attribute name in bytes
+}
+```
+
+Each attribute is 8 bytes (2 × 4 bytes). Use `copy_attrname` to retrieve attribute names.
+
+#### `copy_attrname(value: ValueId, attr_idx: u32, ptr: u32, len: u32)`
+
+Copies an attribute name into Wasm memory.
+
+**Parameters:**
+- `value` - ID of a Nix attribute set value
+- `attr_idx` - Index of the attribute (from `copy_attrset`)
+- `ptr` - Pointer to buffer in Wasm memory
+- `len` - Length of the buffer (must exactly match the attribute name length)
+
+**Note:** Throws an error if `len` doesn't match the attribute name length or if `attr_idx` is out of bounds.
+
+#### `get_attr(value: ValueId, ptr: u32, len: u32) -> ValueId`
+
+Gets an attribute value from an attribute set by name.
+
+**Parameters:**
+- `value` - ID of a Nix attribute set value
+- `ptr` - Pointer to the attribute name in Wasm memory
+- `len` - Length of the attribute name in bytes
+
+**Returns:** Value ID of the attribute value, or 0 if the attribute doesn't exist
+
+### Function Operations
+
+#### `call_function(fun: ValueId, ptr: u32, len: u32) -> ValueId`
+
+Calls a Nix function with arguments.
+
+**Parameters:**
+- `fun` - ID of a Nix function value
+- `ptr` - Pointer to array of `ValueId` arguments in Wasm memory
+- `len` - Number of arguments
+
+**Returns:** Value ID of the function result
+
+#### `make_app(fun: ValueId, ptr: u32, len: u32) -> ValueId`
+
+Creates a lazy or partially applied function application.
+
+**Parameters:**
+- `fun` - ID of a Nix function value
+- `ptr` - Pointer to array of `ValueId` arguments in Wasm memory
+- `len` - Number of arguments
+
+**Returns:** Value ID of the unevaluated application
+
+### Returning Results (WASI mode only)
+
+#### `return_to_nix(value: ValueId)`
+
+Returns a result value to the Nix evaluator from a WASI module. This function is only available in WASI mode.
+
+**Parameters:**
+- `value` - ID of the Nix value to return as the result of the `builtins.wasm` call
+
+**Note:** Calling this function immediately terminates the WASI module's execution. The module must call `return_to_nix` before finishing; otherwise, an error is raised.
+
+### File I/O
+
+#### `read_file(path: ValueId, ptr: u32, len: u32) -> u32`
+
+Reads a file into Wasm memory.
+
+**Parameters:**
+- `path` - Value ID of a Nix path value
+- `ptr` - Pointer to buffer in Wasm memory
+- `len` - Maximum number of bytes to read
+
+**Returns:** The actual file size in bytes
+
+**Note:** Similar to `builtins.readFile`, but can handle files that cannot be represented as Nix strings (in particular, files containing NUL bytes). If the returned size is greater than `len`, no data is copied.
+
+## Example Usage
+
+For Rust bindings to this interface and several examples, see https://github.com/DeterminateSystems/nix-wasm-rust/.
diff --git a/doc/manual/source/quick-start.md b/doc/manual/source/quick-start.md
index 9eb7a3265903..42e4e9c0c247 100644
--- a/doc/manual/source/quick-start.md
+++ b/doc/manual/source/quick-start.md
@@ -3,10 +3,13 @@
This chapter is for impatient people who don't like reading documentation.
For more in-depth information you are kindly referred to subsequent chapters.
-1. Install Nix:
+1. Install Nix.
+ We recommend that macOS users install Determinate Nix using our graphical installer, [Determinate.pkg][pkg].
+ For Linux and Windows Subsystem for Linux (WSL) users:
```console
- $ curl -L https://nixos.org/nix/install | sh
+ $ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | \
+ sh -s -- install
```
The install script will use `sudo`, so make sure you have sufficient rights.
@@ -41,3 +44,5 @@ For more in-depth information you are kindly referred to subsequent chapters.
```console
$ nix-collect-garbage
```
+
+[pkg]: https://install.determinate.systems/determinate-pkg/stable/Universal
diff --git a/doc/manual/source/release-notes-determinate/changes.md b/doc/manual/source/release-notes-determinate/changes.md
new file mode 100644
index 000000000000..b9d0790d29b9
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/changes.md
@@ -0,0 +1,210 @@
+# Changes between Nix and Determinate Nix
+
+This section lists the differences between upstream Nix 2.33 and Determinate Nix 3.17.3.
+
+* In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature.
+
+* In Determinate Nix, the new Nix CLI (i.e. the `nix` command) is stable. You no longer need to enable the `nix-command` experimental feature.
+
+* Determinate Nix has a setting [`json-log-path`](@docroot@/command-ref/conf-file.md#conf-json-log-path) to send a copy of all Nix log messages (in JSON format) to a file or Unix domain socket.
+
+* Determinate Nix has made `nix profile install` an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.
+
+* `nix-channel` and `channel:` url syntax (like `channel:nixos-24.11`) is deprecated, see: https://github.com/DeterminateSystems/nix-src/issues/34
+
+* Using indirect flake references and implicit inputs is deprecated, see: https://github.com/DeterminateSystems/nix-src/issues/37
+
+* Warnings around "dirty trees" are updated to reduce "dirty" jargon, and now refers to "uncommitted changes".
+
+
+
+
+
+
+
+* `nix upgrade-nix` is now inert, and suggests using `determinate-nixd upgrade`. [DeterminateSystems/nix-src#55](https://github.com/DeterminateSystems/nix-src/pull/55)
+
+* Determinate Nix has Lazy Trees, avoiding expensive copying of flake inputs to the Nix store. ([DeterminateSystems/nix-src#27](https://github.com/DeterminateSystems/nix-src/pull/27), [DeterminateSystems/nix-src#56](https://github.com/DeterminateSystems/nix-src/pull/56))
+
+
+
+
+
+
+
+
+
+* Documentation on how to replicate `nix-store --query --deriver` with the new `nix` cli. [DeterminateSystems/nix-src#82](https://github.com/DeterminateSystems/nix-src/pull/82)
+
+* In `nix profile`, the symbols `ε` and `∅` have been replaced with descriptive English words. [DeterminateSystems/nix-src#81](https://github.com/DeterminateSystems/nix-src/pull/81)
+
+
+
+
+
+
+
+* When remote building with `--keep-failed`, Determinate Nix shows "you can rerun" message if the derivation's platform is supported on this machine. [DeterminateSystems/nix-src#87](https://github.com/DeterminateSystems/nix-src/pull/87)
+
+* Improved error message when `sandbox-paths` specifies a missing file. [DeterminateSystems/nix-src#88](https://github.com/DeterminateSystems/nix-src/pull/88)
+
+
+
+
+
+
+
+
+
+* `nix store delete` now explains why deletion fails. [DeterminateSystems/nix-src#130](https://github.com/DeterminateSystems/nix-src/pull/130)
+
+
+
+
+
+
+
+
+
+
+
+
+
+* Tab completing arguments to Nix avoids network access. [DeterminateSystems/nix-src#161](https://github.com/DeterminateSystems/nix-src/pull/161)
+
+* Importing Nixpkgs and other tarballs to the cache is 2-4x faster. [DeterminateSystems/nix-src#149](https://github.com/DeterminateSystems/nix-src/pull/149)
+
+* Adding paths to the store is significantly faster. [DeterminateSystems/nix-src#162](https://github.com/DeterminateSystems/nix-src/pull/162)
+
+
+
+
+
+* Determinate Nix allows flake inputs to be fetched at build time. [DeterminateSystems/nix-src#49](https://github.com/DeterminateSystems/nix-src/pull/49)
+
+
+
+* The default `nix flake init` template is much more useful. [DeterminateSystems/nix-src#180](https://github.com/DeterminateSystems/nix-src/pull/180)
+
+
+
+
+
+
+
+
+* Multithreaded evaluation support. [DeterminateSystems/nix-src#125](https://github.com/DeterminateSystems/nix-src/pull/125)
+
+
+
+
+
+
+* Determinate Nix only tries to substitute inputs if fetching from its original location fails.[DeterminateSystems/nix-src#202](https://github.com/DeterminateSystems/nix-src/pull/202)
+
+
+
+
+
+
+* A new command `nix nario` that replaces `nix-store --export|--export`. It also has a new file format (`--format 2`) that supports store path attributes such as signatures, and that can be imported more efficiently. [DeterminateSystems/nix-src#215](https://github.com/DeterminateSystems/nix-src/pull/215)
+
+* Determinate Nix prints the Nix version when using `-vv` or higher verbosity. [DeterminateSystems/nix-src#237](https://github.com/DeterminateSystems/nix-src/pull/237)
+
+
+
+
+* During evaluation, you can read or import from the result of `builtins.fetchClosure`. [DeterminateSystems/nix-src#241](https://github.com/DeterminateSystems/nix-src/pull/241)
+
+
+
+* Flakerefs in error messages and lockfile diffs are abbreviated for readability. [DeterminateSystems/nix-src#243](https://github.com/DeterminateSystems/nix-src/pull/243), [DeterminateSystems/nix-src#264](https://github.com/DeterminateSystems/nix-src/pull/264)
+
+
+
+
+
+
+
+
+* The Git fetcher doesn't compute `revCount` or `lastModified` if they're already specified [DeterminateSystems./nix-src#269](https://github.com/DeterminateSystems/nix-src/pull/269)
+
+* The Git fetcher avoids doing a shallow Git fetch if it previously did a non-shallow fetch of the same repository. [DeterminateSystems/nix-src#270](https://github.com/DeterminateSystems/nix-src/pull/270)
+
+* Determinate Nix has a builtin copy of the flake registry, making it more resilient to network outages. [DeterminateSystems/nix-src#271](https://github.com/DeterminateSystems/nix-src/pull/271)
+
+
+
+* `nix build` and `nix profile` report failing or succeeding installables. [DeterminateSystems/nix-src#281](https://github.com/DeterminateSystems/nix-src/pull/281)
+
+* `nix flake check` shows which outputs failed or succeeded. [DeterminateSystems/nix-src#285](https://github.com/DeterminateSystems/nix-src/pull/285)
+
+* Determinate Nix has a `nix ps` command to show active builds. [DeterminateSystems/nix-src#282](https://github.com/DeterminateSystems/nix-src/pull/282)
+
+* Determinate Nix has improved backward compatibility with lock files created by Nix < 2.20. [DeterminateSystems/nix-src#278](https://github.com/DeterminateSystems/nix-src/pull/278)
+
+
+
+* Determinate Nix has a builtin function `builtins.filterAttrs`. [DeterminateSystems/nix-src#291](https://github.com/DeterminateSystems/nix-src/pull/291)
+
+* `builtins.fetchTree` implicitly sets `__final = true` when a `narHash` is supplied. This allows the tree to be substituted. [DeterminateSystems/nix-src#297](https://github.com/DeterminateSystems/nix-src/pull/297)
+
+
+
+
+
+* Path inputs are now lazy [DeterminateSystems/nix-src#312](https://github.com/DeterminateSystems/nix-src/pull/312)
+
+* Improved performance when fetching a lot of dependencies with curl [DeterminateSystems/nix-src#315](https://github.com/DeterminateSystems/nix-src/pull/315)
+
+
+
+* Wasm support [DeterminateSystems/nix-src#309](https://github.com/DeterminateSystems/nix-src/pull/309)
+
+* Fix hung downloads when `http-connections = 0` [DeterminateSystems/nix-src#327](https://github.com/DeterminateSystems/nix-src/pull/327)
+
+* Support .gitattributes in subdirectories [DeterminateSystems/nix-src#335](https://github.com/DeterminateSystems/nix-src/pull/335)
+
+* builtins.getFlake fixes [DeterminateSystems/nix-src#337](https://github.com/DeterminateSystems/nix-src/pull/337)
+
+* builtins.getFlake: Support path values [DeterminateSystems/nix-src#338](https://github.com/DeterminateSystems/nix-src/pull/338)
+
+* Provenance [DeterminateSystems/nix-src#321](https://github.com/DeterminateSystems/nix-src/pull/321)
+
+* Add subcommand 'nix provenance show' [DeterminateSystems/nix-src#340](https://github.com/DeterminateSystems/nix-src/pull/340)
+
+* Increase the open file soft limit to the hard limit [DeterminateSystems/nix-src#347](https://github.com/DeterminateSystems/nix-src/pull/347)
+
+
+
+
+* Record provenance for unlocked inputs and impure evaluations in [DeterminateSystems/nix-src#354](https://github.com/DeterminateSystems/nix-src/pull/354)
+
+* Add setting narinfo-cache-meta-ttl in [DeterminateSystems/nix-src#355](https://github.com/DeterminateSystems/nix-src/pull/355)
+
+* Add derivationWithMeta builtin in [DeterminateSystems/nix-src#357](https://github.com/DeterminateSystems/nix-src/pull/357)
+
+* Add builtins.wasi in [DeterminateSystems/nix-src#359](https://github.com/DeterminateSystems/nix-src/pull/359)
+
+* Add `nix provenance verify` command in [DeterminateSystems/nix-src#356](https://github.com/DeterminateSystems/nix-src/pull/356)
+
+* builtins.hashString: Devirtualize lazy paths, and re-enable lazy trees tests in [DeterminateSystems/nix-src#360](https://github.com/DeterminateSystems/nix-src/pull/360)
+
+
+
+
+
+
+
+
+
+
+
+
+* Flake inputs are substituted if possible before fetching from the authoritative source, in [DeterminateSystems/nix-src#380](https://github.com/DeterminateSystems/nix-src/pull/380)
+
+* Provenance now supports additional nix.conf-defined tags, in [DeterminateSystems/nix-src#374](https://github.com/DeterminateSystems/nix-src/pull/374)
+
+
+
+
diff --git a/doc/manual/source/release-notes-determinate/index.md b/doc/manual/source/release-notes-determinate/index.md
new file mode 100644
index 000000000000..bba33084424c
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/index.md
@@ -0,0 +1,3 @@
+# Determinate Nix Release Notes
+
+This chapter lists the differences between Nix and Determinate Nix, as well as the release history of Determinate Nix.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.0.0.md b/doc/manual/source/release-notes-determinate/rl-3.0.0.md
new file mode 100644
index 000000000000..d60786e9a72f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.0.0.md
@@ -0,0 +1,5 @@
+# Release 3.0.0 (2025-03-04)
+
+* Initial release of Determinate Nix.
+
+* Based on [upstream Nix 2.26.2](../release-notes/rl-2.26.md).
diff --git a/doc/manual/source/release-notes-determinate/rl-3.1.0.md b/doc/manual/source/release-notes-determinate/rl-3.1.0.md
new file mode 100644
index 000000000000..96b7819d08db
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.1.0.md
@@ -0,0 +1,5 @@
+# Release 3.1.0 (2025-03-27)
+
+* Based on [upstream Nix 2.27.1](../release-notes/rl-2.27.md).
+
+* New setting `json-log-path` that sends a copy of all Nix log messages (in JSON format) to a file or Unix domain socket.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.3.0.md b/doc/manual/source/release-notes-determinate/rl-3.3.0.md
new file mode 100644
index 000000000000..badf96415df0
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.3.0.md
@@ -0,0 +1,5 @@
+# Release 3.3.0 (2025-04-11)
+
+* Based on [upstream Nix 2.28.1](../release-notes/rl-2.28.md).
+
+* The `nix profile install` command is now an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.4.0.md b/doc/manual/source/release-notes-determinate/rl-3.4.0.md
new file mode 100644
index 000000000000..24ae03ca554f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.4.0.md
@@ -0,0 +1,50 @@
+# Release 3.4.0 (2025-04-25)
+
+* Based on [upstream Nix 2.28.2](../release-notes/rl-2.28.md).
+
+* **Warn users that `nix-channel` is deprecated.**
+
+This is the first change accomplishing our roadmap item of deprecating Nix channels: https://github.com/DeterminateSystems/nix-src/issues/34
+
+This is due to user confusion and surprising behavior of channels, especially in the context of user vs. root channels.
+
+The goal of this change is to make the user experience of Nix more predictable.
+In particular, these changes are to support users with lower levels of experience who are following guides that focus on channels as the mechanism of distribution.
+
+Users will now see this message:
+
+> nix-channel is deprecated in favor of flakes in Determinate Nix. For a guide on Nix flakes, see: https://zero-to-nix.com/. or details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.
+
+
+* **Warn users that `channel:` URLs are deprecated.**
+
+This is the second change regarding our deprecation of Nix channels.
+Using a `channel:` URL (like `channel:nixos-24.11`) will yield a warning like this:
+
+> Channels are deprecated in favor of flakes in Determinate Nix. Instead of 'channel:nixos-24.11', use 'https://nixos.org/channels/nixos-24.11/nixexprs.tar.xz'. For a guide on Nix flakes, see: https://zero-to-nix.com/. For details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.
+
+* **Warn users against indirect flake references in `flake.nix` inputs**
+
+This is the first change accomplishing our roadmap item of deprecating implicit and indirect flake inputs: https://github.com/DeterminateSystems/nix-src/issues/37
+
+The flake registry provides an important UX affordance for using Nix flakes and remote sources in command line uses.
+For that reason, the registry is not being deprecated entirely and will still be used for command-line incantations, like nix run.
+
+This move will eliminate user confusion and surprising behavior around global and local registries during flake input resolution.
+
+The goal of this change is to make the user experience of Nix more predictable.
+We have seen a pattern of confusion when using automatic flake inputs and local registries.
+Specifically, users' flake inputs resolving and locking inconsistently depending on the configuration of the host system.
+
+Users will now see the following warning if their flake.nix uses an implicit or indirect Flake reference input:
+
+> Flake input 'nixpkgs' uses the flake registry. Using the registry in flake inputs is deprecated in Determinate Nix. To make your flake future-proof, add the following to 'xxx/flake.nix':
+>
+> inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
+>
+> For more information, see: https://github.com/DeterminateSystems/nix-src/issues/37
+
+
+### Other updates:
+* Improve the "dirty tree" message. Determinate Nix will now say `Git tree '...' has uncommitted changes` instead of `Git tree '...' is dirty`
+* Stop warning about uncommitted changes in a Git repository when using `nix develop`
diff --git a/doc/manual/source/release-notes-determinate/rl-3.4.2.md b/doc/manual/source/release-notes-determinate/rl-3.4.2.md
new file mode 100644
index 000000000000..8acabd4425fd
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.4.2.md
@@ -0,0 +1,4 @@
+# Release 3.4.2 (2025-05-05)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.0.md b/doc/manual/source/release-notes-determinate/rl-3.5.0.md
new file mode 100644
index 000000000000..d5b26b9419e7
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.0.md
@@ -0,0 +1,4 @@
+# Release 3.5.0 (2025-05-09)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.1.md b/doc/manual/source/release-notes-determinate/rl-3.5.1.md
new file mode 100644
index 000000000000..b0813ca59c90
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.1.md
@@ -0,0 +1,57 @@
+# Release 3.5.1 (2025-05-09)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
+## What's Changed
+
+Most notably, Lazy Trees has merged in to Determinate Nix and is in Feature Preview status, but remains disabled by default.
+Lazy trees massively improves performance in virtually all scenarios because it enables Nix to avoid making unnecessary copies of files into the Nix store.
+In testing, we saw iteration times on Nixpkgs **drop from over 12 seconds to 3.5 seconds**.
+
+After upgrading to Determinate Nix 3.5.1 with `sudo determinate-nixd upgrade`, enable lazy trees by adding this to `/etc/nix/nix.custom.conf`:
+
+```
+lazy-trees = true
+```
+
+Please note that our full flake regression test suite passes with no changes with lazy trees, and please report compatibility issues.
+
+Read [this GitHub comment](https://github.com/DeterminateSystems/nix-src/pull/27#pullrequestreview-2822153088) for further details and next steps.
+We'll be publishing an update on the [Determinate Systems blog](https://determinate.systems/posts/) in the next few days with more information as well.
+
+Relevant PRs:
+* Lazy trees v2 by @edolstra in [DeterminateSystems/nix-src#27](https://github.com/DeterminateSystems/nix-src/pull/27)
+* Improve lazy trees backward compatibility by @edolstra in [DeterminateSystems/nix-src#56](https://github.com/DeterminateSystems/nix-src/pull/56)
+
+
+### Additional changes in this release:
+* Bug fix: Flake input URLs are canonicalized before checking flake.lock file staleness, avoiding needlessly regenerating flake.lock files with `dir` in URL-style flakerefs by @edolstra in [DeterminateSystems/nix-src#57](https://github.com/DeterminateSystems/nix-src/pull/57)
+* `nix upgrade-nix` is deprecated in favor of `determinate-nixd upgrade`, by @gustavderdrache in [DeterminateSystems/nix-src#55](https://github.com/DeterminateSystems/nix-src/pull/55)
+* UX: Improved build failure and dependency failure error messages to include needed output paths by @edolstra in [DeterminateSystems/nix-src#58](https://github.com/DeterminateSystems/nix-src/pull/58).
+
+Previously:
+
+```
+error: builder for '/nix/store/[...]-nested-failure-bottom.drv' failed with exit code 1
+error: 1 dependencies of derivation '/nix/store/[...]-nested-failure-middle.drv' failed to build
+error: 1 dependencies of derivation '/nix/store/[...]-nested-failure-top.drv' failed to build
+```
+
+Now:
+
+```
+error: Cannot build '/nix/store/w37gflm9wz9dcnsgy3sfrmnlvm8qigaj-nested-failure-bottom.drv'.
+ Reason: builder failed with exit code 1.
+ Output paths:
+ /nix/store/yzybs8kp35dfipbzdlqcc6lxz62hax04-nested-failure-bottom
+error: Cannot build '/nix/store/00gr5hlxfc03x2675w6nn3pwfrz2fr62-nested-failure-middle.drv'.
+ Reason: 1 dependency failed.
+ Output paths:
+ /nix/store/h781j5h4bdchmb4c2lvy8qzh8733azhz-nested-failure-middle
+error: Cannot build '/nix/store/8am0ng1gyx8sbzyr0yx6jd5ix3yy5szc-nested-failure-top.drv'.
+ Reason: 1 dependency failed.
+ Output paths:
+ /nix/store/fh12637kgvp906s9yhi9w2dc7ghfwxs1-nested-failure-top
+```
+
+**Full Changelog**: [v3.4.2...v3.5.1](https://github.com/DeterminateSystems/nix-src/compare/v3.4.2...v3.5.1)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.5.2.md b/doc/manual/source/release-notes-determinate/rl-3.5.2.md
new file mode 100644
index 000000000000..bc5396c255b6
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.5.2.md
@@ -0,0 +1,11 @@
+# Release 3.5.2 (2025-05-12)
+
+* Based on [upstream Nix 2.28.3](../release-notes/rl-2.28.md).
+
+## What's Changed
+* Fix a regression where narHash was not added to lock files when lazy trees were disabled by @edolstra in [DeterminateSystems/nix-src#63](https://github.com/DeterminateSystems/nix-src/pull/63)
+
+* 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)
+
+
+**Full Changelog**: [v3.5.1...v3.5.2](https://github.com/DeterminateSystems/nix-src/compare/v3.5.1...v3.5.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.0.md b/doc/manual/source/release-notes-determinate/rl-3.6.0.md
new file mode 100644
index 000000000000..453ab6c301dc
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.0.md
@@ -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)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.1.md b/doc/manual/source/release-notes-determinate/rl-3.6.1.md
new file mode 100644
index 000000000000..12505afee278
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.1.md
@@ -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)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.2.md b/doc/manual/source/release-notes-determinate/rl-3.6.2.md
new file mode 100644
index 000000000000..882c142f00c3
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.2.md
@@ -0,0 +1,15 @@
+# Release 3.6.2 (2025-06-02)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Dramatically improve the performance of nix store copy-sigs: Use http-connections setting to control parallelism by @edolstra in [DeterminateSystems/nix-src#80](https://github.com/DeterminateSystems/nix-src/pull/80)
+* Document how to replicate nix-store --query --deriver with the nix cli by @grahamc in [DeterminateSystems/nix-src#82](https://github.com/DeterminateSystems/nix-src/pull/82)
+* The garbage collector no longer gives up if it encounters an undeletable file, by @edolstra in [DeterminateSystems/nix-src#83](https://github.com/DeterminateSystems/nix-src/pull/83)
+* nix profile: Replace ε and ∅ with descriptive English words by @grahamc in [DeterminateSystems/nix-src#81](https://github.com/DeterminateSystems/nix-src/pull/81)
+* Rework README to clarify that this distribution is our distribution, by @lucperkins in [DeterminateSystems/nix-src#84](https://github.com/DeterminateSystems/nix-src/pull/84)
+* Include the source location when warning about inefficient double copies by @edolstra in [DeterminateSystems/nix-src#79](https://github.com/DeterminateSystems/nix-src/pull/79)
+* Call out that `--keep-failed` with remote builders will keep the failed build directory on that builder by @cole-h in [DeterminateSystems/nix-src#85](https://github.com/DeterminateSystems/nix-src/pull/85)
+
+
+**Full Changelog**: [v3.6.1...v3.6.2](https://github.com/DeterminateSystems/nix-src/compare/v3.6.1...v3.6.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.5.md b/doc/manual/source/release-notes-determinate/rl-3.6.5.md
new file mode 100644
index 000000000000..8ef5be0fd0d3
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.5.md
@@ -0,0 +1,19 @@
+# Release 3.6.5 (2025-06-12)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+* When remote building with --keep-failed, only show "you can rerun" message if the derivation's platform is supported on this machine by @cole-h in [DeterminateSystems/nix-src#87](https://github.com/DeterminateSystems/nix-src/pull/87)
+* Indicate that sandbox-paths specifies a missing file in the corresponding error message. by @cole-h in [DeterminateSystems/nix-src#88](https://github.com/DeterminateSystems/nix-src/pull/88)
+* Render lazy tree paths in messages withouth the/nix/store/hash... prefix in substituted source trees by @edolstra in [DeterminateSystems/nix-src#91](https://github.com/DeterminateSystems/nix-src/pull/91)
+* Use FlakeHub inputs by @lucperkins in [DeterminateSystems/nix-src#89](https://github.com/DeterminateSystems/nix-src/pull/89)
+* Proactively cache more flake inputs and fetches by @edolstra in [DeterminateSystems/nix-src#93](https://github.com/DeterminateSystems/nix-src/pull/93)
+* Fix: register extra builtins just once by @edolstra in [DeterminateSystems/nix-src#97](https://github.com/DeterminateSystems/nix-src/pull/97)
+* Fix the link to `builders-use-substitutes` documentation for `builders` by @lucperkins in [DeterminateSystems/nix-src#102](https://github.com/DeterminateSystems/nix-src/pull/102)
+* Improve error messages that use the hypothetical future tense of "will" by @lucperkins in [DeterminateSystems/nix-src#92](https://github.com/DeterminateSystems/nix-src/pull/92)
+* Make the `nix repl` test more stable by @edolstra in [DeterminateSystems/nix-src#103](https://github.com/DeterminateSystems/nix-src/pull/103)
+* Run nixpkgsLibTests against lazy trees by @edolstra in [DeterminateSystems/nix-src#100](https://github.com/DeterminateSystems/nix-src/pull/100)
+* Run the Nix test suite against lazy trees by @edolstra in [DeterminateSystems/nix-src#105](https://github.com/DeterminateSystems/nix-src/pull/105)
+* Improve caching of inputs by @edolstra in [DeterminateSystems/nix-src#98](https://github.com/DeterminateSystems/nix-src/pull/98), [DeterminateSystems/nix-src#110](https://github.com/DeterminateSystems/nix-src/pull/110), and [DeterminateSystems/nix-src#115](https://github.com/DeterminateSystems/nix-src/pull/115)
+
+**Full Changelog**: [v3.6.2...v3.6.5](https://github.com/DeterminateSystems/nix-src/compare/v3.6.2...v3.6.4)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.6.md b/doc/manual/source/release-notes-determinate/rl-3.6.6.md
new file mode 100644
index 000000000000..bf4e3690afa1
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.6.md
@@ -0,0 +1,7 @@
+# Release 3.6.6 (2025-06-17)
+
+* Based on [upstream Nix 2.29.0](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+* No-op release on the nix-src side, due to a regression on nix-darwin in determinate-nixd.
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.7.md b/doc/manual/source/release-notes-determinate/rl-3.6.7.md
new file mode 100644
index 000000000000..197587f1b3a9
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.7.md
@@ -0,0 +1,17 @@
+# Release 3.6.7 (2025-06-24)
+
+* Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+### Security contents
+
+* Patched against GHSA-g948-229j-48j3
+
+### Lazy trees:
+
+* Lazy trees now produces `flake.lock` files with NAR hashes unless `lazy-locks` is set to `true` by @edolstra in [DeterminateSystems/nix-src#113](https://github.com/DeterminateSystems/nix-src/pull/113)
+* Improved caching with lazy-trees when using --impure, with enhanced testing by @edolstra in [DeterminateSystems/nix-src#117](https://github.com/DeterminateSystems/nix-src/pull/117)
+
+
+**Full Changelog**: [v3.6.6...v3.6.7](https://github.com/DeterminateSystems/nix-src/compare/v3.6.6...v3.6.7)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.6.8.md b/doc/manual/source/release-notes-determinate/rl-3.6.8.md
new file mode 100644
index 000000000000..c4b4b96c9e73
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.6.8.md
@@ -0,0 +1,12 @@
+# Release 3.6.8 (2025-06-25)
+
+* Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+* Fix fetchToStore() caching with --impure, improve testing by @edolstra in [DeterminateSystems/nix-src#117](https://github.com/DeterminateSystems/nix-src/pull/117)
+* Add lazy-locks setting by @edolstra in [DeterminateSystems/nix-src#113](https://github.com/DeterminateSystems/nix-src/pull/113)
+* Sync 2.29.1 by @edolstra in [DeterminateSystems/nix-src#124](https://github.com/DeterminateSystems/nix-src/pull/124)
+* Release v3.6.7 by @github-actions in [DeterminateSystems/nix-src#126](https://github.com/DeterminateSystems/nix-src/pull/126)
+
+
+**Full Changelog**: [v3.6.6...v3.6.8](https://github.com/DeterminateSystems/nix-src/compare/v3.6.6...v3.6.8)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.7.0.md b/doc/manual/source/release-notes-determinate/rl-3.7.0.md
new file mode 100644
index 000000000000..615e858592e2
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.7.0.md
@@ -0,0 +1,63 @@
+# Release 3.7.0 (2025-07-03)
+
+- Based on [upstream Nix 2.29.1](../release-notes/rl-2.29.md).
+
+## What's Changed
+
+### Prefetch flake inputs in parallel
+
+By @edolstra in [DeterminateSystems/nix-src#127](https://github.com/DeterminateSystems/nix-src/pull/127)
+
+This release brings the command `nix flake prefetch-inputs`.
+
+Flake inputs are typically fetched "just in time."
+That means Nix fetches a flake input when the evaluator needs it, and not before.
+When the evaluator needs an input, evaluation is paused until the source is available.
+
+This causes a significant slow-down on projects with lots of flake inputs.
+
+The new command `nix flake prefetch-inputs` fetches all flake inputs in parallel.
+We expect running this new command before building will dramatically improve evaluation performance for most projects, especially in CI.
+Note that projects which with many unused flake inputs may not benefit from this change, since the new command fetches every input whether they're used or not.
+
+### Deep flake input overrides now work as expected
+
+By @edolstra in [DeterminateSystems/nix-src#108](https://github.com/DeterminateSystems/nix-src/pull/108)
+
+An override like:
+
+```
+inputs.foo.inputs.bar.inputs.nixpkgs.follows = "nixpkgs";
+```
+
+implicitly set `inputs.foo.inputs.bar` to `flake:bar`, which led to an unexpected error like:
+
+```
+error: cannot find flake 'flake:bar' in the flake registries
+```
+
+We now no longer create a parent override (like for `foo.bar` in the example above) if it doesn't set an explicit ref or follows attribute.
+We only recursively apply its child overrides.
+
+### `nix store delete` now shows you why deletion was not possible
+
+By @edolstra in [DeterminateSystems/nix-src#130](https://github.com/DeterminateSystems/nix-src/pull/130)
+
+For example:
+
+```
+error: Cannot delete path '/nix/store/6fcrjgfjip2ww3sx51rrmmghfsf60jvi-patchelf-0.14.3'
+ because it's referenced by the GC root '/home/eelco/Dev/nix-master/build/result'.
+
+error: Cannot delete path '/nix/store/lf3lrf8bjfn8xvr0az9q96y989sxs5r9-cowsay-3.8.4'
+ because it's referenced by the GC root '/proc/3600568/environ'.
+
+error: Cannot delete path '/nix/store/klyng5rpdkwi5kbxkncy4gjwb490dlhb-foo.drv'
+ because it's in use by '{nix-process:3605324}'.
+```
+
+### Lazy-tree improvements
+
+- Improved lazy-tree evaluation caching for flakes accessed with a `path` flakeref by @edolstra in [DeterminateSystems/nix-src#131](https://github.com/DeterminateSystems/nix-src/pull/131)
+
+**Full Changelog**: [v3.6.8...v3.7.0](https://github.com/DeterminateSystems/nix-src/compare/v3.6.8...v3.7.0)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.0.md b/doc/manual/source/release-notes-determinate/rl-3.8.0.md
new file mode 100644
index 000000000000..4103d6df94e0
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.0.md
@@ -0,0 +1,29 @@
+# Release 3.8.0 (2025-07-10)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Faster CI with `nix flake check`
+
+`nix flake check` no longer downloads flake outputs if no building is necessary.
+
+This command is intended to validate that a flake can fully evaluate and all outputs can build.
+If the outputs are available in a binary cache then both properties are confirmed to be true.
+Notably, downloading the output from the binary cache is not strictly necessary for the validation.
+
+Previously, `nix flake check` would download a flake output if the full build is available in a binary cache.
+
+Some users will find this change significantly reduces costly bandwidth and CI workflow time.
+
+PR: [DeterminateSystems/nix-src#134](https://github.com/DeterminateSystems/nix-src/pull/134)
+
+### Improved flake locking of transitive dependencies
+
+Determinate Nix now re-locks all transitive dependencies when changing a flake input's source URL.
+
+This fixes an issue where in some scenarios Nix would not re-lock those inputs and incorrectly use the old inputs' dependencies.
+
+PR: [DeterminateSystems/nix-src#137](https://github.com/DeterminateSystems/nix-src/pull/137)
+
+**Full Changelog**: [v3.7.0...v3.8.0](https://github.com/DeterminateSystems/nix-src/compare/v3.7.0...v3.8.0)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.1.md b/doc/manual/source/release-notes-determinate/rl-3.8.1.md
new file mode 100644
index 000000000000..90dc328f6ec2
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.1.md
@@ -0,0 +1,9 @@
+# Release 3.8.1 (2025-07-11)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Address ifdef problem with macOS/BSD sandboxing by @gustavderdrache in [DeterminateSystems/nix-src#142](https://github.com/DeterminateSystems/nix-src/pull/142)
+
+
+**Full Changelog**: [v3.8.0...v3.8.1](https://github.com/DeterminateSystems/nix-src/compare/v3.8.0...v3.8.1)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.2.md b/doc/manual/source/release-notes-determinate/rl-3.8.2.md
new file mode 100644
index 000000000000..638d90f6841b
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.2.md
@@ -0,0 +1,10 @@
+# Release 3.8.2 (2025-07-12)
+
+* Based on [upstream Nix 2.30.0](../release-notes/rl-2.30.md).
+
+## What's Changed
+* ci: don't run the full test suite for x86_64-darwin by @grahamc in [DeterminateSystems/nix-src#144](https://github.com/DeterminateSystems/nix-src/pull/144)
+* Try publishing the manual again by @grahamc in [DeterminateSystems/nix-src#145](https://github.com/DeterminateSystems/nix-src/pull/145)
+
+
+**Full Changelog**: [v3.8.1...v3.8.2](https://github.com/DeterminateSystems/nix-src/compare/v3.8.1...v3.8.2)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.3.md b/doc/manual/source/release-notes-determinate/rl-3.8.3.md
new file mode 100644
index 000000000000..d3eb02bc7ea5
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.3.md
@@ -0,0 +1,26 @@
+# Release 3.8.3 (2025-07-18)
+
+* Based on [upstream Nix 2.30.1](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Non-blocking evaluation caching
+
+Users reported evaluation would occasionally block other evaluation processes.
+
+The evaluation cache database is now opened in write-ahead mode to prevent delaying evaluations.
+
+PR: [DeterminateSystems/nix-src#150](https://github.com/DeterminateSystems/nix-src/pull/150)
+
+### New experimental feature: `external-builders`
+
+This experimental feature allows Nix to call an external program for the build environment.
+
+The interface and behavior of this feature may change at any moment without a correspondingly major semver version change.
+
+PRs:
+- [DeterminateSystems/nix-src#141](https://github.com/DeterminateSystems/nix-src/pull/141)
+- [DeterminateSystems/nix-src#152](https://github.com/DeterminateSystems/nix-src/pull/152)
+- [DeterminateSystems/nix-src#78](https://github.com/DeterminateSystems/nix-src/pull/78)
+
+**Full Changelog**: [v3.8.2...v3.8.3](https://github.com/DeterminateSystems/nix-src/compare/v3.8.2...v3.8.3)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.4.md b/doc/manual/source/release-notes-determinate/rl-3.8.4.md
new file mode 100644
index 000000000000..7c73e75ca023
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.4.md
@@ -0,0 +1,9 @@
+# Release 3.8.4 (2025-07-21)
+
+* Based on [upstream Nix 2.30.1](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Revert "Use WAL mode for SQLite cache databases" by @grahamc in [DeterminateSystems/nix-src#155](https://github.com/DeterminateSystems/nix-src/pull/155)
+
+
+**Full Changelog**: [v3.8.3...v3.8.4](https://github.com/DeterminateSystems/nix-src/compare/v3.8.3...v3.8.4)
diff --git a/doc/manual/source/release-notes-determinate/rl-3.8.5.md b/doc/manual/source/release-notes-determinate/rl-3.8.5.md
new file mode 100644
index 000000000000..0f1bbe6f99d7
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/rl-3.8.5.md
@@ -0,0 +1,58 @@
+## What's Changed
+
+### Less time "unpacking into the Git cache"
+
+Unpacking sources into the user's cache is now takes 1/2 to 1/4 of the time it used to.
+Previously, Nix serially unpacked sources into the cache.
+This change takes better advantage of our users' hardware by parallelizing the import.
+Real life testing shows an initial Nixpkgs import takes 3.6s on Linux, when it used to take 11.7s.
+
+PR: [DeterminateSystems/nix-src#149](https://github.com/DeterminateSystems/nix-src/pull/149)
+
+### Copy paths to the daemon in parallel
+
+Determinate Nix's evaluator no longer blocks evaluation when copying paths to the store.
+Previously, Nix would pause evaluation when it needed to add files to the store.
+Now, the copying is performed in the background allowing evaluation to proceed.
+
+PR: [DeterminateSystems/nix-src#162](https://github.com/DeterminateSystems/nix-src/pull/162)
+
+### Faster Nix evaluation by reducing duplicate Nix daemon queries
+
+Determinate Nix more effectively caches store path validity data within a single evaluation.
+Previously, the Nix client would perform many thousands of exra Nix daemon requests.
+Each extra request takes real time, and this change reduced a sample evaluation by over 12,000 requests.
+
+PR: [DeterminateSystems/nix-src#157](https://github.com/DeterminateSystems/nix-src/pull/157)
+
+### More responsive tab completion
+
+Tab completion now implies the "--offline" flag, which disables most network requests.
+Previously, tab completing Nix arguments would attempt to fetch sources and access binary caches.
+Operating in offline mode improves the interactive experience of Nix when tab completing.
+
+PR: [DeterminateSystems/nix-src#161](https://github.com/DeterminateSystems/nix-src/pull/161)
+
+### ZFS users: we fixed the mysterious stall.
+
+Opening the Nix database is usually instantaneous but sometimes has a several second latency.
+Determinate Nix works around this issue, eliminating the frustrating random stall when running Nix commands.
+
+PR: [DeterminateSystems/nix-src#158](https://github.com/DeterminateSystems/nix-src/pull/158)
+
+### Other changes
+
+* Determinate Nix is now fully formatted by clang-format, making it easier than ever to contribute to the project.
+
+PR: [DeterminateSystems/nix-src#159](https://github.com/DeterminateSystems/nix-src/pull/159)
+
+* Determinate Nix is now based on upstream Nix 2.30.2.
+
+PR: [DeterminateSystems/nix-src#160](https://github.com/DeterminateSystems/nix-src/pull/160)
+
+* Determinate Nix now uses `main` as our development branch, moving away from `detsys-main`.
+
+PRs:
+* [DeterminateSystems/nix-src#164](https://github.com/DeterminateSystems/nix-src/pull/164)
+* [DeterminateSystems/nix-src#166](https://github.com/DeterminateSystems/nix-src/pull/166)
+
diff --git a/doc/manual/source/release-notes-determinate/v3.10.0.md b/doc/manual/source/release-notes-determinate/v3.10.0.md
new file mode 100644
index 000000000000..c644dd787446
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.10.0.md
@@ -0,0 +1,10 @@
+# Release 3.10.0 (2025-09-02)
+
+* Based on [upstream Nix 2.31.0](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+This release rebases Determinate Nix on upstream Nix 2.31.0.
+
+
+**Full Changelog**: [v3.9.1...v3.10.0](https://github.com/DeterminateSystems/nix-src/compare/v3.9.1...v3.10.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.10.1.md b/doc/manual/source/release-notes-determinate/v3.10.1.md
new file mode 100644
index 000000000000..08cbe4fd0583
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.10.1.md
@@ -0,0 +1,9 @@
+# Release 3.10.1 (2025-09-02)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+This release rebases Determinate Nix on upstream Nix 2.31.1.
+
+
+**Full Changelog**: [v3.10.0...v3.10.1](https://github.com/DeterminateSystems/nix-src/compare/v3.10.0...v3.10.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.0.md b/doc/manual/source/release-notes-determinate/v3.11.0.md
new file mode 100644
index 000000000000..7abb665a5a9f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.0.md
@@ -0,0 +1,36 @@
+# Release 3.11.0 (2025-09-03)
+
+- Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+### Parallel evaluation
+
+The following commands are now able to evaluate Nix expressions in parallel:
+
+- `nix search`
+- `nix flake check`
+- `nix flake show`
+- `nix eval --json`
+
+This is currently in developer preview, and we'll be turning it on for more users in the coming weeks.
+If you would like to try it right away, specify `eval-cores` in your `/etc/nix/nix.custom.conf`:
+
+```ini
+eval-cores = 0 # Evaluate across all cores
+```
+
+Further, we introduced a new builtin: `builtins.parallel`.
+This new builtin allows users to explicitly parallelize evaluation within a Nix expression.
+
+Using this new builtin requires turning on an additional experimental feature:
+
+```ini
+extra-experimental-features = parallel-eval
+```
+
+Please note that this new builtin is subject to change semantics or even go away during the developer preview.
+
+PR: [DeterminateSystems/nix-src#125](https://github.com/DeterminateSystems/nix-src/pull/125)
+
+**Full Changelog**: [v3.10.1...v3.11.0](https://github.com/DeterminateSystems/nix-src/compare/v3.10.1...v3.11.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.1.md b/doc/manual/source/release-notes-determinate/v3.11.1.md
new file mode 100644
index 000000000000..305971643330
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.1.md
@@ -0,0 +1,9 @@
+# Release 3.11.1 (2025-09-04)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+* Fix race condition in Value::isTrivial() by @edolstra in [DeterminateSystems/nix-src#192](https://github.com/DeterminateSystems/nix-src/pull/192)
+
+
+**Full Changelog**: [v3.11.0...v3.11.1](https://github.com/DeterminateSystems/nix-src/compare/v3.11.0...v3.11.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.2.md b/doc/manual/source/release-notes-determinate/v3.11.2.md
new file mode 100644
index 000000000000..ac4fe569dffe
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.2.md
@@ -0,0 +1,24 @@
+# Release 3.11.2 (2025-09-12)
+
+* Based on [upstream Nix 2.31.1](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+### Fix some interactions with the registry and flakes that include a `?dir=` parameter
+
+Some users were experiencing issues when their flake registry contained a flake that included a `?dir=` parameter, causing commands like `nix eval registry-with-flake-in-subdir#output` and those that used --inputs-from` to fail or behave incorrectly.
+
+This is now fixed, so use your flakes inside subdirs without fear!
+
+PRs: [DeterminateSystems/nix-src#196](https://github.com/DeterminateSystems/nix-src/pull/196), [DeterminateSystems/nix-src#199](https://github.com/DeterminateSystems/nix-src/pull/199)
+
+### Only substitute inputs if they haven't already been fetched
+
+When using `lazy-trees`, you might have noticed Nix fetching some source inputs from a cache, even though you could have sworn it already fetched those inputs!
+
+This fixes that behavior such that Nix will try to fetch inputs from their original location, and only if that fails fall back to fetching from a substituter.
+
+PR: [DeterminateSystems/nix-src#202](https://github.com/DeterminateSystems/nix-src/pull/202)
+
+
+**Full Changelog**: [v3.11.1...v3.11.2](https://github.com/DeterminateSystems/nix-src/compare/v3.11.1...v3.11.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.11.3.md b/doc/manual/source/release-notes-determinate/v3.11.3.md
new file mode 100644
index 000000000000..fab5ed51a4b5
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.11.3.md
@@ -0,0 +1,34 @@
+# Release 3.11.3 (2025-10-09)
+
+* Based on [upstream Nix 2.31.2](../release-notes/rl-2.31.md).
+
+## What's Changed
+
+### Fix some bugs and interactions with parallel eval
+
+We received some reports of parallel eval having issues, such as not being able to be interrupted, infinite recursion hanging forever, and segfaults when using the experimental `builtins.parallel`.
+
+Those have now been fixed.
+
+Additionally, the debugger now disables parallel eval, because the two features are incompatible.
+
+PRs: [DeterminateSystems/nix-src#206](https://github.com/DeterminateSystems/nix-src/pull/206), [DeterminateSystems/nix-src#213](https://github.com/DeterminateSystems/nix-src/pull/213), [DeterminateSystems/nix-src#218](https://github.com/DeterminateSystems/nix-src/pull/218), [DeterminateSystems/nix-src#205](https://github.com/DeterminateSystems/nix-src/pull/205)
+
+### `NIX_SSHOPTS` + `ssh-ng://root@localhost` fix
+
+We noticed that specifying `NIX_SSHOPTS=-p2222` when using a command that uses SSH (such as `nix copy --to ssh-ng://root@localhost`) stopped respecting the `NIX_SSHOPTS` setting because of an incorrect comparison.
+
+This has been fixed, so `NIX_SSHOPTS` and SSH stores that are accessed like `user@localhost` work again.
+
+PR: [DeterminateSystems/nix-src#219](https://github.com/DeterminateSystems/nix-src/pull/219)
+
+### Fix `error: [json.exception.type_error.302] type must be string, but is array` when using `exportReferencesGraph`
+
+We received a report of a `nix build` failing on a specific flake due to its expression using `exportReferencesGraph` with a heterogeneous array of dependencies, causing this inscrutable error.
+
+This specific case has been broken since Nix 2.29.0, and is now fixed.
+
+PRs: [DeterminateSystems/nix-src#221](https://github.com/DeterminateSystems/nix-src/pull/221), [DeterminateSystems/nix-src#225](https://github.com/DeterminateSystems/nix-src/pull/225)
+
+
+**Full Changelog**: [v3.11.2...v3.11.3](https://github.com/DeterminateSystems/nix-src/compare/v3.11.2...v3.11.3)
diff --git a/doc/manual/source/release-notes-determinate/v3.12.0.md b/doc/manual/source/release-notes-determinate/v3.12.0.md
new file mode 100644
index 000000000000..55c1f10bf15f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.12.0.md
@@ -0,0 +1,17 @@
+# Release 3.12.0 (2025-10-23)
+
+* Based on [upstream Nix 2.32.1](../release-notes/rl-2.32.md).
+
+## What's Changed
+
+### `nix nario`
+
+Determinate Nix has a new command, `nix nario`, that replaces the commands `nix-store --export` and `nix-store --import` from the old CLI. `nix nario` allows you to serialize store paths to a file that can be imported into another Nix store. It is backwards compatible with the file format generated by `nix-store --export`. It also provides a new format (selected by passing `--format 2`) that supports store path attributes such as signatures, and allows store paths to be imported more efficiently.
+
+### Other changes
+
+`nix flake clone` now supports arbitrary input types. In particular, this allows you to clone tarball flakes, such as flakes on FlakeHub.
+
+When using `-vv`, Determinate Nix now prints the Nix version. This is useful when diagnosing Nix problems from the debug output of a Nix run.
+
+**Full Changelog**: [v3.11.3...v3.12.0](https://github.com/DeterminateSystems/nix-src/compare/v3.11.3...v3.12.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.12.1.md b/doc/manual/source/release-notes-determinate/v3.12.1.md
new file mode 100644
index 000000000000..1be2b48e26d8
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.12.1.md
@@ -0,0 +1,10 @@
+# Release 3.12.1 (2025-11-04)
+
+* Based on [upstream Nix 2.32.1](../release-notes/rl-2.32.md).
+
+## What's Changed
+* Allow access to the result of fetchClosure by @edolstra in [DeterminateSystems/nix-src#241](https://github.com/DeterminateSystems/nix-src/pull/241)
+* libstore/build: fixup JSON logger missing the resBuildResult result event by @cole-h in [DeterminateSystems/nix-src#246](https://github.com/DeterminateSystems/nix-src/pull/246)
+
+
+**Full Changelog**: [v3.12.0...v3.12.1](https://github.com/DeterminateSystems/nix-src/compare/v3.12.0...v3.12.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.12.2.md b/doc/manual/source/release-notes-determinate/v3.12.2.md
new file mode 100644
index 000000000000..4c8c3169aa72
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.12.2.md
@@ -0,0 +1,42 @@
+# Release 3.12.2 (2025-11-05)
+
+* Based on [upstream Nix 2.32.2](../release-notes/rl-2.32.md).
+
+## What's Changed
+
+### Faster `revCount` computation
+
+When using Git repositories with a long history, calculating the `revCount` attribute can take a long time. Determinate Nix now computes `revCount` using multiple threads, making it much faster.
+
+Note that if you don't need `revCount`, you can disable it altogether by setting the flake input attribute `shallow = true`.
+
+PR: [DeterminateSystems/nix-src#245](https://github.com/DeterminateSystems/nix-src/pull/245)
+
+### More readable error messages
+
+Previously, Nix showed full flakerefs in error messages such as stack traces, e.g.
+```
+ … from call site
+ at «github:NixOS/nixpkgs/3bea86e918d8b54aa49780505d2d4cd9261413be?narHash=sha256-Ica%2B%2BSXFuLyxX9Q7YxhfZulUif6/gwM8AEQYlUxqSgE%3D»/lib/customisation.nix:69:16:
+ 68| let
+ 69| result = f origArgs;
+ | ^
+ 70|
+```
+It now abbreviates these by leaving out `narHash` and shortening Git revisions:
+```
+ … from call site
+ at «github:NixOS/nixpkgs/3bea86e»/lib/customisation.nix:69:16:
+ 68| let
+ 69| result = f origArgs;
+ | ^
+ 70|
+```
+
+PR: [DeterminateSystems/nix-src#243](https://github.com/DeterminateSystems/nix-src/pull/243)
+
+### Other changes
+
+This release fixes an assertion failure in `nix flake check`. PR: [DeterminateSystems/nix-src#252](https://github.com/DeterminateSystems/nix-src/pull/252)
+
+**Full Changelog**: [v3.12.1...v3.12.2](https://github.com/DeterminateSystems/nix-src/compare/v3.12.1...v3.12.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.13.0.md b/doc/manual/source/release-notes-determinate/v3.13.0.md
new file mode 100644
index 000000000000..09041c2acda0
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.13.0.md
@@ -0,0 +1,45 @@
+# Release 3.13.0 (2025-11-09)
+
+* Based on [upstream Nix 2.32.3](../release-notes/rl-2.32.md).
+
+## What's Changed
+
+
+### Git sources have a progress indicator again
+
+Nix used to feel "stuck" while it was cloning large repositories.
+Determinate Nix now shows git's native progress indicator while fetching.
+
+PR: [DeterminateSystems/nix-src#250](https://github.com/DeterminateSystems/nix-src/pull/250)
+
+### C API improvements
+
+We've invested in the C API to support our work on closure analysis for SBOM generation, and made a couple of changes:
+
+* C API: add nix_locked_flake_read_path for flake file reading
+* C API: make nix_store_get_fs_closure compatible with upstream
+
+PRs:
+* [DeterminateSystems/nix-src#244](https://github.com/DeterminateSystems/nix-src/pull/244)
+* [DeterminateSystems/nix-src#254](https://github.com/DeterminateSystems/nix-src/pull/254)
+
+### Dropping support for Intel Macs
+
+Determinate Nix no longer supports being installed on Intel Macs.
+Determinate Nix will continue to support building for Intel macOS targets, but only from an Apple Silicon host.
+
+From our intent-to-ship:
+> Over the past year, we’ve watched usage of Determinate on Intel macOS hosts dwindle to a minuscule fraction of total usage.
+> It currently stands at approximately 0.02% of all installations.
+> The vast majority are run in managed CI environments that, we anticipate, will be able to easily convert to using Apple Silicon runners.
+
+For more information: https://github.com/DeterminateSystems/nix-src/issues/224
+
+PR: [DeterminateSystems/nix-src#257](https://github.com/DeterminateSystems/nix-src/pull/257)
+
+### Bugs fixed
+
+* IPv6 Store URLs now handles zone ID references like it did in previous releases [NixOS/nix#14434](https://github.com/NixOS/nix/pull/14434)
+
+
+**Full Changelog**: [v3.12.2...v3.13.0](https://github.com/DeterminateSystems/nix-src/compare/v3.12.2...v3.13.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.13.1.md b/doc/manual/source/release-notes-determinate/v3.13.1.md
new file mode 100644
index 000000000000..025a192c44ee
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.13.1.md
@@ -0,0 +1,10 @@
+# Release 3.13.1 (2025-11-12)
+
+* Based on [upstream Nix 2.32.4](../release-notes/rl-2.32.md).
+
+## What's Changed
+* nix bundle: Wait for async path writer by @edolstra in [DeterminateSystems/nix-src#260](https://github.com/DeterminateSystems/nix-src/pull/260)
+* Sync with upstream 2.32.4 by @edolstra in [DeterminateSystems/nix-src#261](https://github.com/DeterminateSystems/nix-src/pull/261)
+
+
+**Full Changelog**: [v3.13.0...v3.13.1](https://github.com/DeterminateSystems/nix-src/compare/v3.13.0...v3.13.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.13.2.md b/doc/manual/source/release-notes-determinate/v3.13.2.md
new file mode 100644
index 000000000000..2490b865e6bc
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.13.2.md
@@ -0,0 +1,68 @@
+# Release 3.13.2 (2025-11-19)
+
+* Based on [upstream Nix 2.32.4](../release-notes/rl-2.32.md).
+
+## What's Changed
+
+### Abbreviate flakerefs in lockfile diffs and `nix flake metadata`
+
+Flake refs are now abbreviated when possible, to reduce visual clutter.
+
+For example, this changes
+
+```
+• Updated input 'blender-bin':
+ 'https://api.flakehub.com/f/pinned/edolstra/blender-bin/1.0.19/01993ca7-2aa8-746f-96f5-ca8d2c2b962d/source.tar.gz?narHash=sha256-ZqVhVl9UYVErF8HW8lcvqss005VWYjuX//rZ%2BOmXyHg%3D' (2025-09-12)
+ → 'https://api.flakehub.com/f/pinned/edolstra/blender-bin/1.0.20/019a8772-b044-7738-8c03-109bdc9f0a01/source.tar.gz?narHash=sha256-sVj9Gmx0kwTDQPJ5kgQYszE3Hdjevu0zx0b/bL2fyUc%3D' (2025-11-15)
+• Updated input 'nix':
+ 'github:DeterminateSystems/nix-src/236ebef6514f3a2a9765c8a1d80dd503b8e672be?narHash=sha256-s6/Err0yqOp5fM3OdCF1vhmEYpeElbPOWX88YrW2qj4%3D' (2025-10-23)
+ → 'github:DeterminateSystems/nix-src/ef054dc06e9701597bce0b0572af18cb4c7e7277?narHash=sha256-uqYmH0KA8caQqX5u4BMarZsuDlC%2B71HRsH3h4f3DPCA%3D' (2025-11-12)
+```
+
+to
+
+```
+• Updated input 'blender-bin':
+ 'https://api.flakehub.com/f/pinned/edolstra/blender-bin/1.0.19/01993ca7-2aa8-746f-96f5-ca8d2c2b962d/source.tar.gz' (2025-09-12)
+ → 'https://api.flakehub.com/f/pinned/edolstra/blender-bin/1.0.20/019a8772-b044-7738-8c03-109bdc9f0a01/source.tar.gz' (2025-11-15)
+• Updated input 'nix':
+ 'github:DeterminateSystems/nix-src/236ebef' (2025-10-23)
+ → 'github:DeterminateSystems/nix-src/ef054dc' (2025-11-12)
+```
+
+PR: [DeterminateSystems/nix-src#264](https://github.com/DeterminateSystems/nix-src/pull/264)
+
+### `nix flake prefetch-inputs` now skips build-time inputs
+
+Build-time inputs can already be fetched in parallel, so prefetching them is usually not what you want.
+
+This can be especially noticeable in projects that make extensive use of build-time flake inputs.
+
+PR: [DeterminateSystems/nix-src#263](https://github.com/DeterminateSystems/nix-src/pull/263)
+
+### Don't compute `revCount`/`lastModified` if they're already specified
+
+We don't care if the user (or more likely the lock file) specifies an incorrect value for these attributes, since it doesn't matter for security (unlike content hashes like `narHash`).
+
+This can save time when operating on large repos -- having to recalculate these attributes could slow things down greatly.
+
+PR: [DeterminateSystems/nix-src#269](https://github.com/DeterminateSystems/nix-src/pull/269)
+
+### Avoid unnecessary Git refetches
+
+This fixes the issue where updating a Git input does a non-shallow fetch, and then a subsequent eval does a shallow refetch because the `revCount` is already known.
+
+Now the subsequent eval will reuse the repo used in the first fetch.
+
+PR: [DeterminateSystems/nix-src#270](https://github.com/DeterminateSystems/nix-src/pull/270)
+
+### Use our mirrored flake registry
+
+The flake registry is security-critical and thus should have high availability.
+
+By mirroring the upstream Nix flake registry, we can make it less likely that a GitHub outage affects being able to resolve from the registry.
+
+PR: [DeterminateSystems/nix-src#271](https://github.com/DeterminateSystems/nix-src/pull/271)
+
+
+**Full Changelog**: [v3.13.1...v3.13.2](https://github.com/DeterminateSystems/nix-src/compare/v3.13.1...v3.13.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.14.0.md b/doc/manual/source/release-notes-determinate/v3.14.0.md
new file mode 100644
index 000000000000..d72d5d21468c
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.14.0.md
@@ -0,0 +1,159 @@
+# Release 3.14.0 (2025-12-08)
+
+* Based on [upstream Nix 2.32.4](../release-notes/rl-2.32.md).
+
+## What is going on?! `nix ps` to the rescue
+
+Determinate Nix now features a `nix ps` command to summarize all of the active builds and child processes:
+
+```
+$ nix ps
+USER PID CPU DERIVATION/COMMAND
+_nixbld1 30167 0.4s /nix/store/h431bcfml83czhpyzljhp9mw4yrq95vs-determinate-nix-manual-3.14.0.drv (wall=9s)
+_nixbld1 30167 0.2s └───bash -e /nix/store/jwqf79v5p51x9mv8vx20fv9mzm2x7kig-source-stdenv.sh /nix/store/285whzixr5k1kfj6nidyj29mqqgv7n0b-default-builder.s
+_nixbld1 30278 0.0s └───ninja -j14
+_nixbld1 30279 0.0s ├───/nix/store/p7rag2cw99d7alp6749rjqp71qc0mnzl-python3-3.12.11/bin/python3.12 /nix/store/8k5fancbc5fjmxq6izn0z4inwnmpj09y-mes
+_nixbld1 30286 0.0s │ └───/nix/store/z59zm01pjwzil2qkvv0s4ibk54risy9a-determinate-nix-3.14.0/bin/nix config show --json
+_nixbld1 30280 0.0s ├───/nix/store/p7rag2cw99d7alp6749rjqp71qc0mnzl-python3-3.12.11/bin/python3.12 /nix/store/8k5fancbc5fjmxq6izn0z4inwnmpj09y-mes
+_nixbld1 30287 0.0s │ └───/nix/store/z59zm01pjwzil2qkvv0s4ibk54risy9a-determinate-nix-3.14.0/bin/nix __dump-language
+_nixbld1 30281 0.0s ├───/nix/store/p7rag2cw99d7alp6749rjqp71qc0mnzl-python3-3.12.11/bin/python3.12 /nix/store/8k5fancbc5fjmxq6izn0z4inwnmpj09y-mes
+_nixbld1 30288 0.0s │ └───/nix/store/z59zm01pjwzil2qkvv0s4ibk54risy9a-determinate-nix-3.14.0/bin/nix __dump-cli
+_nixbld1 30282 0.0s ├───/nix/store/p7rag2cw99d7alp6749rjqp71qc0mnzl-python3-3.12.11/bin/python3.12 /nix/store/8k5fancbc5fjmxq6izn0z4inwnmpj09y-mes
+_nixbld1 30284 0.0s │ └───/nix/store/z59zm01pjwzil2qkvv0s4ibk54risy9a-determinate-nix-3.14.0/bin/nix __dump-xp-features
+_nixbld1 30283 0.0s └───/nix/store/p7rag2cw99d7alp6749rjqp71qc0mnzl-python3-3.12.11/bin/python3.12 /nix/store/8k5fancbc5fjmxq6izn0z4inwnmpj09y-mes
+_nixbld1 30285 0.0s └───/nix/store/bs1pvy8margy5sj0jwahchxbjnqzi14i-bash-5.2p37/bin/bash -euo pipefail -c if type -p build-release-notes > /de
+_nixbld1 30289 0.0s └───changelog-d ../source/release-notes/../../rl-next
+```
+
+For the integrators out there, it also has a `--json` flag with all the raw data.
+
+PRs:
+* [DeterminateSystems/nix-src#282](https://github.com/DeterminateSystems/nix-src/pull/282)
+* [DeterminateSystems/nix-src#287](https://github.com/DeterminateSystems/nix-src/pull/287)
+
+
+## Nix `build`, `profile`, and `flake check` commands tell you what output failed
+
+These commands now tell you exactly what flake outputs failed to build.
+Previously, the error would indicate only what derivation failed to build -- but not which output.
+
+Now, `nix build` and `nix profile` commands provide the specific output:
+
+```
+$ nix build .#oneFakeHash .#badSystem --keep-going
+❌ git+file:///Users/grahamc/src/github.com/DeterminateSystems/samples#oneFakeHash
+error: hash mismatch in fixed-output derivation '/nix/store/58pp1y74j4f5zxfq50xncv2wvnxf7w3y-one-fake-hash.drv':
+ specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ got: sha256-i7j83d71sibS/ssSjLJ5PMKmbhjAM+BHW0aElvkgEwY=
+❌ git+file:///Users/grahamc/src/github.com/DeterminateSystems/samples#badSystem
+error: Cannot build '/nix/store/5vsaxi730yl2icngkyvn8wiflik5wfmq-bad-system.drv'.
+ Reason: required system or feature not available
+ Required system: 'bogus' with features {}
+ Current system: 'aarch64-darwin' with features {apple-virt, benchmark, big-parallel, nixos-test}
+```
+
+And in a great change for CI, `nix flake check` users get improved summaries too:
+
+```
+$ nix flake check
+❓ checks.aarch64-darwin.twoFakeHashes (cancelled)
+❓ checks.aarch64-darwin.badSystemNested (cancelled)
+❓ checks.aarch64-darwin.oneFakeHash (cancelled)
+❓ checks.aarch64-darwin.failure (cancelled)
+❓ checks.aarch64-darwin.badSystem (cancelled)
+❓ checks.aarch64-darwin.weirdHash (cancelled)
+❓ checks.aarch64-darwin.all (cancelled)
+❓ checks.aarch64-darwin.fakeHashes (cancelled)
+❓ checks.aarch64-darwin.incorrectHashes (cancelled)
+❓ checks.aarch64-darwin.badFeaturesNested (cancelled)
+❓ checks.aarch64-darwin.failureNested (cancelled)
+❌ checks.aarch64-darwin.badFeatures
+error: Cannot build '/nix/store/sc1cyhrpsm9yjx55cl2zzyr5lypwigi6-bad-feature.drv'.
+ Reason: required system or feature not available
+ Required system: 'aarch64-darwin' with features {bogus}
+ Current system: 'aarch64-darwin' with features {apple-virt, benchmark, big-parallel, nixos-test}
+```
+
+PRs:
+* [DeterminateSystems/nix-src#281](https://github.com/DeterminateSystems/nix-src/pull/281)
+* [DeterminateSystems/nix-src#285](https://github.com/DeterminateSystems/nix-src/pull/285)
+
+
+## More seamless upgrades from Nix 2.18 and Nix 2.19
+
+We've heard from some users who are trying to upgrade from Nix 2.18.
+
+These users are primarily experiencing problems caused by Nix 2.20 switching from `git-archive` to `libgit2` for fetching repositories.
+This change caused some `git-archive` filters to stop executing, like autocrlf.
+Not running those filters is an improvement, and running those filters *can cause* instability in source hashes.
+However, this switch *did* cause previously valid hashes to become invalid.
+
+Determinate Nix now retries fetching an old archive with `git-archive` as a fallback when libgit2 fails to provide the correct source.
+
+Further, to support a progressive migration Determinate Nix has a new option: `nix-219-compat`.
+Set `nix-219-compat=true` to cause Nix to author new flake.nix files with a `git-archive` based source hash.
+
+Finally, a user identified `builtins.path` changed since 2.18 and stopped propagating references.
+We have corrected this regression.
+
+PRs:
+* [DeterminateSystems/nix-src#283](https://github.com/DeterminateSystems/nix-src/pull/283)
+* [DeterminateSystems/nix-src#278](https://github.com/DeterminateSystems/nix-src/pull/278)
+
+## Flake registry mirroring
+
+Determinate Nix now includes a fallback copy of the Nix Registry.
+This change builds on top of v3.13.2, where we changed from the upstream Nix registry to a mirrored copy hosted by `install.determinate.systems`.
+
+Combined, these changes increase the reliability of Nix in the face of network outages.
+
+> [!NOTE]
+> Flake registry URLs for `flake.nix` inputs is deprecated.
+> The flake registry should only be used for interactive use.
+> See: https://github.com/DeterminateSystems/nix-src/issues/37
+
+PR: [DeterminateSystems/nix-src#273](https://github.com/DeterminateSystems/nix-src/pull/273)
+
+## Flake registry resolution CLI
+
+We added the new command `nix registry resolve` to help debug issues with Flake registries.
+This command looks up a flake registry input name and returns the flakeref it resolves to.
+
+For example, looking up Nixpkgs:
+
+```
+$ nix registry resolve nixpkgs
+github:NixOS/nixpkgs/nixpkgs-unstable
+```
+
+Or looking up the 25.11 branch of Nixpkgs:
+```
+$ nix registry resolve nixpkgs/release-25.11
+github:NixOS/nixpkgs/release-25.11
+```
+
+> [!NOTE]
+> Flake registry URLs for `flake.nix` inputs is deprecated.
+> The flake registry should only be used for interactive use.
+> See: https://github.com/DeterminateSystems/nix-src/issues/37
+
+PR: [DeterminateSystems/nix-src#273](https://github.com/DeterminateSystems/nix-src/pull/273)
+
+## Improved Docker image packaging
+
+Thanks to `employee-64c7dcd530593118dcccc3fb`, the OCI / Docker images built by the Determinate Nix flake.nix can be further customized.
+
+Users can specify their own base image by specifying `fromImage`.
+
+Additionally, users can specify additional directories to include at the beginning or end of the PATH variable with `extraPrePaths` and `extraPostPaths`.
+
+PRs:
+* [DeterminateSystems/nix-src#277](https://github.com/DeterminateSystems/nix-src/pull/277)
+* [DeterminateSystems/nix-src#280](https://github.com/DeterminateSystems/nix-src/pull/280)
+
+## Bug fixes
+
+* Corrected an error with parallel evaluation which ([DeterminateSystems/nix-src#286](https://github.com/DeterminateSystems/nix-src/pull/286))
+* Fixed compatibility with updated Nixpkgs versions. Thank you SandaruKasa! ([DeterminateSystems/nix-src#284](https://github.com/DeterminateSystems/nix-src/pull/284))
+
+**Full Changelog**: [v3.13.2...v3.14.0](https://github.com/DeterminateSystems/nix-src/compare/v3.13.2...v3.14.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.15.0.md b/doc/manual/source/release-notes-determinate/v3.15.0.md
new file mode 100644
index 000000000000..fb568374c3f2
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.15.0.md
@@ -0,0 +1,28 @@
+# Release 3.15.0 (2025-12-19)
+
+* Based on [upstream Nix 2.33.0](../release-notes/rl-2.33.md).
+
+## `fetchTree` improvement
+
+`builtins.fetchTree` now implicitly treats the fetched tree as "final" when a `narHash` is supplied, meaning that it will not return attributes like `lastModified` or `revCount` unless they were specified by the caller. This makes it possible to substitute the tree from a binary cache, which is often more efficient. Furthermore, for Git inputs, it allows Nix to perform a shallow fetch, which is much faster.
+
+This is primarily useful for users of `flake-compat`, since it uses `builtins.fetchTree` internally.
+
+PR: [DeterminateSystems/nix-src#297](https://github.com/DeterminateSystems/nix-src/pull/297)
+
+## New builtin function `builtins.filterAttrs`
+
+Nixpkgs heavily relies on this function to select attributes from an attribute set:
+
+```nix
+filterAttrs = pred: set: removeAttrs set (filter (name: !pred name set.${name}) (attrNames set));
+```
+
+Determinate Nix now has this function built-in, which makes it much faster.
+
+PR: [DeterminateSystems/nix-src#291](https://github.com/DeterminateSystems/nix-src/pull/291)
+
+## New Contributors
+* @not-ronjinger made their first contribution in [DeterminateSystems/nix-src#291](https://github.com/DeterminateSystems/nix-src/pull/291)
+
+**Full Changelog**: [v3.14.0...v3.15.0](https://github.com/DeterminateSystems/nix-src/compare/v3.14.0...v3.15.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.15.1.md b/doc/manual/source/release-notes-determinate/v3.15.1.md
new file mode 100644
index 000000000000..9243962cf4b5
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.15.1.md
@@ -0,0 +1,15 @@
+# Release 3.15.1 (2025-12-24)
+
+* Based on [upstream Nix 2.33.0](../release-notes/rl-2.33.md).
+
+## What's Changed
+Users reported the v3.15.0 tarball could not be fetched in a fixed-output derivation due to current stdenv paths present in the documentation. This release eliminated those paths.
+
+PR: [DeterminateSystems/nix-src#306](https://github.com/DeterminateSystems/nix-src/pull/306)
+
+Additionally, this change re-enables CodeRabbit's code review on our changes. CodeRabit was disabled by the upstream project, and we inadvertently included that change.
+
+PR: [DeterminateSystems/nix-src#305](https://github.com/DeterminateSystems/nix-src/pull/305)
+
+
+**Full Changelog**: [v3.15.0...v3.15.1](https://github.com/DeterminateSystems/nix-src/compare/v3.15.0...v3.15.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.15.2.md b/doc/manual/source/release-notes-determinate/v3.15.2.md
new file mode 100644
index 000000000000..c5e5339990b5
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.15.2.md
@@ -0,0 +1,44 @@
+# Release 3.15.2 (2026-01-20)
+
+* Based on [upstream Nix 2.33.1](../release-notes/rl-2.33.md).
+
+## What's Changed
+
+### Improved performance for users with a lot of dependencies
+
+If you even had the occasion to query your binary cache for over 110,000 store path simultaneously you might have found it rather slow.
+Previously, Nix would enqueue all the downloads at once.
+This appears to trigger quadratic behavior in curl.
+
+Determinate Nix now enqueues a reasonable number of subtitutions once.
+At the same time, we fixed a performance issue in the progress bar with so many dependencies.
+
+PR: [DeterminateSystems/nix-src#315](https://github.com/DeterminateSystems/nix-src/pull/315)
+
+### Lazy trees update: path inputs are now lazy
+
+Previously inputs like `path:///path/to/a/dependency` were eagerly fetched when lazy-trees is enabled.
+In Determinate Nix 3.15.2, path input types are also fetched lazily.
+This change saves time and improves performance for users with path inputs.
+
+PRs:
+* [DeterminateSystems/nix-src#312](https://github.com/DeterminateSystems/nix-src/pull/312)
+* [DeterminateSystems/nix-src#317](https://github.com/DeterminateSystems/nix-src/pull/317)
+
+### `nix repl` now reports the Determinate version
+
+A small change, but now `nix repl` correctly reports the Determinate Nix version:
+
+```
+$ nix repl
+Nix (Determinate Nix 3.15.1) 2.33.0
+Type :? for help.
+nix-repl>
+```
+
+PR: [DeterminateSystems/nix-src#316](https://github.com/DeterminateSystems/nix-src/pull/316)
+
+## New Contributors
+* @dliberalesso made their first contribution in [DeterminateSystems/nix-src#313](https://github.com/DeterminateSystems/nix-src/pull/313)
+
+**Full Changelog**: [v3.15.1...v3.15.2](https://github.com/DeterminateSystems/nix-src/compare/v3.15.1...v3.15.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.16.0.md b/doc/manual/source/release-notes-determinate/v3.16.0.md
new file mode 100644
index 000000000000..8e80ac68402a
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.16.0.md
@@ -0,0 +1,53 @@
+# Release 3.16.0 (2026-02-12)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## Support `.gitattributes` in subdirectories
+
+For performance, the Git backwards compatibility hack was only applied to repositories that had a `.gitattributes` in the root directory.
+However, it is possible to have a `.gitattributes` file in a subdirectory, and there are real-world repos that do this, so we have dropped that restriction.
+
+PR: [DeterminateSystems/nix-src#335](https://github.com/DeterminateSystems/nix-src/pull/335)
+
+## Fix hung downloads when `http-connections = 0`
+
+When we started limiting the number of active cURL handles in [DeterminateSystems/nix-src#315](https://github.com/DeterminateSystems/nix-src/pull/315), we did not take into account that `http-connections = 0` is a special value that means, roughly "as many connections as possible" (the exact behavior is up to cURL).
+
+This should now be fixed.
+
+PR: [DeterminateSystems/nix-src#327](https://github.com/DeterminateSystems/nix-src/pull/327)
+
+## `builtins.getFlake` now supports relative paths
+
+`builtins.getFlake` now supports using relative paths, like:
+
+```nix
+builtins.getFlake ./..
+```
+
+instead of the hacky
+
+```nix
+builtins.getFlake (builtins.flakeRefToString { type = "path"; path = self.sourceInfo.outPath; narHash = self.narHash; });
+```
+
+Note that allowing `builtins.getFlake` to fetch from store paths is probably a bad idea, since it's ambiguous when using chroot stores, so a warning will be printed when this is encountered.
+
+PRs:
+* [DeterminateSystems/nix-src#337](https://github.com/DeterminateSystems/nix-src/pull/337)
+* [DeterminateSystems/nix-src#338](https://github.com/DeterminateSystems/nix-src/pull/338)
+
+## Fixed a bug with too many open files
+
+Recently, some users have reported seeing errors like:
+
+```
+error: creating git packfile indexer: failed to create temporary file '/Users/anon/.cache/nix/tarball-cache-v2/objects/pack/pack_git2_56d617039ac17c2b': Too many open files
+```
+
+This should now be fixed.
+
+PR: [DeterminateSystems/nix-src#347](https://github.com/DeterminateSystems/nix-src/pull/347)
+
+
+**Full Changelog**: [v3.15.2...v3.16.0](https://github.com/DeterminateSystems/nix-src/compare/v3.15.2...v3.16.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.16.1.md b/doc/manual/source/release-notes-determinate/v3.16.1.md
new file mode 100644
index 000000000000..6ecd5262b7c9
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.16.1.md
@@ -0,0 +1,24 @@
+# Release 3.16.1 (2026-02-22)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+
+### `nix store info` now correctly support `--refresh` and `--offline`
+
+Previously, Nix had a hard-coded TTL of seven days.
+Determinate Nix moved that TTL to a new setting `narinfo-cache-meta-ttl` and now `nix store info` respects the `--refresh` and `--offline` flags.
+
+This change makes it possible to freshly validate authenticating to a remote store.
+
+PR: [DeterminateSystems/nix-src#355](https://github.com/DeterminateSystems/nix-src/pull/355)
+
+### Corrected `builtins.hashString` behavior under lazy trees
+
+`builtins.hashString` now devirtualizes lazy paths, making the hash result stable.
+
+PR: [DeterminateSystems/nix-src#360](https://github.com/DeterminateSystems/nix-src/pull/360)
+
+
+
+**Full Changelog**: [v3.16.0...v3.16.1](https://github.com/DeterminateSystems/nix-src/compare/v3.16.0...v3.16.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.16.2.md b/doc/manual/source/release-notes-determinate/v3.16.2.md
new file mode 100644
index 000000000000..73a1b25f21c8
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.16.2.md
@@ -0,0 +1,8 @@
+# Release 3.16.2 (2026-02-23)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+This release is exclusively improvements to `determinate-nixd`.
+
+
diff --git a/doc/manual/source/release-notes-determinate/v3.16.3.md b/doc/manual/source/release-notes-determinate/v3.16.3.md
new file mode 100644
index 000000000000..fcc6fefa33c7
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.16.3.md
@@ -0,0 +1,6 @@
+# Release 3.16.3 (2026-02-24)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+This release only includes changes in determinate-nixd.
diff --git a/doc/manual/source/release-notes-determinate/v3.17.0.md b/doc/manual/source/release-notes-determinate/v3.17.0.md
new file mode 100644
index 000000000000..e09938786e55
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.17.0.md
@@ -0,0 +1,10 @@
+# Release 3.17.0 (2026-03-04)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+Determinate Nix 3.17.0 brings exciting improvements like Flake Schemas, provenance, and Wasm / WASI.
+We'll be posting more details over the next week or so on our blog: https://determinate.systems/blog/.
+
+
+**Full Changelog**: [v3.16.3...v3.17.0](https://github.com/DeterminateSystems/nix-src/compare/v3.16.3...v3.17.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.17.1.md b/doc/manual/source/release-notes-determinate/v3.17.1.md
new file mode 100644
index 000000000000..19da0209931e
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.17.1.md
@@ -0,0 +1,49 @@
+# Release 3.17.1 (2026-03-18)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+
+### Provenance now supports "build-time" provenance tags
+
+Users can now specify key/value tags to attach to a build's provenance.
+For example, the `nix-installer-action` now attaches the following properties to each build:
+
+- github_workflow_ref
+- github_workflow_sha
+- github_sha
+- github_run_attempt
+- github_run_id
+- github_run_number
+- github_job
+- github_ref
+- github_repository
+- github_server_url
+
+PR: [DeterminateSystems/nix-src#374](https://github.com/DeterminateSystems/nix-src/pull/374)
+
+### Flake inputs are substituted when possible
+
+Locked flake inputs will be fetched from a binary cache when possible, instead of preferring the authoritative flake source.
+This is intended to reduce load on code forges, and also improves the user experience on large flake inputs.
+
+PR: [DeterminateSystems/nix-src#380](https://github.com/DeterminateSystems/nix-
+
+### `nix profile upgrade` and `nix profile remove` now support tab completion
+
+PR: [DeterminateSystems/nix-src#382](https://github.com/DeterminateSystems/nix-src/pull/382)
+
+### Flake schemas can now define an output as "legacy"
+
+"Legacy" flakes are intended for legacyPackages on Nixpkgs.
+The "legacy" mark is intended to reduce evaluation time due to the extreme size of legacyPackages.
+Note: the name "legacy" is not intended as a value judgement, and at this point we're sort of stuck with the name.
+
+### Bug fixes
+
+* Fix crash in `nix repl` loading an invalid WASM file twice. [DeterminateSystems/nix-src#378](https://github.com/DeterminateSystems/nix-src/pull/378)
+* Don't crash if SIGINT happens while printing an exception. [DeterminateSystems/nix-src#384](https://github.com/DeterminateSystems/nix-src/pull/384)
+* `nix-env -i`: Wait for the async path writer. [DeterminateSystems/nix-src#385](https://github.com/DeterminateSystems/nix-src/pull/385)
+
+
+**Full Changelog**: [v3.17.0...v3.17.1](https://github.com/DeterminateSystems/nix-src/compare/v3.17.0...v3.17.1)
diff --git a/doc/manual/source/release-notes-determinate/v3.17.2.md b/doc/manual/source/release-notes-determinate/v3.17.2.md
new file mode 100644
index 000000000000..ce45a8df7ec7
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.17.2.md
@@ -0,0 +1,16 @@
+# Release 3.17.2 (2026-03-27)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+
+### Bug fixes
+
+* Cache `getLegacyGitAccessor()`. [DeterminateSystems/nix-src#396](https://github.com/DeterminateSystems/nix-src/pull/396)
+* Don't destroy `windowSize` mutex. [DeterminateSystems/nix-src#397](https://github.com/DeterminateSystems/nix-src/pull/397)
+* When doing concurrent substitutions of the same path, download only once. [DeterminateSystems/nix-src#398](https://github.com/DeterminateSystems/nix-src/pull/398)
+* `builtins.getFlake`: Handle `path:` where *p* has a discarded string context. [DeterminateSystems/nix-src#402](https://github.com/DeterminateSystems/nix-src/pull/402)
+* Ensure `_interruptCallbacks` is alive while `signalHandlerThread` is running. [DeterminateSystems/nix-src#403](https://github.com/DeterminateSystems/nix-src/pull/403)
+* Fix assertion failure in `nix::BuiltPath::toRealisedPaths()`. [DeterminateSystems/nix-src#401](https://github.com/DeterminateSystems/nix-src/pull/401)
+
+**Full Changelog**: [v3.17.1...v3.17.2](https://github.com/DeterminateSystems/nix-src/compare/v3.17.1...v3.17.2)
diff --git a/doc/manual/source/release-notes-determinate/v3.17.3.md b/doc/manual/source/release-notes-determinate/v3.17.3.md
new file mode 100644
index 000000000000..24463e48485f
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.17.3.md
@@ -0,0 +1,48 @@
+# Release 3.17.3 (2026-04-07)
+
+* Based on [upstream Nix 2.33.3](../release-notes/rl-2.33.md).
+
+## What's Changed
+
+### Fix for GHSA-g3g9-5vj6-r3gj: root privilege escalation via the Nix daemon
+
+This release contains a critical fix for a security vulnerability on Linux that allows any user that has access to the Nix daemon to obtain root privileges.
+This vulnerability affects all versions of Determinate Nix prior to 3.17.3, and all versions of upstream Nix prior to 2.34.5, 2.33.4, 2.32.7, 2.31.4, 2.30.4, 2.29.3, and 2.28.6.
+All Linux users are advised to upgrade immediately.
+
+For more details, see the upstream advisory [GHSA-g3g9-5vj6-r3gj](https://github.com/NixOS/nix/security/advisories/GHSA-g3g9-5vj6-r3gj).
+Many thanks to edef for reporting this issue and to Sergei Zimmerman for implementing the fix.
+
+### Avoiding duplicate source tree downloads
+
+When multiple Nix processes (like `nix-eval-jobs` instances) fetch the same source tree at the same time, it was previously possible for each process to perform the download independently, resulting in wasteful multiple downloads of the same source tree. Nix now uses a per-source tree lock to ensure that only one process performs the download.
+
+PR: [DeterminateSystems/nix-src#410](https://github.com/DeterminateSystems/nix-src/pull/410)
+
+### WAT support in `builtins.wasm`
+
+`builtins.wasm` now supports WebAssembly Text Format (WAT) in addition to binary Wasm modules.
+This is primarily useful for testing.
+
+PR: [DeterminateSystems/nix-src#405](https://github.com/DeterminateSystems/nix-src/pull/405)
+
+### Git shallow fetching
+
+Nix now removes Git's `shallow.lock` lock file before running `git fetch`.
+This prevents fetches from hanging if Git was previously interrupted.
+
+PR: [DeterminateSystems/nix-src#414](https://github.com/DeterminateSystems/nix-src/pull/414)
+
+### Debugging improvements
+
+Certain C++ exceptions that should never happen (like `std::logic_error`) are now treated as aborts, providing stack traces and core dumps that are easier to debug.
+
+PR: [DeterminateSystems/nix-src#407](https://github.com/DeterminateSystems/nix-src/pull/407)
+
+### Bug fixes
+
+* `nix develop` respects `legacyPackages` again. [DeterminateSystems/nix-src#413](https://github.com/DeterminateSystems/nix-src/pull/413)
+
+* The `lookupPathResolved` data structure has been made thread-safe. [DeterminateSystems/nix-src#415](https://github.com/DeterminateSystems/nix-src/pull/415)
+
+**Full Changelog**: [v3.17.2...v3.17.3](https://github.com/DeterminateSystems/nix-src/compare/v3.17.2...v3.17.3)
diff --git a/doc/manual/source/release-notes-determinate/v3.8.6.md b/doc/manual/source/release-notes-determinate/v3.8.6.md
new file mode 100644
index 000000000000..8f917f2362ff
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.8.6.md
@@ -0,0 +1,14 @@
+# Release 3.8.6 (2025-08-19)
+
+* Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+## What's Changed
+* Auto update release notes by @grahamc in [DeterminateSystems/nix-src#170](https://github.com/DeterminateSystems/nix-src/pull/170)
+* Use WAL mode for SQLite cache databases (2nd attempt) by @edolstra in [DeterminateSystems/nix-src#167](https://github.com/DeterminateSystems/nix-src/pull/167)
+* Enable parallel marking in boehm-gc by @edolstra in [DeterminateSystems/nix-src#168](https://github.com/DeterminateSystems/nix-src/pull/168)
+* BasicClientConnection::queryPathInfo(): Don't throw exception for invalid paths by @edolstra in [DeterminateSystems/nix-src#172](https://github.com/DeterminateSystems/nix-src/pull/172)
+* Fix queryPathInfo() negative caching by @edolstra in [DeterminateSystems/nix-src#173](https://github.com/DeterminateSystems/nix-src/pull/173)
+* forceDerivation(): Wait for async path write after forcing value by @edolstra in [DeterminateSystems/nix-src#176](https://github.com/DeterminateSystems/nix-src/pull/176)
+
+
+**Full Changelog**: [v3.8.5...v3.8.6](https://github.com/DeterminateSystems/nix-src/compare/v3.8.5...v3.8.6)
diff --git a/doc/manual/source/release-notes-determinate/v3.9.0.md b/doc/manual/source/release-notes-determinate/v3.9.0.md
new file mode 100644
index 000000000000..66deb69b6192
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.9.0.md
@@ -0,0 +1,45 @@
+# Release 3.9.0 (2025-08-26)
+
+* Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+## What's Changed
+
+### Build-time flake inputs
+
+Some of our users have hundreds or thousands of flake inputs.
+In those cases, it is painfully slow for Nix to fetch all the inputs during evaluation of the flake.
+
+Determinate Nix has an experimental feature for deferring the fetching to build time of the dependent derivations.
+
+This is currently in developer preview.
+If you would like to try it, add the experimental feature to your `/etc/nix/nix.custom.conf`:
+
+```ini
+extra-experimental-features = build-time-fetch-tree
+```
+
+Then, mark an input to be fetched at build time:
+
+```nix
+inputs.example = {
+ type = "github";
+ owner = "DeterminateSystems";
+ repo = "example";
+ flake = false; # <-- currently required
+ buildTime = true;
+};
+```
+
+Let us know what you think!
+
+PR: [DeterminateSystems/nix-src#49](https://github.com/DeterminateSystems/nix-src/pull/49)
+
+### Corrected inconsistent behavior of `nix flake check`
+
+Users reported that `nix flake check` would not consistently validate the entire flake.
+
+We've fixed this issue and improved our testing around `nix flake check`.
+
+PR: [DeterminateSystems/nix-src#182](https://github.com/DeterminateSystems/nix-src/pull/182)
+
+**Full Changelog**: [v3.8.6...v3.9.0](https://github.com/DeterminateSystems/nix-src/compare/v3.8.6...v3.9.0)
diff --git a/doc/manual/source/release-notes-determinate/v3.9.1.md b/doc/manual/source/release-notes-determinate/v3.9.1.md
new file mode 100644
index 000000000000..38d17199c2c0
--- /dev/null
+++ b/doc/manual/source/release-notes-determinate/v3.9.1.md
@@ -0,0 +1,20 @@
+# Release 3.9.1 (2025-08-28)
+
+- Based on [upstream Nix 2.30.2](../release-notes/rl-2.30.md).
+
+### A useful `nix flake init` template default
+
+Nix's default flake template is [extremely bare bones](https://github.com/NixOS/templates/blob/ad0e221dda33c4b564fad976281130ce34a20cb9/trivial/flake.nix), and not a useful starting point.
+
+Deteminate Nix now uses [a more fleshed out default template](https://github.com/DeterminateSystems/flake-templates/blob/8af99b99627da41f16897f60eb226db30c775e76/default/flake.nix), including targeting multiple systems.
+
+PR: [DeterminateSystems/nix-src#180](https://github.com/DeterminateSystems/nix-src/pull/180)
+
+### Build cancellation is repaired on macOS
+
+A recent macOS update changed how signals are handled by Nix and broke using Ctrl-C to stop a build.
+Determinate Nix on macOS correctly handles these signals and stops the build.
+
+PR: [DeterminateSystems/nix-src#184](https://github.com/DeterminateSystems/nix-src/pull/184)
+
+**Full Changelog**: [v3.9.0...v3.9.1](https://github.com/DeterminateSystems/nix-src/compare/v3.9.0...v3.9.1)
diff --git a/doc/manual/source/release-notes/rl-0.12.md b/doc/manual/source/release-notes/rl-0.12.md
index 3a4aba07d693..3541b6487e73 100644
--- a/doc/manual/source/release-notes/rl-0.12.md
+++ b/doc/manual/source/release-notes/rl-0.12.md
@@ -80,7 +80,7 @@
...
the following paths will be downloaded/copied (30.02 MiB):
/nix/store/4m8pvgy2dcjgppf5b4cj5l6wyshjhalj-samba-3.2.4
- /nix/store/7h1kwcj29ip8vk26rhmx6bfjraxp0g4l-libunwind-0.98.6
+ /nix/store/spc1m987vlibchdx369qwa391s738s7l-libunwind-0.98.6
...
- Language features:
diff --git a/doc/manual/source/release-notes/rl-0.8.md b/doc/manual/source/release-notes/rl-0.8.md
index 5ba6e0e7217c..2bc6352c3540 100644
--- a/doc/manual/source/release-notes/rl-0.8.md
+++ b/doc/manual/source/release-notes/rl-0.8.md
@@ -63,7 +63,7 @@ Nix 0.8 has the following improvements:
can query all paths that directly or indirectly use a certain Glibc:
$ nix-store -q --referrers-closure \
- /nix/store/8lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
+ /nix/store/1a6mdrjz4wn7b9sfmcw5ggbk1mi281mh-glibc-2.3.4
- The concept of fixed-output derivations has been formalised.
Previously, functions such as `fetchurl` in Nixpkgs used a hack
diff --git a/doc/manual/source/release-notes/rl-2.0.md b/doc/manual/source/release-notes/rl-2.0.md
index 25cc5e0a5f38..181940f616f9 100644
--- a/doc/manual/source/release-notes/rl-2.0.md
+++ b/doc/manual/source/release-notes/rl-2.0.md
@@ -66,7 +66,7 @@ This release has the following new features:
nix copy --to ssh://machine nixpkgs.hello
- nix copy --to ssh://machine /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
+ nix copy --to ssh://machine /nix/store/qbhyj3blxpw2i6pb7c6grc9185nbnpvy-hello-2.10
nix copy --to ssh://machine '(with import {}; hello)'
@@ -187,7 +187,7 @@ This release has the following new features:
former is primarily useful in conjunction with remote stores,
e.g.
- nix ls-store --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
+ nix ls-store --store https://cache.nixos.org/ -lR /nix/store/qbhyj3blxpw2i6pb7c6grc9185nbnpvy-hello-2.10
lists the contents of path in a binary cache.
diff --git a/doc/manual/source/release-notes/rl-2.13.md b/doc/manual/source/release-notes/rl-2.13.md
index 168708113ea9..6976f91501be 100644
--- a/doc/manual/source/release-notes/rl-2.13.md
+++ b/doc/manual/source/release-notes/rl-2.13.md
@@ -25,7 +25,7 @@
* Allow explicitly selecting outputs in a store derivation installable, just like we can do with other sorts of installables.
For example,
```shell-session
- # nix build /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev
+ # nix build /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv^dev
```
now works just as
```shell-session
diff --git a/doc/manual/source/release-notes/rl-2.15.md b/doc/manual/source/release-notes/rl-2.15.md
index e7e52631ba40..1d30c70a4c0c 100644
--- a/doc/manual/source/release-notes/rl-2.15.md
+++ b/doc/manual/source/release-notes/rl-2.15.md
@@ -18,13 +18,13 @@
For example,
```shell-session
- $ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv
+ $ nix path-info /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv
```
now gives info about the derivation itself, while
```shell-session
- $ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*
+ $ nix path-info /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv^*
```
provides information about each of its outputs.
diff --git a/doc/manual/source/release-notes/rl-2.19.md b/doc/manual/source/release-notes/rl-2.19.md
index 04f8c9c28d29..0596ef909619 100644
--- a/doc/manual/source/release-notes/rl-2.19.md
+++ b/doc/manual/source/release-notes/rl-2.19.md
@@ -45,7 +45,7 @@
```json5
[
{
- "path": "/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15",
+ "path": "/nix/store/fvqsvk65d38p8qqir371ii0hyqxvjcw6-bash-5.2-p15",
"valid": true,
// ...
},
@@ -60,7 +60,7 @@
```json5
{
- "/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15": {
+ "/nix/store/fvqsvk65d38p8qqir371ii0hyqxvjcw6-bash-5.2-p15": {
// ...
},
"/nix/store/wffw7l0alvs3iw94cbgi1gmmbmw99sqb-home-manager-path": null,
@@ -69,7 +69,7 @@
This makes it match `nix derivation show`, which also maps store paths to information.
-- When Nix is installed using the [binary installer](@docroot@/installation/installing-binary.md), in supported shells (Bash, Zsh, Fish)
+- When Nix is installed using the binary installer, in supported shells (Bash, Zsh, Fish)
[`XDG_DATA_DIRS`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables) is now populated with the path to the `/share` subdirectory of the current profile.
This means that command completion scripts, `.desktop` files, and similar artifacts installed via [`nix-env`](@docroot@/command-ref/nix-env.md) or [`nix profile`](@docroot@/command-ref/new-cli/nix3-profile.md)
(experimental) can be found by any program that follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
diff --git a/doc/manual/source/release-notes/rl-2.20.md b/doc/manual/source/release-notes/rl-2.20.md
index eb724f600aa7..d54646379c88 100644
--- a/doc/manual/source/release-notes/rl-2.20.md
+++ b/doc/manual/source/release-notes/rl-2.20.md
@@ -182,7 +182,7 @@
«partially applied primop map»
nix-repl> builtins.trace lib.id "my-value"
- trace: «lambda id @ /nix/store/8rrzq23h2zq7sv5l2vhw44kls5w0f654-source/lib/trivial.nix:26:5»
+ trace: «lambda id @ /nix/store/kgr5lnaiiv08wb7k324yv1i1npjmrvjc-source/lib/trivial.nix:26:5»
"my-value"
```
diff --git a/doc/manual/source/release-notes/rl-2.24.md b/doc/manual/source/release-notes/rl-2.24.md
index e9b46bb22b70..f608fb54f7d9 100644
--- a/doc/manual/source/release-notes/rl-2.24.md
+++ b/doc/manual/source/release-notes/rl-2.24.md
@@ -268,6 +268,21 @@
be configured using the `warn-large-path-threshold` setting,
e.g. `--warn-large-path-threshold 100M`.
+- Wrap filesystem exceptions more correctly [#11378](https://github.com/NixOS/nix/pull/11378)
+
+ With the switch to `std::filesystem` in different places, Nix started to throw `std::filesystem::filesystem_error` in many places instead of its own exceptions.
+
+ This led to no longer generating error traces, for example when listing a non-existing directory.
+
+ This version catches these types of exception correctly and wraps them into Nix's own exeception type.
+
+ Author: [**@Mic92**](https://github.com/Mic92)
+
+- `` uses TLS verification [#11585](https://github.com/NixOS/nix/pull/11585)
+
+ Previously `` did not do TLS verification. This was because the Nix sandbox in the past did not have access to TLS certificates, and Nix checks the hash of the fetched file anyway. However, this can expose authentication data from `netrc` and URLs to man-in-the-middle attackers. In addition, Nix now in some cases (such as when using impure derivations) does *not* check the hash. Therefore we have now enabled TLS verification. This means that downloads by `` will now fail if you're fetching from a HTTPS server that does not have a valid certificate.
+
+ `` is also known as the builtin derivation builder `builtin:fetchurl`. It's not to be confused with the evaluation-time function `builtins.fetchurl`, which was not affected by this issue.
## Contributors
diff --git a/doc/manual/source/release-notes/rl-2.33.md b/doc/manual/source/release-notes/rl-2.33.md
index bed697029389..810dcad00b15 100644
--- a/doc/manual/source/release-notes/rl-2.33.md
+++ b/doc/manual/source/release-notes/rl-2.33.md
@@ -279,3 +279,35 @@ This release was made possible by the following 33 contributors:
- Henry [**(@cootshk)**](https://github.com/cootshk)
- Martin Joerg [**(@mjoerg)**](https://github.com/mjoerg)
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)
+# Release 2.33.3 (2026-02-13)
+
+- S3 binary caches now use virtual-hosted-style addressing by default [#15208](https://github.com/NixOS/nix/issues/15208)
+
+ S3 binary caches now use virtual-hosted-style URLs
+ (`https://bucket.s3.region.amazonaws.com/key`) instead of path-style URLs
+ (`https://s3.region.amazonaws.com/bucket/key`) when connecting to standard AWS
+ S3 endpoints. This enables HTTP/2 multiplexing and fixes TCP connection
+ exhaustion (TIME_WAIT socket accumulation) under high-concurrency workloads.
+
+ A new `addressing-style` store option controls this behavior:
+
+ - `auto` (default): virtual-hosted-style for standard AWS endpoints, path-style
+ for custom endpoints.
+ - `path`: forces path-style addressing (deprecated by AWS).
+ - `virtual`: forces virtual-hosted-style addressing (bucket names must not
+ contain dots).
+
+ Bucket names containing dots (e.g., `my.bucket.name`) automatically fall back
+ to path-style addressing in `auto` mode, because dotted names create
+ multi-level subdomains that break TLS wildcard certificate validation.
+
+ Example using path-style for backwards compatibility:
+
+ ```
+ s3://my-bucket/key?region=us-east-1&addressing-style=path
+ ```
+
+ Additionally, TCP keep-alive is now enabled on all HTTP connections, preventing
+ idle connections from being silently dropped by intermediate network devices
+ (NATs, firewalls, load balancers).
+
diff --git a/doc/manual/source/store/store-path.md b/doc/manual/source/store/store-path.md
index 4061f3653f68..08b024e4a846 100644
--- a/doc/manual/source/store/store-path.md
+++ b/doc/manual/source/store/store-path.md
@@ -2,7 +2,7 @@
> **Example**
>
-> `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
+> `/nix/store/jf6gn2dzna4nmsfbdxsd7kwhsk6gnnlr-git-2.38.1`
>
> A rendered store path
@@ -22,7 +22,7 @@ Store paths are pairs of
> **Example**
>
-> - Digest: `b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z`
+> - Digest: `q06x3jll2yfzckz2bzqak089p43ixkkq`
> - Name: `firefox-33.1`
To make store objects accessible to operating system processes, stores have to expose store objects through the file system.
@@ -38,7 +38,7 @@ A store path is rendered to a file system path as the concatenation of
> **Example**
>
> ```
-> /nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1
+> /nix/store/q06x3jll2yfzckz2bzqak089p43ixkkq-firefox-33.1
> |--------| |------------------------------| |----------|
> store directory digest name
> ```
diff --git a/doc/manual/source/store/types/index.md.in b/doc/manual/source/store/types/index.md.in
index a35161ce8fa4..b211ac98fe3a 100644
--- a/doc/manual/source/store/types/index.md.in
+++ b/doc/manual/source/store/types/index.md.in
@@ -8,7 +8,7 @@ Stores are specified using a URL-like syntax. For example, the command
```console
# nix path-info --store https://cache.nixos.org/ --json \
- /nix/store/a7gvj343m05j2s32xcnwr35v31ynlypr-coreutils-9.1
+ /nix/store/1542dip9i7k4f24y6hqgd04hmvid9hr5-coreutils-9.1
```
fetches information about a store path in the HTTP binary cache
diff --git a/docker.nix b/docker.nix
index 32205224b734..72c13663488d 100644
--- a/docker.nix
+++ b/docker.nix
@@ -8,6 +8,7 @@
# Image configuration
name ? "nix",
tag ? "latest",
+ fromImage ? null,
bundleNixpkgs ? true,
channelName ? "nixpkgs",
channelURL ? "https://channels.nixos.org/nixpkgs-unstable",
@@ -27,6 +28,8 @@
"org.opencontainers.image.description" = "Nix container image";
},
Cmd ? [ (lib.getExe bashInteractive) ],
+ extraPrePaths ? [ ],
+ extraPostPaths ? [ ],
# Default Packages
nix ? pkgs.nix,
bashInteractive ? pkgs.bashInteractive,
@@ -336,7 +339,7 @@ let
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
mkdir -p $out/nix/var/nix/gcroots/auto
- rootName=$(${lib.getExe' nix "nix"} --extra-experimental-features nix-command hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
+ rootName=$(${lib.getExe' nix "nix"} hash file --type sha1 --base32 <(echo -n $globalFlakeRegistryPath))
ln -s $globalFlakeRegistryPath $out/nix/var/nix/gcroots/auto/$rootName
'')
);
@@ -352,6 +355,7 @@ dockerTools.buildLayeredImageWithNixDb {
gid
uname
gname
+ fromImage
;
contents = [ baseSystem ];
@@ -373,11 +377,15 @@ dockerTools.buildLayeredImageWithNixDb {
Env = [
"USER=${uname}"
"PATH=${
- lib.concatStringsSep ":" [
- "${userHome}/.nix-profile/bin"
- "/nix/var/nix/profiles/default/bin"
- "/nix/var/nix/profiles/default/sbin"
- ]
+ lib.concatStringsSep ":" (
+ extraPrePaths
+ ++ [
+ "${userHome}/.nix-profile/bin"
+ "/nix/var/nix/profiles/default/bin"
+ "/nix/var/nix/profiles/default/sbin"
+ ]
+ ++ extraPostPaths
+ )
}"
"MANPATH=${
lib.concatStringsSep ":" [
diff --git a/flake.lock b/flake.lock
index 19f7b0c1c21f..f56706ec761e 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
- "lastModified": 1733328505,
- "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
- "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@@ -23,55 +23,51 @@
]
},
"locked": {
- "lastModified": 1733312601,
- "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
- "owner": "hercules-ci",
- "repo": "flake-parts",
- "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
- "type": "github"
+ "lastModified": 1748821116,
+ "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=",
+ "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1",
+ "revCount": 377,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/hercules-ci/flake-parts/0.1.377%2Brev-49f0870db23e8c1ca0b5259734a02cd9e1e371a1/01972f28-554a-73f8-91f4-d488cc502f08/source.tar.gz"
},
"original": {
- "owner": "hercules-ci",
- "repo": "flake-parts",
- "type": "github"
+ "type": "tarball",
+ "url": "https://flakehub.com/f/hercules-ci/flake-parts/0.1"
}
},
"git-hooks-nix": {
"inputs": {
- "flake-compat": [],
+ "flake-compat": "flake-compat",
"gitignore": [],
"nixpkgs": [
"nixpkgs"
- ],
- "nixpkgs-stable": [
- "nixpkgs"
]
},
"locked": {
- "lastModified": 1734279981,
- "narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
- "owner": "cachix",
- "repo": "git-hooks.nix",
- "rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
- "type": "github"
+ "lastModified": 1747372754,
+ "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
+ "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
+ "revCount": 1026,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/cachix/git-hooks.nix/0.1.1026%2Brev-80479b6ec16fefd9c1db3ea13aeb038c60530f46/0196d79a-1b35-7b8e-a021-c894fb62163d/source.tar.gz"
},
"original": {
- "owner": "cachix",
- "repo": "git-hooks.nix",
- "type": "github"
+ "type": "tarball",
+ "url": "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941"
}
},
"nixpkgs": {
"locked": {
- "lastModified": 1763948260,
- "narHash": "sha256-zZk7fn2ARAqmLwaYTpxBJmj81KIdz11NiWt7ydHHD/M=",
- "rev": "1c8ba8d3f7634acac4a2094eef7c32ad9106532c",
+ "lastModified": 1761597516,
+ "narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=",
+ "rev": "daf6dc47aa4b44791372d6139ab7b25269184d55",
+ "revCount": 811874,
"type": "tarball",
- "url": "https://releases.nixos.org/nixos/25.05/nixos-25.05.813095.1c8ba8d3f763/nixexprs.tar.xz"
+ "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2505.811874%2Brev-daf6dc47aa4b44791372d6139ab7b25269184d55/019a3494-3498-707e-9086-1fb81badc7fe/source.tar.gz"
},
"original": {
"type": "tarball",
- "url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"
+ "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2505"
}
},
"nixpkgs-23-11": {
@@ -108,7 +104,6 @@
},
"root": {
"inputs": {
- "flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"git-hooks-nix": "git-hooks-nix",
"nixpkgs": "nixpkgs",
diff --git a/flake.nix b/flake.nix
index d35363ab2e53..b32a95b06a23 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,24 +1,18 @@
{
description = "The purely functional package manager";
- inputs.nixpkgs.url = "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz";
+ inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.2505";
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
- inputs.flake-compat = {
- url = "github:edolstra/flake-compat";
- flake = false;
- };
# dev tooling
- inputs.flake-parts.url = "github:hercules-ci/flake-parts";
- inputs.git-hooks-nix.url = "github:cachix/git-hooks.nix";
+ inputs.flake-parts.url = "https://flakehub.com/f/hercules-ci/flake-parts/0.1";
+ inputs.git-hooks-nix.url = "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941";
# work around https://github.com/NixOS/nix/issues/7730
inputs.flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
inputs.git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs";
- inputs.git-hooks-nix.inputs.nixpkgs-stable.follows = "nixpkgs";
# work around 7730 and https://github.com/NixOS/nix/issues/7807
- inputs.git-hooks-nix.inputs.flake-compat.follows = "";
inputs.git-hooks-nix.inputs.gitignore.follows = "";
outputs =
@@ -34,26 +28,24 @@
officialRelease = true;
- linux32BitSystems = [ "i686-linux" ];
+ linux32BitSystems = [ ];
linux64BitSystems = [
"x86_64-linux"
"aarch64-linux"
];
linuxSystems = linux32BitSystems ++ linux64BitSystems;
darwinSystems = [
- "x86_64-darwin"
"aarch64-darwin"
];
systems = linuxSystems ++ darwinSystems;
crossSystems = [
- "armv6l-unknown-linux-gnueabihf"
- "armv7l-unknown-linux-gnueabihf"
- "riscv64-unknown-linux-gnu"
+ #"armv6l-unknown-linux-gnueabihf"
+ #"armv7l-unknown-linux-gnueabihf"
+ #"riscv64-unknown-linux-gnu"
# Disabled because of https://github.com/NixOS/nixpkgs/issues/344423
# "x86_64-unknown-netbsd"
- "x86_64-unknown-freebsd"
- "x86_64-w64-mingw32"
+ #"x86_64-unknown-freebsd"
];
stdenvs = [
@@ -372,6 +364,40 @@
nix-manual-manpages-only = nixpkgsFor.${system}.native.nixComponents2.nix-manual-manpages-only;
nix-internal-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-internal-api-docs;
nix-external-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-external-api-docs;
+
+ fallbackPathsNix =
+ let
+ pkgs = nixpkgsFor.${system}.native;
+
+ closures = forAllSystems (system: self.packages.${system}.default.outPath);
+
+ closures_json =
+ pkgs.runCommand "versions.json"
+ {
+ buildInputs = [ pkgs.jq ];
+ passAsFile = [ "json" ];
+ json = builtins.toJSON closures;
+ }
+ ''
+ cat "$jsonPath" | jq . > $out
+ '';
+
+ closures_nix =
+ pkgs.runCommand "versions.nix"
+ {
+ buildInputs = [ pkgs.jq ];
+ passAsFile = [ "template" ];
+ jsonPath = closures_json;
+ template = ''
+ builtins.fromJSON('''@closures@''')
+ '';
+ }
+ ''
+ export closures=$(cat "$jsonPath");
+ substituteAll "$templatePath" "$out"
+ '';
+ in
+ closures_nix;
}
# We need to flatten recursive attribute sets of derivations to pass `flake check`.
//
@@ -434,8 +460,6 @@
{
# These attributes go right into `packages.`.
"${pkgName}" = nixpkgsFor.${system}.native.nixComponents2.${pkgName};
- "${pkgName}-static" = nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName};
- "${pkgName}-llvm" = nixpkgsFor.${system}.native.pkgsLLVM.nixComponents2.${pkgName};
}
// lib.optionalAttrs supportsCross (
flatMapAttrs (lib.genAttrs crossSystems (_: { })) (
@@ -446,6 +470,9 @@
"${pkgName}-${crossSystem}" = nixpkgsFor.${system}.cross.${crossSystem}.nixComponents2.${pkgName};
}
)
+ // {
+ "${pkgName}-static" = nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName};
+ }
)
// flatMapAttrs (lib.genAttrs stdenvs (_: { })) (
stdenvName:
@@ -455,6 +482,10 @@
"${pkgName}-${stdenvName}" =
nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.nixComponents2.${pkgName};
}
+ // lib.optionalAttrs supportsCross {
+ "${pkgName}-${stdenvName}-static" =
+ nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.pkgsStatic.nixComponents2.${pkgName};
+ }
)
)
// lib.optionalAttrs (builtins.elem system linux64BitSystems) {
@@ -512,32 +543,6 @@
}
)
)
- // lib.optionalAttrs (!nixpkgsFor.${system}.native.stdenv.isDarwin) (
- prefixAttrs "static" (
- forAllStdenvs (
- stdenvName:
- makeShell {
- pkgs = nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.pkgsStatic;
- }
- )
- )
- // prefixAttrs "llvm" (
- forAllStdenvs (
- stdenvName:
- makeShell {
- pkgs = nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.pkgsLLVM;
- }
- )
- )
- // prefixAttrs "cross" (
- forAllCrossSystems (
- crossSystem:
- makeShell {
- pkgs = nixpkgsFor.${system}.cross.${crossSystem};
- }
- )
- )
- )
// {
native = self.devShells.${system}.native-stdenv;
default = self.devShells.${system}.native;
diff --git a/maintainers/flake-module.nix b/maintainers/flake-module.nix
index 414e6c570ab4..7f7447b19e49 100644
--- a/maintainers/flake-module.nix
+++ b/maintainers/flake-module.nix
@@ -102,6 +102,7 @@
# Don't format vendored code
''^doc/manual/redirects\.js$''
''^doc/manual/theme/highlight\.js$''
+ ''^src/libfetchers/builtin-flake-registry\.json$''
];
};
shellcheck = {
diff --git a/maintainers/invalidate-store-paths.sh b/maintainers/invalidate-store-paths.sh
new file mode 100755
index 000000000000..a075e2621834
--- /dev/null
+++ b/maintainers/invalidate-store-paths.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+set -euo pipefail
+set -x
+
+git ls-files -z \
+ | xargs -0 grep -o '[0123456789abcdfghijklmnpqrsvwxyz]\{32\}' 2> /dev/null \
+ | rev \
+ | cut -d: -f1 \
+ | rev \
+ | sort \
+ | uniq \
+ | while read -r oldhash; do
+ if ! curl --fail -I "https://cache.nixos.org/$oldhash.narinfo" > /dev/null 2>&1; then
+ continue
+ fi
+
+ newhash=$(
+ nix eval --expr "builtins.toFile \"006c6ssvddri1sg34wnw65mzd05pcp3qliylxlhv49binldajba5\" \"$oldhash\"" \
+ | cut -d- -f1 \
+ | cut -d/ -f4
+ )
+
+ msg=$(printf "bad: %s -> %s" "$oldhash" "$newhash")
+ echo "$msg"
+ git ls-files -z \
+ | xargs -0 grep -a -l "$oldhash" 2> /dev/null \
+ | while read -r file; do
+ [ -L "$file" ] && continue
+ perl -pi -e "s/$oldhash/$newhash/g" "$file" || true
+ done || true
+ git commit -am "$msg"
+ done
diff --git a/maintainers/link-headers b/maintainers/link-headers
new file mode 100755
index 000000000000..2457a2dc8295
--- /dev/null
+++ b/maintainers/link-headers
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+
+# This script must be run from the root of the Nix repository.
+#
+# For include path hygiene, we need to put headers in a separate
+# directory than sources. But during development, it is nice to paths
+# that are similar for headers and source files, e.g.
+# `foo/bar/baz.{cc,hh}`, e.g. for less typing when opening one file, and
+# then opening the other file.
+#
+# This script symlinks the headers next to the source files to
+# facilitate such a development workflows. It also updates
+# `.git/info/exclude` so that the symlinks are not accidentally committed
+# by mistake.
+
+from pathlib import Path
+import subprocess
+import os
+
+
+def main() -> None:
+ # Path to the source directory
+ GIT_TOPLEVEL = Path(
+ subprocess.run(
+ ["git", "rev-parse", "--show-toplevel"],
+ text=True,
+ stdout=subprocess.PIPE,
+ check=True,
+ ).stdout.strip()
+ )
+
+ # Get header files from git
+ result = subprocess.run(
+ ["git", "-C", str(GIT_TOPLEVEL), "ls-files", "*/include/nix/**.hh"],
+ text=True,
+ stdout=subprocess.PIPE,
+ check=True,
+ )
+ header_files = result.stdout.strip().split("\n")
+ header_files.sort()
+
+ links = []
+ for file_str in header_files:
+ project_str, header_str = file_str.split("/include/nix/", 1)
+ project = Path(project_str)
+ header = Path(header_str)
+
+ # Reconstruct the full path (relative to SRC_DIR) to the header file.
+ file = project / "include" / "nix" / header
+
+ # The symlink should be created at "project/header", i.e. next to the project's sources.
+ link = project / header
+
+ # Compute a relative path from the symlink's parent directory to the actual header file.
+ relative_source = os.path.relpath(
+ GIT_TOPLEVEL / file, GIT_TOPLEVEL / link.parent
+ )
+
+ # Create the symbolic link.
+ full_link_path = GIT_TOPLEVEL / link
+ full_link_path.parent.mkdir(parents=True, exist_ok=True)
+ if full_link_path.is_symlink():
+ full_link_path.unlink()
+ full_link_path.symlink_to(relative_source)
+ links.append(link)
+
+ # Generate .gitignore file
+ gitignore_path = GIT_TOPLEVEL / ".git" / "info" / "exclude"
+ gitignore_path.parent.mkdir(parents=True, exist_ok=True)
+ with gitignore_path.open("w") as gitignore:
+ gitignore.write("# DO NOT EDIT! Autogenerated\n")
+ gitignore.write(
+ "# Symlinks for headers to be next to sources for development\n"
+ )
+ gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')
+ gitignore.write('# Run "maintainers/link-headers" to regenerate\n\n')
+
+ for link in links:
+ gitignore.write(f"/{link}\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/maintainers/upload-debug-info-to-sentry.py b/maintainers/upload-debug-info-to-sentry.py
new file mode 100755
index 000000000000..e1c242fd2fee
--- /dev/null
+++ b/maintainers/upload-debug-info-to-sentry.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env nix
+#!nix shell --inputs-from . nixpkgs#sentry-cli --command python3
+
+import argparse
+import json
+import os
+import platform
+import re
+import subprocess
+import sys
+import urllib.error
+import urllib.parse
+import urllib.request
+
+NAR_DIR = "/tmp/nars"
+DEBUG_INFO_DIR = "/tmp/debug-info"
+
+
+def get_dynamic_libraries(executable: str) -> list[str]:
+ if platform.system() == "Darwin":
+ result = subprocess.run(["otool", "-L", executable], capture_output=True, text=True, check=True)
+ libs = []
+ for line in result.stdout.splitlines()[1:]: # skip first line (the binary path itself)
+ # otool -L output lines look like:
+ # /nix/store/.../libfoo.dylib (compatibility version X.Y.Z, current version A.B.C)
+ m = re.match(r"\s+(\S+)\s+\(", line)
+ if m:
+ libs.append(m.group(1))
+ return libs
+ else:
+ result = subprocess.run(["ldd", executable], capture_output=True, text=True, check=True)
+ libs = []
+ for line in result.stdout.splitlines():
+ # ldd output lines look like:
+ # libfoo.so.1 => /nix/store/.../libfoo.so.1 (0x...)
+ # /lib64/ld-linux-x86-64.so.2 (0x...)
+ m = re.search(r"=> (/\S+)", line)
+ if m:
+ libs.append(m.group(1))
+ elif line.strip().startswith("/"):
+ path = line.strip().split()[0]
+ libs.append(path)
+ return libs
+
+
+def get_build_id(path: str) -> str | None:
+ result = subprocess.run(["readelf", "-n", path], capture_output=True, text=True)
+ m = re.search(r"Build ID:\s+([0-9a-f]+)", result.stdout)
+ return m.group(1) if m else None
+
+
+def download_nar(build_id: str, archive: str) -> str:
+ """Download a NAR to /tmp/nars and return the local path. Skips if already present."""
+ base_url = f"https://cache.nixos.org/debuginfo/{build_id}"
+ nar_url = urllib.parse.urljoin(base_url, archive)
+ filename = nar_url.split("/")[-1]
+ local_path = os.path.join(NAR_DIR, filename)
+ if not os.path.exists(local_path):
+ os.makedirs(NAR_DIR, exist_ok=True)
+ print(f" downloading {nar_url} ...", file=sys.stderr)
+ urllib.request.urlretrieve(nar_url, local_path)
+ else:
+ print(f" already have {filename}", file=sys.stderr)
+ return local_path
+
+
+def extract_debug_symbols(nar_path: str, member: str, build_id: str) -> str:
+ """Extract a member from a .nar.xz into /tmp/debug-info/.debug. Returns the output path."""
+ out_path = os.path.join(DEBUG_INFO_DIR, f"{build_id}.debug")
+ if os.path.exists(out_path):
+ print(f" already extracted {out_path}", file=sys.stderr)
+ return out_path
+ os.makedirs(DEBUG_INFO_DIR, exist_ok=True)
+ print(f" extracting {member} -> {out_path} ...", file=sys.stderr)
+ xz = subprocess.Popen(["xz", "-d"], stdin=open(nar_path, "rb"), stdout=subprocess.PIPE)
+ nar_cat = subprocess.run(
+ ["nix", "nar", "cat", "/dev/stdin", member],
+ stdin=xz.stdout,
+ capture_output=True,
+ check=True,
+ )
+ xz.wait()
+ with open(out_path, "wb") as f:
+ f.write(nar_cat.stdout)
+ return out_path
+
+
+def find_debug_file_in_dirs(build_id: str, debug_dirs: list[str]) -> str | None:
+ """Look for a .debug file by build ID under /lib/debug/.build-id/NN/NNN.debug."""
+ subpath = os.path.join("lib", "debug", ".build-id", build_id[:2], build_id[2:] + ".debug")
+ for d in debug_dirs:
+ candidate = os.path.join(d, subpath)
+ if os.path.exists(candidate):
+ return candidate
+ return None
+
+
+def fetch_debuginfo(build_id: str) -> dict | None:
+ url = f"https://cache.nixos.org/debuginfo/{build_id}"
+ try:
+ with urllib.request.urlopen(url) as resp:
+ return json.loads(resp.read())
+ except urllib.error.HTTPError as e:
+ if e.code == 404:
+ return None
+ raise
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Upload debug symbols to Sentry."
+ )
+ parser.add_argument("executable", help="Path to the executable (e.g. ./result/bin/nix)")
+ parser.add_argument("--project", help="Sentry project ID")
+ parser.add_argument("--debug-dir", action="append", default=[], metavar="DIR",
+ help="Directory to search for debug files (may be repeated, Linux only)")
+ args = parser.parse_args()
+
+ libs = [args.executable] + get_dynamic_libraries(args.executable)
+
+ if platform.system() == "Darwin":
+ # On macOS there are no separate debug info files; upload the binaries directly.
+ print("Files to upload:", file=sys.stderr)
+ for lib in libs:
+ print(f" {lib}", file=sys.stderr)
+ files_to_upload = libs
+ else:
+ debug_files = []
+ print("ELF files to process:", file=sys.stderr)
+ for lib in libs:
+ build_id = get_build_id(lib)
+ if build_id is None:
+ print(f" {lib} (no build ID)", file=sys.stderr)
+ continue
+
+ local = find_debug_file_in_dirs(build_id, args.debug_dir)
+ if local:
+ print(f" {lib} ({build_id}): found locally at {local}", file=sys.stderr)
+ debug_files.append(local)
+ continue
+
+ debuginfo = fetch_debuginfo(build_id)
+ if debuginfo is None:
+ print(f" {lib} ({build_id}, no debug info in cache)", file=sys.stderr)
+ continue
+ print(f" {lib} ({build_id}): member={debuginfo['member']}", file=sys.stderr)
+ nar_path = download_nar(build_id, debuginfo["archive"])
+ debug_file = extract_debug_symbols(nar_path, debuginfo["member"], build_id)
+ debug_files.append(debug_file)
+ files_to_upload = debug_files
+
+ if files_to_upload:
+ print(f"Uploading {len(files_to_upload)} file(s) to Sentry...", file=sys.stderr)
+ cmd = ["sentry-cli", "debug-files", "upload"]
+ if args.project:
+ cmd += ["--project", args.project]
+ subprocess.run(cmd + files_to_upload, check=True)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/misc/systemd/nix-daemon.service.in b/misc/systemd/nix-daemon.service.in
index b3055cfe2929..531498fa6c8d 100644
--- a/misc/systemd/nix-daemon.service.in
+++ b/misc/systemd/nix-daemon.service.in
@@ -11,7 +11,7 @@ ExecStart=@@bindir@/nix-daemon nix-daemon --daemon
KillMode=process
LimitNOFILE=1048576
TasksMax=1048576
-Delegate=yes
+Delegate=
[Install]
WantedBy=multi-user.target
diff --git a/nix-meson-build-support/common/cxa-throw/interpose-cxa-throw.cc b/nix-meson-build-support/common/cxa-throw/interpose-cxa-throw.cc
new file mode 100644
index 000000000000..7238800b1906
--- /dev/null
+++ b/nix-meson-build-support/common/cxa-throw/interpose-cxa-throw.cc
@@ -0,0 +1,21 @@
+#include
+#include
+#include
+
+#include "is-logic-error.hh"
+
+typedef void (*cxa_throw_type)(void *, std::type_info *, void (*)(void *));
+
+extern "C" void __cxa_throw(void * exc, std::type_info * tinfo, void (*dest)(void *))
+{
+ if (is_logic_error(tinfo))
+ abort_on_exception(exc, tinfo);
+
+ static auto * orig = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
+ if (!orig)
+ abort();
+
+ orig(exc, tinfo, dest);
+
+ __builtin_unreachable();
+}
diff --git a/nix-meson-build-support/common/cxa-throw/is-logic-error.hh b/nix-meson-build-support/common/cxa-throw/is-logic-error.hh
new file mode 100644
index 000000000000..9e5b1d638e7a
--- /dev/null
+++ b/nix-meson-build-support/common/cxa-throw/is-logic-error.hh
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#ifndef CXA_THROW_ON_LOGIC_ERROR
+# define CXA_THROW_ON_LOGIC_ERROR() abort()
+#endif
+
+static bool is_logic_error(const std::type_info * tinfo)
+{
+ if (*tinfo == typeid(std::logic_error))
+ return true;
+
+ auto * si = dynamic_cast(tinfo);
+ if (si)
+ return is_logic_error(si->__base_type);
+
+ return false;
+}
+
+static void abort_on_exception(void * exc, const std::type_info * tinfo)
+{
+ if (!is_logic_error(tinfo))
+ return;
+
+ char buf[512];
+ snprintf(
+ buf,
+ sizeof(buf),
+ "Aborting on unexpected exception of type '%s', error: %s\n",
+ tinfo->name(),
+ ((std::exception *) exc)->what());
+ [[maybe_unused]] auto r = write(STDERR_FILENO, buf, strlen(buf));
+
+ CXA_THROW_ON_LOGIC_ERROR();
+}
diff --git a/nix-meson-build-support/common/cxa-throw/meson.build b/nix-meson-build-support/common/cxa-throw/meson.build
new file mode 100644
index 000000000000..a20438059b95
--- /dev/null
+++ b/nix-meson-build-support/common/cxa-throw/meson.build
@@ -0,0 +1,77 @@
+have_cxa_throw = false
+
+can_interpose_cxa_throw_test_code = '''
+#include
+#include
+
+#define CXA_THROW_ON_LOGIC_ERROR() _exit(0)
+#include "interpose-cxa-throw.cc"
+
+int main()
+{
+ const char * volatile p = nullptr;
+ std::string s(p);
+ return 1;
+}
+'''
+
+can_interpose_cxa_throw_result = cxx.run(
+ can_interpose_cxa_throw_test_code,
+ args : [ '-ldl' ],
+ include_directories : include_directories('.'),
+ name : 'can interpose __cxa_throw (catches libstdc++ throws)',
+)
+can_interpose_cxa_throw = can_interpose_cxa_throw_result.compiled() and can_interpose_cxa_throw_result.returncode() == 0
+
+if can_interpose_cxa_throw
+ interpose_cxa_throw_lib = static_library(
+ 'interpose-cxa-throw',
+ 'interpose-cxa-throw.cc',
+ dependencies : cxx.find_library('dl', required : false),
+ )
+
+ cxa_throw_dep = declare_dependency(
+ link_whole : interpose_cxa_throw_lib,
+ )
+
+ have_cxa_throw = true
+else
+ can_wrap_cxa_throw_test_code = '''
+ #include
+ #include
+
+ #define CXA_THROW_ON_LOGIC_ERROR() _exit(0)
+ #include "wrap-cxa-throw.cc"
+
+ int main()
+ {
+ const char * volatile p = nullptr;
+ std::string s(p);
+ return 1;
+ }
+ '''
+
+ wrap_cxa_throw_args = [ '-Wl,--wrap=__cxa_throw' ]
+
+ can_wrap_cxa_throw_result = cxx.run(
+ can_wrap_cxa_throw_test_code,
+ args : wrap_cxa_throw_args,
+ include_directories : include_directories('.'),
+ name : 'can wrap __cxa_throw (catches libstdc++ throws)',
+ )
+ can_wrap_cxa_throw = can_wrap_cxa_throw_result.compiled() and can_wrap_cxa_throw_result.returncode() == 0
+
+ if can_wrap_cxa_throw
+ wrap_cxa_throw_lib = static_library(
+ 'wrap-cxa-throw',
+ 'wrap-cxa-throw.cc',
+ )
+
+ cxa_throw_dep = declare_dependency(
+ link_whole : wrap_cxa_throw_lib,
+ link_args : wrap_cxa_throw_args + [ '-Wl,-u,__wrap___cxa_throw' ],
+ )
+
+ have_cxa_throw = true
+ endif
+endif
diff --git a/nix-meson-build-support/common/cxa-throw/wrap-cxa-throw.cc b/nix-meson-build-support/common/cxa-throw/wrap-cxa-throw.cc
new file mode 100644
index 000000000000..f9de15533de0
--- /dev/null
+++ b/nix-meson-build-support/common/cxa-throw/wrap-cxa-throw.cc
@@ -0,0 +1,16 @@
+#include
+#include
+
+#include "is-logic-error.hh"
+
+extern "C" void __real___cxa_throw(void *, std::type_info *, void (*)(void *));
+
+extern "C" void __wrap___cxa_throw(void * exc, std::type_info * tinfo, void (*dest)(void *))
+{
+ if (is_logic_error(tinfo))
+ abort_on_exception(exc, tinfo);
+
+ __real___cxa_throw(exc, tinfo, dest);
+
+ __builtin_unreachable();
+}
diff --git a/nix-meson-build-support/common/meson.build b/nix-meson-build-support/common/meson.build
index 5fcf557e70ba..6d343b68a416 100644
--- a/nix-meson-build-support/common/meson.build
+++ b/nix-meson-build-support/common/meson.build
@@ -65,5 +65,15 @@ endif
# Darwin ld doesn't like "X.Y.ZpreABCD+W"
nix_soversion = meson.project_version().split('+')[0].split('pre')[0]
+cxx = meson.get_compiler('cpp')
+
+# Clang does not support prelinking on static builds
+if cxx.get_id() == 'clang' and get_option('default_library') == 'static'
+ prelink = false
+else
+ prelink = true
+endif
+
subdir('assert-fail')
subdir('asan-options')
+subdir('cxa-throw')
diff --git a/nix-meson-build-support/default-system-cpu/meson.build b/nix-meson-build-support/default-system-cpu/meson.build
index f63b07975b6e..3e872578efca 100644
--- a/nix-meson-build-support/default-system-cpu/meson.build
+++ b/nix-meson-build-support/default-system-cpu/meson.build
@@ -14,6 +14,6 @@ if (host_machine.cpu_family() in [ 'ppc64', 'ppc' ]) and host_machine.endian() =
nix_system_cpu += 'le'
elif host_machine.cpu_family() in [ 'mips64', 'mips' ] and host_machine.endian() == 'little'
nix_system_cpu += 'el'
-elif host_machine.cpu_family() == 'arm'
+elif host_machine.cpu_family() in [ 'arm', 'arm64' ]
nix_system_cpu = host_machine.cpu()
endif
diff --git a/packaging/components.nix b/packaging/components.nix
index dbf2180e8942..6402e8b7b2f8 100644
--- a/packaging/components.nix
+++ b/packaging/components.nix
@@ -27,7 +27,7 @@ let
pkg-config
;
- baseVersion = lib.fileContents ../.version;
+ baseVersion = lib.fileContents ../.version-determinate;
versionSuffix = lib.optionalString (!officialRelease) "pre";
@@ -51,15 +51,6 @@ let
exts: userFn: stdenv.mkDerivation (lib.extends (lib.composeManyExtensions exts) userFn);
setVersionLayer = finalAttrs: prevAttrs: {
- preConfigure =
- prevAttrs.preConfigure or ""
- +
- # Update the repo-global .version file.
- # Symlink ./.version points there, but by default only workDir is writable.
- ''
- chmod u+w ./.version
- echo ${finalAttrs.version} > ./.version
- '';
};
localSourceLayer =
diff --git a/packaging/dependencies.nix b/packaging/dependencies.nix
index 7b7ee0ecf4d8..3c68ed1e749b 100644
--- a/packaging/dependencies.nix
+++ b/packaging/dependencies.nix
@@ -16,9 +16,41 @@ in
scope: {
inherit stdenv;
+ libblake3 =
+ (pkgs.libblake3.override {
+ inherit stdenv;
+ # Nixpkgs disables tbb on static
+ useTBB = !stdenv.hostPlatform.isStatic;
+ })
+ # For some reason that is not clear, it is wanting to use libgcc_eh which is not available.
+ # Force this to be built with compiler-rt & libunwind over libgcc_eh works.
+ # Issue: https://github.com/NixOS/nixpkgs/issues/177129
+ .overrideAttrs
+ (
+ attrs:
+ lib.optionalAttrs
+ (
+ stdenv.cc.isClang
+ && stdenv.hostPlatform.isStatic
+ && stdenv.cc.libcxx != null
+ && stdenv.cc.libcxx.isLLVM
+ )
+ {
+ NIX_CFLAGS_COMPILE = [
+ "-rtlib=compiler-rt"
+ "-unwindlib=libunwind"
+ ];
+
+ buildInputs = [
+ pkgs.llvmPackages.libunwind
+ ];
+ }
+ );
+
boehmgc =
(pkgs.boehmgc.override {
enableLargeConfig = true;
+ inherit stdenv;
}).overrideAttrs
(attrs: {
# Increase the initial mark stack size to avoid stack
@@ -27,20 +59,51 @@ scope: {
# small, run Nix with GC_PRINT_STATS=1 and look for messages
# such as `Mark stack overflow`, `No room to copy back mark
# stack`, and `Grew mark stack to ... frames`.
- NIX_CFLAGS_COMPILE = "-DINITIAL_MARK_STACK_SIZE=1048576";
+ NIX_CFLAGS_COMPILE = [
+ "-DINITIAL_MARK_STACK_SIZE=1048576"
+ ]
+ # For some reason that is not clear, it is wanting to use libgcc_eh which is not available.
+ # Force this to be built with compiler-rt & libunwind over libgcc_eh works.
+ # Issue: https://github.com/NixOS/nixpkgs/issues/177129
+ ++
+ lib.optionals
+ (
+ stdenv.cc.isClang
+ && stdenv.hostPlatform.isStatic
+ && stdenv.cc.libcxx != null
+ && stdenv.cc.libcxx.isLLVM
+ )
+ [
+ "-rtlib=compiler-rt"
+ "-unwindlib=libunwind"
+ ];
+
+ buildInputs =
+ (attrs.buildInputs or [ ])
+ ++ lib.optional (
+ stdenv.cc.isClang
+ && stdenv.hostPlatform.isStatic
+ && stdenv.cc.libcxx != null
+ && stdenv.cc.libcxx.isLLVM
+ ) pkgs.llvmPackages.libunwind;
});
- lowdown = pkgs.lowdown.overrideAttrs (prevAttrs: rec {
- version = "2.0.2";
- src = pkgs.fetchurl {
- url = "https://kristaps.bsd.lv/lowdown/snapshots/lowdown-${version}.tar.gz";
- hash = "sha512-cfzhuF4EnGmLJf5EGSIbWqJItY3npbRSALm+GarZ7SMU7Hr1xw0gtBFMpOdi5PBar4TgtvbnG4oRPh+COINGlA==";
- };
- nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ pkgs.buildPackages.bmake ];
- postInstall =
- lib.replaceStrings [ "lowdown.so.1" "lowdown.1.dylib" ] [ "lowdown.so.2" "lowdown.2.dylib" ]
- (prevAttrs.postInstall or "");
- });
+ lowdown =
+ if lib.versionAtLeast pkgs.lowdown.version "2.0.2" then
+ pkgs.lowdown
+ else
+ pkgs.lowdown.overrideAttrs (prevAttrs: rec {
+ version = "2.0.2";
+ src = pkgs.fetchurl {
+ url = "https://kristaps.bsd.lv/lowdown/snapshots/lowdown-${version}.tar.gz";
+ hash = "sha512-cfzhuF4EnGmLJf5EGSIbWqJItY3npbRSALm+GarZ7SMU7Hr1xw0gtBFMpOdi5PBar4TgtvbnG4oRPh+COINGlA==";
+ };
+ patches = [ ];
+ nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ pkgs.buildPackages.bmake ];
+ postInstall =
+ lib.replaceStrings [ "lowdown.so.1" "lowdown.1.dylib" ] [ "lowdown.so.2" "lowdown.2.dylib" ]
+ (prevAttrs.postInstall or "");
+ });
# TODO: Remove this when https://github.com/NixOS/nixpkgs/pull/442682 is included in a stable release
toml11 =
@@ -66,12 +129,27 @@ scope: {
"--with-coroutine"
"--with-iostreams"
"--with-url"
+ "--with-thread"
];
enableIcu = false;
+ inherit stdenv;
}).overrideAttrs
(old: {
# Need to remove `--with-*` to use `--with-libraries=...`
buildPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.buildPhase;
installPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.installPhase;
});
+
+ wasmtime = pkgs.callPackage ./wasmtime.nix { };
+
+ curl = pkgs.curl.override {
+ # libpsl uses a data file needed at runtime, not useful for nix.
+ pslSupport = !stdenv.hostPlatform.isStatic;
+ idnSupport = !stdenv.hostPlatform.isStatic;
+ };
+
+ sentry-native = (pkgs.callPackage ./sentry-native.nix { }).override {
+ # Avoid having two curls in our closure.
+ inherit (scope) curl;
+ };
}
diff --git a/packaging/dev-shell.nix b/packaging/dev-shell.nix
index eecfa2ea84c0..d13a8d0e23cb 100644
--- a/packaging/dev-shell.nix
+++ b/packaging/dev-shell.nix
@@ -215,7 +215,7 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
};
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
- version = lib.fileContents ../.version;
+ version = lib.fileContents ../.version-determinate;
name = finalAttrs.pname;
installFlags = "sysconfdir=$(out)/etc";
@@ -259,10 +259,13 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
# We use this shell with the local checkout, not unpackPhase.
src = null;
+
# Workaround https://sourceware.org/pipermail/gdb-patches/2025-October/221398.html
# Remove when gdb fix is rolled out everywhere.
separateDebugInfo = false;
+ mesonBuildType = "debugoptimized";
+
env = {
# For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
@@ -287,7 +290,8 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
)
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
- ++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
+ ++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags)
+ ++ map (transformFlag "nix") (ignoreCrossFile pkgs.nixComponents2.nix-cli.mesonFlags);
nativeBuildInputs =
let
diff --git a/packaging/everything.nix b/packaging/everything.nix
index f6bdad4907b6..1a9c948e8e2e 100644
--- a/packaging/everything.nix
+++ b/packaging/everything.nix
@@ -44,6 +44,10 @@
testers,
patchedSrc ? null,
+
+ curl,
+ boehmgc,
+ sentry-native,
}:
let
@@ -75,7 +79,7 @@ let
};
devdoc = buildEnv {
- name = "nix-${nix-cli.version}-devdoc";
+ name = "determinate-nix-${nix-cli.version}-devdoc";
paths = [
nix-internal-api-docs
nix-external-api-docs
@@ -84,7 +88,7 @@ let
in
stdenv.mkDerivation (finalAttrs: {
- pname = "nix";
+ pname = "determinate-nix";
version = nix-cli.version;
/**
@@ -102,6 +106,7 @@ stdenv.mkDerivation (finalAttrs: {
"dev"
"doc"
"man"
+ "debug"
];
/**
@@ -153,9 +158,18 @@ stdenv.mkDerivation (finalAttrs: {
installPhase =
let
devPaths = lib.mapAttrsToList (_k: lib.getDev) finalAttrs.finalPackage.libs;
+ debugPaths = lib.map (lib.getOutput "debug") (
+ lib.attrValues finalAttrs.finalPackage.libs
+ ++ [
+ nix-cli
+ curl
+ boehmgc
+ ]
+ ++ lib.optional (stdenv.hostPlatform.isLinux && !stdenv.hostPlatform.isStatic) sentry-native
+ );
in
''
- mkdir -p $out $dev/nix-support
+ mkdir -p $out $dev/nix-support $debug/lib/debug
# Custom files
echo $libs >> $dev/nix-support/propagated-build-inputs
@@ -168,6 +182,12 @@ stdenv.mkDerivation (finalAttrs: {
lndir $lib $dev
done
+ for d in ${lib.escapeShellArgs debugPaths}; do
+ if [[ -d $d/lib/debug ]]; then
+ lndir $d/lib/debug $debug/lib/debug
+ fi
+ done
+
# Forwarded outputs
ln -sT ${nix-manual} $doc
ln -sT ${nix-manual.man} $man
diff --git a/packaging/hydra.nix b/packaging/hydra.nix
index 3a31314f709e..9839dd621639 100644
--- a/packaging/hydra.nix
+++ b/packaging/hydra.nix
@@ -122,77 +122,6 @@ rec {
system: self.devShells.${system}.default.inputDerivation
)) [ "i686-linux" ];
- buildStatic = forAllPackages (
- pkgName:
- lib.genAttrs linux64BitSystems (
- system: nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName}
- )
- );
-
- buildCross = forAllPackages (
- pkgName:
- # Hack to avoid non-evaling package
- (
- if pkgName == "nix-functional-tests" then
- lib.flip builtins.removeAttrs [ "x86_64-w64-mingw32" ]
- else
- lib.id
- )
- (
- forAllCrossSystems (
- crossSystem:
- lib.genAttrs [ "x86_64-linux" ] (
- system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents2.${pkgName}
- )
- )
- )
- );
-
- # Builds with sanitizers already have GC disabled, so this buildNoGc can just
- # point to buildWithSanitizers in order to reduce the load on hydra.
- buildNoGc = buildWithSanitizers;
-
- buildWithSanitizers =
- let
- components = forAllSystems (
- system:
- let
- pkgs = nixpkgsFor.${system}.native;
- in
- pkgs.nixComponents2.overrideScope (
- self: super: {
- # Boost coroutines fail with ASAN on darwin.
- withASan = !pkgs.stdenv.buildPlatform.isDarwin;
- withUBSan = true;
- nix-expr = super.nix-expr.override { enableGC = false; };
- # Unclear how to make Perl bindings work with a dynamically linked ASAN.
- nix-perl-bindings = null;
- }
- )
- );
- in
- forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
-
- buildNoTests = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-cli);
-
- # Toggles some settings for better coverage. Windows needs these
- # library combinations, and Debian build Nix with GNU readline too.
- buildReadlineNoMarkdown =
- let
- components = forAllSystems (
- system:
- nixpkgsFor.${system}.native.nixComponents2.overrideScope (
- self: super: {
- nix-cmd = super.nix-cmd.override {
- enableMarkdown = false;
- readlineFlavor = "readline";
- };
- }
- )
- );
- in
- forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
-
# Perl bindings for various platforms.
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-perl-bindings);
@@ -203,30 +132,6 @@ rec {
system: nixpkgsFor.${system}.native.callPackage ./binary-tarball.nix { }
);
- binaryTarballCross = lib.genAttrs [ "x86_64-linux" ] (
- system:
- forAllCrossSystems (
- crossSystem: nixpkgsFor.${system}.cross.${crossSystem}.callPackage ./binary-tarball.nix { }
- )
- );
-
- # The first half of the installation script. This is uploaded
- # to https://nixos.org/nix/install. It downloads the binary
- # tarball for the user's system and calls the second half of the
- # installation script.
- installerScript = installScriptFor [
- # Native
- self.hydraJobs.binaryTarball."x86_64-linux"
- self.hydraJobs.binaryTarball."i686-linux"
- self.hydraJobs.binaryTarball."aarch64-linux"
- self.hydraJobs.binaryTarball."x86_64-darwin"
- self.hydraJobs.binaryTarball."aarch64-darwin"
- # Cross
- self.hydraJobs.binaryTarballCross."x86_64-linux"."armv6l-unknown-linux-gnueabihf"
- self.hydraJobs.binaryTarballCross."x86_64-linux"."armv7l-unknown-linux-gnueabihf"
- self.hydraJobs.binaryTarballCross."x86_64-linux"."riscv64-unknown-linux-gnu"
- ];
-
installerScriptForGHA = forAllSystems (
system:
nixpkgsFor.${system}.native.callPackage ./installer {
@@ -294,6 +199,19 @@ rec {
pkgs = nixpkgsFor.${system}.native;
}
);
+
+ nixpkgsLibTestsLazy = forAllSystems (
+ system:
+ lib.overrideDerivation
+ (import (nixpkgs + "/lib/tests/test-with-nix.nix") {
+ lib = nixpkgsFor.${system}.native.lib;
+ nix = self.packages.${system}.nix-cli;
+ pkgs = nixpkgsFor.${system}.native;
+ })
+ (_: {
+ "NIX_CONFIG" = "lazy-trees = true";
+ })
+ );
};
metrics.nixpkgs = import "${nixpkgs-regression}/pkgs/top-level/metrics.nix" {
@@ -308,17 +226,12 @@ rec {
in
pkgs.runCommand "install-tests" {
againstSelf = testNixVersions pkgs pkgs.nix;
- againstCurrentLatest =
- # FIXME: temporarily disable this on macOS because of #3605.
- if system == "x86_64-linux" then testNixVersions pkgs pkgs.nixVersions.latest else null;
+ #againstCurrentLatest =
+ # # FIXME: temporarily disable this on macOS because of #3605.
+ # if system == "x86_64-linux" then testNixVersions pkgs pkgs.nixVersions.latest else null;
# Disabled because the latest stable version doesn't handle
# `NIX_DAEMON_SOCKET_PATH` which is required for the tests to work
# againstLatestStable = testNixVersions pkgs pkgs.nixStable;
} "touch $out"
);
-
- installerTests = import ../tests/installer {
- binaryTarballs = self.hydraJobs.binaryTarball;
- inherit nixpkgsFor;
- };
}
diff --git a/packaging/installer/default.nix b/packaging/installer/default.nix
index e171f36f99f7..a8e344b496c8 100644
--- a/packaging/installer/default.nix
+++ b/packaging/installer/default.nix
@@ -32,7 +32,7 @@ runCommand "installer-script"
in
''
\
- --replace '@tarballHash_${system}@' $(nix --experimental-features nix-command hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
+ --replace '@tarballHash_${system}@' $(nix hash-file --base16 --type sha256 ${tarball}/*.tar.xz) \
--replace '@tarballPath_${system}@' $(tarballPath ${tarball}/*.tar.xz) \
''
) tarballs
diff --git a/packaging/sentry-native.nix b/packaging/sentry-native.nix
new file mode 100644
index 000000000000..06accdd5b18a
--- /dev/null
+++ b/packaging/sentry-native.nix
@@ -0,0 +1,52 @@
+{
+ lib,
+ stdenv,
+ fetchgit,
+ cmake,
+ curl,
+ pkg-config,
+ python3,
+ darwin,
+}:
+
+stdenv.mkDerivation rec {
+ pname = "sentry-native";
+ version = "0.13.5";
+
+ src = fetchgit {
+ url = "https://github.com/getsentry/sentry-native";
+ tag = version;
+ hash = "sha256-vDBI6lB1DMLleAgRCfsHvTSdtmXOzvJSaNAt+NwOd3c=";
+ fetchSubmodules = true;
+ };
+
+ dontFixCmake = true;
+
+ nativeBuildInputs = [
+ cmake
+ pkg-config
+ ]
+ ++ lib.optionals stdenv.hostPlatform.isDarwin [
+ python3
+ darwin.bootstrap_cmds
+ ];
+
+ postPatch = ''
+ # Borrowed from psutil: stick to the old SDK name for now.
+ substituteInPlace external/crashpad/util/mac/mac_util.cc \
+ --replace-fail kIOMainPortDefault kIOMasterPortDefault
+ '';
+
+ buildInputs = [
+ curl
+ ];
+
+ cmakeBuildType = "RelWithDebInfo";
+
+ cmakeFlags = [ ];
+
+ outputs = [
+ "out"
+ "dev"
+ ];
+}
diff --git a/packaging/wasmtime.nix b/packaging/wasmtime.nix
new file mode 100644
index 000000000000..3e8b71280c07
--- /dev/null
+++ b/packaging/wasmtime.nix
@@ -0,0 +1,74 @@
+# Stripped-down version of https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/wa/wasmtime/package.nix,
+# license: https://github.com/NixOS/nixpkgs/blob/master/COPYING
+{
+ lib,
+ stdenv,
+ rust_1_89,
+ fetchFromGitHub,
+ cmake,
+ enableShared ? !stdenv.hostPlatform.isStatic,
+ enableStatic ? stdenv.hostPlatform.isStatic,
+}:
+rust_1_89.packages.stable.rustPlatform.buildRustPackage (finalAttrs: {
+ pname = "wasmtime";
+ version = "40.0.2";
+
+ src = fetchFromGitHub {
+ owner = "bytecodealliance";
+ repo = "wasmtime";
+ tag = "v${finalAttrs.version}";
+ hash = "sha256-4y9WpCdyuF/Tp2k/1d5rZxwYunWNdeibEsFgHcBC52Q=";
+ fetchSubmodules = true;
+ };
+
+ # Disable cargo-auditable until https://github.com/rust-secure-code/cargo-auditable/issues/124 is solved.
+ auditable = false;
+
+ cargoHash = "sha256-aTPgnuBvOIqg1+Sa2ZLdMTLujm8dKGK5xpZ3qHpr3f8=";
+ cargoBuildFlags = [
+ "--package"
+ "wasmtime-c-api"
+ "--no-default-features"
+ "--features cranelift,wasi,pooling-allocator,wat,demangle,gc-null"
+ ];
+
+ outputs = [
+ "out"
+ "lib"
+ ];
+
+ nativeBuildInputs = [
+ cmake
+ ];
+
+ doCheck =
+ with stdenv.buildPlatform;
+ # SIMD tests are only executed on platforms that support all
+ # required processor features (e.g. SSE3, SSSE3 and SSE4.1 on x86_64):
+ # https://github.com/bytecodealliance/wasmtime/blob/v9.0.0/cranelift/codegen/src/isa/x64/mod.rs#L220
+ (isx86_64 -> sse3Support && ssse3Support && sse4_1Support)
+ &&
+ # The dependency `wasi-preview1-component-adapter` fails to build because of:
+ # error: linker `rust-lld` not found
+ !isAarch64;
+
+ postInstall =
+ let
+ inherit (stdenv.hostPlatform.rust) cargoShortTarget;
+ in
+ ''
+ moveToOutput lib $lib
+ ${lib.optionalString (!enableShared) "rm -f $lib/lib/*.so{,.*}"}
+ ${lib.optionalString (!enableStatic) "rm -f $lib/lib/*.a"}
+
+ # copy the build.rs generated c-api headers
+ # https://github.com/rust-lang/cargo/issues/9661
+ mkdir -p $out
+ cp -r target/${cargoShortTarget}/release/build/wasmtime-c-api-impl-*/out/include $out/include
+ ''
+ + lib.optionalString stdenv.hostPlatform.isDarwin ''
+ install_name_tool -id \
+ $lib/lib/libwasmtime.dylib \
+ $lib/lib/libwasmtime.dylib
+ '';
+})
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index 5ff760a6143f..683beca10fde 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -53,8 +53,8 @@ readonly PROFILE_NIX_FILE_FISH="$NIX_ROOT/var/nix/profiles/default/etc/profile.d
readonly NIX_INSTALLED_NIX="@nix@"
readonly NIX_INSTALLED_CACERT="@cacert@"
-#readonly NIX_INSTALLED_NIX="/nix/store/j8dbv5w6jl34caywh2ygdy88knx1mdf7-nix-2.3.6"
-#readonly NIX_INSTALLED_CACERT="/nix/store/7dxhzymvy330i28ii676fl1pqwcahv2f-nss-cacert-3.49.2"
+#readonly NIX_INSTALLED_NIX="/nix/store/byi37zv50wnfrpp4d81z3spswd5zva37-nix-2.3.6"
+#readonly NIX_INSTALLED_CACERT="/nix/store/7pi45g541xa8ahwgpbpy7ggsl0xj1jj6-nss-cacert-3.49.2"
EXTRACTED_NIX_PATH="$(dirname "$0")"
readonly EXTRACTED_NIX_PATH
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index 918f4bbd9e9e..000000000000
--- a/shell.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-(import (fetchTarball "https://github.com/edolstra/flake-compat/archive/master.tar.gz") {
- src = ./.;
-}).shellNix
diff --git a/src/external-api-docs/package.nix b/src/external-api-docs/package.nix
index b194e16d4608..28cde8c09e69 100644
--- a/src/external-api-docs/package.nix
+++ b/src/external-api-docs/package.nix
@@ -14,7 +14,7 @@ let
in
mkMesonDerivation (finalAttrs: {
- pname = "nix-external-api-docs";
+ pname = "determinate-nix-external-api-docs";
inherit version;
workDir = ./.;
diff --git a/src/internal-api-docs/package.nix b/src/internal-api-docs/package.nix
index 6c4f354aee5c..636c19653eab 100644
--- a/src/internal-api-docs/package.nix
+++ b/src/internal-api-docs/package.nix
@@ -14,7 +14,7 @@ let
in
mkMesonDerivation (finalAttrs: {
- pname = "nix-internal-api-docs";
+ pname = "determinate-nix-internal-api-docs";
inherit version;
workDir = ./.;
diff --git a/src/libcmd/built-path.cc b/src/libcmd/built-path.cc
index fc7f1849384c..fccd3997e16b 100644
--- a/src/libcmd/built-path.cc
+++ b/src/libcmd/built-path.cc
@@ -119,9 +119,10 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
outputName);
DrvOutput key{*drvOutput, outputName};
auto thisRealisation = store.queryRealisation(key);
- assert(thisRealisation); // We’ve built it, so we must
- // have the realisation
- res.insert(Realisation{*thisRealisation, std::move(key)});
+ if (thisRealisation)
+ res.insert(Realisation{*thisRealisation, std::move(key)});
+ else
+ res.insert(outputPath);
} else {
res.insert(outputPath);
}
diff --git a/src/libcmd/builtin-flake-schemas.nix b/src/libcmd/builtin-flake-schemas.nix
new file mode 100644
index 000000000000..39f09d92fa29
--- /dev/null
+++ b/src/libcmd/builtin-flake-schemas.nix
@@ -0,0 +1,488 @@
+{
+ description = "Schemas for well-known Nix flake output types";
+
+ outputs =
+ { self }:
+ let
+ mapAttrsToList = f: attrs: map (name: f name attrs.${name}) (builtins.attrNames attrs);
+
+ checkModule =
+ module_:
+ let
+ module = if builtins.isPath module_ then import module_ else module_;
+ in
+ builtins.isAttrs module || builtins.isFunction module;
+
+ mkApp = system: app: {
+ forSystems = [ system ];
+ evalChecks.isValidApp =
+ app ? type
+ && app.type == "app"
+ && app ? program
+ && builtins.isString app.program
+ &&
+ builtins.removeAttrs app [
+ "type"
+ "program"
+ "meta"
+ ] == { };
+ what = "app";
+ shortDescription = app.meta.description or "";
+ };
+
+ mkPackage = isFlakeCheck: what: system: package: {
+ forSystems = [ system ];
+ shortDescription = package.meta.description or "";
+ derivationAttrPath = [ ];
+ inherit what isFlakeCheck;
+ };
+
+ singleDerivationInventory =
+ what: isFlakeCheck: output:
+ self.lib.mkChildren (builtins.mapAttrs (mkPackage isFlakeCheck what) output);
+
+ schemasSchema = {
+ version = 1;
+ doc = ''
+ The `schemas` flake output is used to define and document flake outputs.
+ For the expected format, consult the Nix manual.
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (schemaName: schemaDef: {
+ shortDescription = "A schema checker for the `${schemaName}` flake output";
+ evalChecks.isValidSchema =
+ schemaDef.version or 0 == 1
+ && schemaDef ? doc
+ && builtins.isString (schemaDef.doc)
+ && schemaDef ? inventory
+ && builtins.isFunction (schemaDef.inventory);
+ what = "flake schema";
+ }) output
+ );
+ };
+
+ appsSchema = {
+ version = 1;
+ doc = ''
+ The `apps` output provides commands available via `nix run`.
+ '';
+ roles.nix-run = { };
+ appendSystem = true;
+ defaultAttrPath = [ "default" ];
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (system: apps: {
+ forSystems = [ system ];
+ children = builtins.mapAttrs (appName: app: mkApp system app) apps;
+ }) output
+ );
+ };
+
+ defaultAppSchema = {
+ version = 1;
+ doc = ''
+ **DEPRECATED**. Use `apps..default` instead.
+ '';
+ roles.nix-run = { };
+ appendSystem = true;
+ defaultAttrPath = [ ];
+ inventory = output: self.lib.mkChildren (builtins.mapAttrs mkApp output);
+ };
+
+ packagesSchema = {
+ version = 1;
+ doc = ''
+ The `packages` flake output contains packages that can be added to a shell using `nix shell`.
+ '';
+ roles.nix-build = { };
+ roles.nix-run = { };
+ roles.nix-develop = { };
+ roles.nix-search = { };
+ appendSystem = true;
+ defaultAttrPath = [ "default" ];
+ inventory = self.lib.derivationsInventory "package" false;
+ };
+
+ defaultPackageSchema = {
+ version = 1;
+ doc = ''
+ **DEPRECATED**. Use `packages..default` instead.
+ '';
+ roles.nix-build = { };
+ roles.nix-run = { };
+ roles.nix-develop = { };
+ roles.nix-search = { };
+ appendSystem = true;
+ defaultAttrPath = [ ];
+ inventory = singleDerivationInventory "package" false;
+ };
+
+ ociImagesSchema = {
+ version = 1;
+ doc = ''
+ The `ociImages` flake output contains derivations that build valid Open Container Initiative images.
+ '';
+ inventory = self.lib.derivationsInventory "OCI image" false;
+ };
+
+ legacyPackagesSchema = {
+ version = 1;
+ doc = ''
+ The `legacyPackages` flake output is similar to `packages` but different in that it can be nested and thus contain attribute sets that contain more packages.
+ Since enumerating packages in nested attribute sets can be inefficient, you should favor `packages` over `legacyPackages`.
+ '';
+ roles.nix-build = { };
+ roles.nix-run = { };
+ roles.nix-search = { };
+ roles.nix-develop = { };
+ appendSystem = true;
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (systemType: packagesForSystem: {
+ forSystems = [ systemType ];
+ isLegacy = true;
+ children =
+ let
+ recurse =
+ prefix: attrs:
+ builtins.mapAttrs (
+ attrName: attrs:
+ # Necessary to deal with `AAAAAASomeThingsFailToEvaluate` etc. in Nixpkgs.
+ self.lib.try (
+ if attrs.type or null == "derivation" then
+ {
+ forSystems = [ attrs.system ];
+ shortDescription = attrs.meta.description or "";
+ derivationAttrPath = [ ];
+ what = "package";
+ }
+ else
+ # Recurse at the first and second levels, or if the
+ # recurseForDerivations attribute if set.
+ if attrs.recurseForDerivations or false then
+ {
+ children = recurse (prefix + attrName + ".") attrs;
+ }
+ else
+ {
+ what = "unknown";
+ }
+ ) (throw "failed")
+ ) attrs;
+ in
+ # The top-level cannot be a derivation.
+ assert packagesForSystem.type or null != "derivation";
+ recurse (systemType + ".") packagesForSystem;
+ }) output
+ );
+ };
+
+ checksSchema = {
+ version = 1;
+ doc = ''
+ The `checks` flake output contains derivations that will be built by `nix flake check`.
+ '';
+ # FIXME: add role
+ inventory = self.lib.derivationsInventory "CI test" true;
+ };
+
+ devShellsSchema = {
+ version = 1;
+ doc = ''
+ The `devShells` flake output contains derivations that provide a development environment for `nix develop`.
+ '';
+ roles.nix-develop = { };
+ appendSystem = true;
+ defaultAttrPath = [ "default" ];
+ inventory = self.lib.derivationsInventory "development environment" false;
+ };
+
+ devShellSchema = {
+ version = 1;
+ doc = ''
+ **DEPRECATED**. Use `devShells..default` instead.
+ '';
+ roles.nix-develop = { };
+ appendSystem = true;
+ defaultAttrPath = [ ];
+ inventory = singleDerivationInventory "development environment" false;
+ };
+
+ formatterSchema = {
+ version = 1;
+ doc = ''
+ The `formatter` output specifies the package to use to format the project.
+ '';
+ roles.nix-fmt = { };
+ appendSystem = true;
+ defaultAttrPath = [ ];
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (system: formatter: {
+ forSystems = [ system ];
+ shortDescription = formatter.meta.description or "";
+ derivationAttrPath = [ ];
+ what = "formatter";
+ isFlakeCheck = false;
+ }) output
+ );
+ };
+
+ templatesSchema = {
+ version = 1;
+ doc = ''
+ The `templates` output provides project templates.
+ '';
+ roles.nix-template = { };
+ defaultAttrPath = [ "default" ];
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (templateName: template: {
+ shortDescription = template.description or "";
+ evalChecks.isValidTemplate =
+ template ? path
+ && builtins.isPath template.path
+ && template ? description
+ && builtins.isString template.description;
+ what = "template";
+ }) output
+ );
+ };
+
+ hydraJobsSchema = {
+ version = 1;
+ doc = ''
+ The `hydraJobs` flake output defines derivations to be built by the Hydra continuous integration system.
+ '';
+ allowIFD = false;
+ inventory =
+ output:
+ let
+ recurse =
+ prefix: attrs:
+ self.lib.mkChildren (
+ builtins.mapAttrs (
+ attrName: attrs:
+ if attrs.type or null == "derivation" then
+ {
+ forSystems = [ attrs.system ];
+ shortDescription = attrs.meta.description or "";
+ derivationAttrPath = [ ];
+ what = "Hydra CI test";
+ }
+ else
+ recurse (prefix + attrName + ".") attrs
+ ) attrs
+ );
+ in
+ # The top-level cannot be a derivation.
+ assert output.type or null != "derivation";
+ recurse "" output;
+ };
+
+ overlaysSchema = {
+ version = 1;
+ doc = ''
+ The `overlays` flake output defines ["overlays"](https://nixos.org/manual/nixpkgs/stable/#chap-overlays) that can be plugged into Nixpkgs.
+ Overlays add additional packages or modify or replace existing packages.
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (overlayName: overlay: {
+ what = "Nixpkgs overlay";
+ evalChecks.isOverlay =
+ # FIXME: should try to apply the overlay to an actual
+ # Nixpkgs. But we don't have access to a nixpkgs
+ # flake here. Maybe this schema should be moved to the
+ # nixpkgs flake, where it does have access.
+ if !builtins.isFunction overlay then
+ throw "Overlay is not a function. It should be structured like: `final: previous: { /* ... */ }`."
+ else
+ true;
+ }) output
+ );
+ };
+
+ nixosConfigurationsSchema = {
+ version = 1;
+ doc = ''
+ The `nixosConfigurations` flake output defines [NixOS system configurations](https://nixos.org/manual/nixos/stable/#ch-configuration).
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (configName: machine: {
+ what = "NixOS configuration";
+ derivationAttrPath = [
+ "config"
+ "system"
+ "build"
+ "toplevel"
+ ];
+ forSystems = [ machine.pkgs.stdenv.system ];
+ }) output
+ );
+ };
+
+ nixosModulesSchema = {
+ version = 1;
+ doc = ''
+ The `nixosModules` flake output defines importable [NixOS modules](https://nixos.org/manual/nixos/stable/#sec-writing-modules).
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (moduleName: module: {
+ what = "NixOS module";
+ evalChecks.isFunctionOrAttrs = checkModule module;
+ }) output
+ );
+ };
+
+ homeConfigurationsSchema = {
+ version = 1;
+ doc = ''
+ The `homeConfigurations` flake output defines [Home Manager configurations](https://github.com/nix-community/home-manager).
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (configName: this: {
+ what = "Home Manager configuration";
+ derivationAttrPath = [ "activationPackage" ];
+ forSystems = [ this.activationPackage.system ];
+ }) output
+ );
+ };
+
+ homeModulesSchema = {
+ version = 1;
+ doc = ''
+ The `homeModules` flake output defines importable [Home Manager](https://github.com/nix-community/home-manager) modules.
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (moduleName: module: {
+ what = "Home Manager module";
+ evalChecks.isFunctionOrAttrs = checkModule module;
+ }) output
+ );
+ };
+
+ darwinConfigurationsSchema = {
+ version = 1;
+ doc = ''
+ The `darwinConfigurations` flake output defines [nix-darwin configurations](https://github.com/nix-darwin/nix-darwin).
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (configName: this: {
+ what = "nix-darwin configuration";
+ derivationAttrPath = [ "system" ];
+ forSystems = [ this.system.system ];
+ }) output
+ );
+ };
+
+ darwinModulesSchema = {
+ version = 1;
+ doc = ''
+ The `darwinModules` flake output defines importable [nix-darwin modules](https://github.com/nix-darwin/nix-darwin).
+ '';
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (moduleName: module: {
+ what = "nix-darwin module";
+ evalChecks.isFunctionOrAttrs = checkModule module;
+ }) output
+ );
+ };
+
+ bundlersSchema = {
+ version = 1;
+ doc = ''
+ The `bundlers` flake output defines ["bundlers"](https://nix.dev/manual/nix/latest/command-ref/new-cli/nix3-bundle) that transform derivation outputs into other formats, typically self-extracting executables or container images.
+ '';
+ roles.nix-bundler = { };
+ appendSystem = true;
+ defaultAttrPath = [ "default" ];
+ inventory =
+ output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (
+ system: bundlers:
+ let
+ forSystems = [ system ];
+ in
+ {
+ inherit forSystems;
+ children = builtins.mapAttrs (bundlerName: bundler: {
+ inherit forSystems;
+ evalChecks.isValidBundler = builtins.isFunction bundler;
+ what = "bundler";
+ }) bundlers;
+ }
+ ) output
+ );
+ };
+
+ in
+
+ {
+ # Helper functions
+ lib = {
+ try =
+ e: default:
+ let
+ res = builtins.tryEval e;
+ in
+ if res.success then res.value else default;
+
+ mkChildren = children: { inherit children; };
+
+ derivationsInventory =
+ what: isFlakeCheck: output:
+ self.lib.mkChildren (
+ builtins.mapAttrs (systemType: packagesForSystem: {
+ forSystems = [ systemType ];
+ children = builtins.mapAttrs (
+ packageName: mkPackage isFlakeCheck what systemType
+ ) packagesForSystem;
+ }) output
+ );
+ };
+
+ # FIXME: distinguish between available and active schemas?
+ schemas.schemas = schemasSchema;
+ schemas.apps = appsSchema;
+ schemas.defaultApp = defaultAppSchema;
+ schemas.packages = packagesSchema;
+ schemas.defaultPackage = defaultPackageSchema;
+ schemas.legacyPackages = legacyPackagesSchema;
+ schemas.checks = checksSchema;
+ schemas.devShells = devShellsSchema;
+ schemas.devShell = devShellSchema;
+ schemas.formatter = formatterSchema;
+ schemas.templates = templatesSchema;
+ schemas.hydraJobs = hydraJobsSchema;
+ schemas.overlays = overlaysSchema;
+ schemas.nixosConfigurations = nixosConfigurationsSchema;
+ schemas.nixosModules = nixosModulesSchema;
+ schemas.homeConfigurations = homeConfigurationsSchema;
+ schemas.homeModules = homeModulesSchema;
+ schemas.darwinConfigurations = darwinConfigurationsSchema;
+ schemas.darwinModules = darwinModulesSchema;
+ schemas.ociImages = ociImagesSchema;
+ schemas.bundlers = bundlersSchema;
+ };
+}
diff --git a/src/libcmd/call-flake-schemas.nix b/src/libcmd/call-flake-schemas.nix
new file mode 100644
index 000000000000..f1604259aef7
--- /dev/null
+++ b/src/libcmd/call-flake-schemas.nix
@@ -0,0 +1,38 @@
+# The flake providing default schemas.
+defaultSchemasFlake:
+
+# The flake whose contents we want to extract.
+flake:
+
+let
+
+ # Helper functions.
+
+ mapAttrsToList = f: attrs: map (name: f name attrs.${name}) (builtins.attrNames attrs);
+
+ outputNames = builtins.attrNames flake.outputs;
+
+ schemas = flake.outputs.schemas or defaultSchemasFlake.schemas;
+
+in
+
+{
+ outputs = flake.outputs;
+
+ inventory = builtins.mapAttrs (
+ outputName: _:
+ if schemas ? ${outputName} && schemas.${outputName}.version == 1 then
+ schemas.${outputName}
+ // (
+ if flake.outputs ? ${outputName} then
+ {
+ output = schemas.${outputName}.inventory flake.outputs.${outputName};
+ }
+ else
+ {
+ }
+ )
+ else
+ { unknown = true; }
+ ) (schemas // flake.outputs);
+}
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 798ef072eb14..226b65f4a7c3 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -138,6 +138,13 @@ ref EvalCommand::getEvalStore()
ref EvalCommand::getEvalState()
{
if (!evalState) {
+ if (startReplOnEvalErrors && evalSettings.evalCores != 1U) {
+ // Disable parallel eval if the debugger is enabled, since
+ // they're incompatible at the moment.
+ warn("using the debugger disables multi-threaded evaluation");
+ evalSettings.evalCores = 1;
+ }
+
evalState = std::allocate_shared(
traceable_allocator(), lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore());
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 30e76b2455d4..865901febf48 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -19,17 +19,12 @@
namespace nix {
-fetchers::Settings fetchSettings;
-
-static GlobalConfig::Register rFetchSettings(&fetchSettings);
-
EvalSettings evalSettings{
settings.readOnlyMode,
{
{
"flake",
[](EvalState & state, std::string_view rest) {
- experimentalFeatureSettings.require(Xp::Flakes);
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(fetchSettings, std::string{rest}, {}, true, false);
debug("fetching flake search path element '%s''", rest);
@@ -186,7 +181,6 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const std::files
}
else if (hasPrefix(s, "flake:")) {
- experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(fetchSettings, std::string(s.substr(6)), {}, true, false);
auto [accessor, lockedRef] =
flakeRef.resolve(fetchSettings, *state.store).lazyFetch(fetchSettings, *state.store);
diff --git a/src/libcmd/flake-schemas.cc b/src/libcmd/flake-schemas.cc
new file mode 100644
index 000000000000..c8e2992be7e2
--- /dev/null
+++ b/src/libcmd/flake-schemas.cc
@@ -0,0 +1,387 @@
+#include "nix/cmd/flake-schemas.hh"
+#include "nix/expr/eval-settings.hh"
+#include "nix/fetchers/fetch-to-store.hh"
+#include "nix/util/memory-source-accessor.hh"
+#include "nix/util/mounted-source-accessor.hh"
+#include "nix/flake/provenance.hh"
+
+namespace nix::flake_schemas {
+
+using namespace eval_cache;
+using namespace flake;
+
+static LockedFlake getBuiltinDefaultSchemasFlake(EvalState & state)
+{
+ auto accessor = make_ref();
+
+ accessor->setPathDisplay("«builtin-flake-schemas»");
+
+ accessor->addFile(
+ CanonPath("flake.nix"),
+#include "builtin-flake-schemas.nix.gen.hh"
+ );
+
+ auto [storePath, narHash] = state.store->computeStorePath("source", {accessor});
+
+ state.allowPath(storePath); // FIXME: should just whitelist the entire virtual store
+
+ state.storeFS->mount(CanonPath(state.store->printStorePath(storePath)), accessor);
+
+ // Construct a dummy flakeref.
+ auto flakeRef = parseFlakeRef(
+ fetchSettings,
+ fmt("tarball+https://builtin-flake-schemas?narHash=%s", narHash.to_string(HashFormat::SRI, true)));
+
+ auto flake = readFlake(state, flakeRef, flakeRef, flakeRef, state.storePath(storePath), {});
+
+ return lockFlake(flakeSettings, state, flakeRef, {}, flake);
+}
+
+ref call(
+ EvalState & state,
+ std::shared_ptr lockedFlake,
+ std::optional defaultSchemasFlake,
+ bool allowEvalCache)
+{
+ auto fingerprint = lockedFlake->getFingerprint(*state.store, state.fetchSettings);
+
+ std::string callFlakeSchemasNix =
+#include "call-flake-schemas.nix.gen.hh"
+ ;
+
+ auto lockedDefaultSchemasFlake = defaultSchemasFlake
+ ? flake::lockFlake(flakeSettings, state, *defaultSchemasFlake, {})
+ : getBuiltinDefaultSchemasFlake(state);
+ auto lockedDefaultSchemasFlakeFingerprint =
+ lockedDefaultSchemasFlake.getFingerprint(*state.store, state.fetchSettings);
+
+ std::optional fingerprint2;
+ if (allowEvalCache && evalSettings.useEvalCache && evalSettings.pureEval && fingerprint
+ && lockedDefaultSchemasFlakeFingerprint)
+ fingerprint2 = hashString(
+ HashAlgorithm::SHA256,
+ fmt("app:%s:%s:%s",
+ hashString(HashAlgorithm::SHA256, callFlakeSchemasNix).to_string(HashFormat::Base16, false),
+ fingerprint->to_string(HashFormat::Base16, false),
+ lockedDefaultSchemasFlakeFingerprint->to_string(HashFormat::Base16, false)));
+
+ if (fingerprint2) {
+ auto i = state.evalCaches.find(*fingerprint2);
+ if (i != state.evalCaches.end())
+ return i->second;
+ }
+
+ auto cache = make_ref(
+ fingerprint2, state, [&state, lockedFlake, callFlakeSchemasNix, lockedDefaultSchemasFlake]() {
+ auto vCallFlakeSchemas = state.allocValue();
+ state.eval(
+ state.parseExprFromString(callFlakeSchemasNix, state.rootPath(CanonPath::root)), *vCallFlakeSchemas);
+
+ auto vFlake = state.allocValue();
+ flake::callFlake(state, *lockedFlake, *vFlake);
+
+ auto vDefaultSchemasFlake = state.allocValue();
+ if (vFlake->type() == nAttrs && vFlake->attrs()->get(state.symbols.create("schemas")))
+ vDefaultSchemasFlake->mkNull();
+ else
+ flake::callFlake(state, lockedDefaultSchemasFlake, *vDefaultSchemasFlake);
+
+ auto vRes = state.allocValue();
+ Value * args[] = {vDefaultSchemasFlake, vFlake};
+ state.callFunction(*vCallFlakeSchemas, args, *vRes, noPos);
+
+ return vRes;
+ });
+
+ /* Derive the flake output attribute path from the cursor used to
+ traverse the inventory. We do this so we don't have to maintain
+ a separate attrpath for that. */
+ cache->cleanupAttrPath = [&](AttrPath && attrPath) {
+ AttrPath res;
+ auto i = attrPath.begin();
+ if (i == attrPath.end())
+ return attrPath;
+
+ if (state.symbols[*i] == "inventory") {
+ ++i;
+ if (i != attrPath.end()) {
+ res.push_back(*i++); // copy output name
+ if (i != attrPath.end())
+ ++i; // skip "outputs"
+ while (i != attrPath.end()) {
+ ++i; // skip "children"
+ if (i != attrPath.end())
+ res.push_back(*i++);
+ }
+ }
+ }
+
+ else if (state.symbols[*i] == "outputs") {
+ res.insert(res.begin(), ++i, attrPath.end());
+ }
+
+ else
+ abort();
+
+ return res;
+ };
+
+ if (fingerprint2)
+ state.evalCaches.emplace(*fingerprint2, cache);
+
+ return cache;
+}
+
+void forEachOutput(
+ ref inventory,
+ std::function output, const std::string & doc, bool isLast)> f)
+{
+ auto outputNames = inventory->getAttrs();
+
+ auto doOutputs = [&](bool allowIFD) {
+ evalSettings.enableImportFromDerivation.setDefault(allowIFD);
+ for (const auto & [i, outputName] : enumerate(outputNames)) {
+ auto outputInfo = inventory->getAttr(outputName);
+ try {
+ auto allowIFDAttr = outputInfo->maybeGetAttr("allowIFD");
+ if (allowIFD != (!allowIFDAttr || allowIFDAttr->getBool()))
+ continue;
+ auto isUnknown = (bool) outputInfo->maybeGetAttr("unknown");
+ auto output = outputInfo->maybeGetAttr("output");
+ if (!output && !isUnknown)
+ // We have a schema but no corresponding output, so skip this.
+ continue;
+ Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", outputInfo->getAttrPathStr()));
+ f(outputName,
+ isUnknown ? std::shared_ptr() : output,
+ isUnknown ? "" : outputInfo->getAttr("doc")->getString(),
+ i + 1 == outputNames.size());
+ } catch (Error & e) {
+ e.addTrace(nullptr, "while evaluating the flake output '%s':", outputInfo->getAttrPathStr());
+ throw;
+ }
+ }
+ };
+
+ // Do outputs that disallow import-from-derivation first. That way, they can't depend on outputs that do allow it.
+ doOutputs(false);
+ doOutputs(true);
+}
+
+void visit(
+ std::optional system,
+ bool includeLegacy,
+ ref node,
+ std::shared_ptr provenance,
+ std::function visitLeaf,
+ std::function)> visitNonLeaf,
+ std::function node, const std::vector & systems)> visitFiltered,
+ std::function node)> visitLegacy)
+{
+ Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", node->getAttrPathStr()));
+
+ PushProvenance pushedProvenance(
+ node->root->state,
+ provenance ? std::make_shared(provenance, node->getAttrPathStr(), evalSettings.pureEval)
+ : nullptr);
+
+ /* Filter out legacy outputs, unless --legacy is enabled. */
+ if (!includeLegacy) {
+ if (auto b = node->maybeGetAttr("isLegacy"); b && b->getBool()) {
+ visitLegacy(node);
+ return;
+ }
+ }
+
+ /* Apply the system type filter. */
+ if (system) {
+ if (auto forSystems = Node(node).forSystems()) {
+ if (std::find(forSystems->begin(), forSystems->end(), *system) == forSystems->end()) {
+ visitFiltered(node, *forSystems);
+ return;
+ }
+ }
+ }
+
+ if (auto children = node->maybeGetAttr("children")) {
+ visitNonLeaf([&](ForEachChild f) {
+ auto attrNames = children->getAttrs();
+ for (const auto & [i, attrName] : enumerate(attrNames)) {
+ try {
+ f(attrName, children->getAttr(attrName), i + 1 == attrNames.size());
+ } catch (Error & e) {
+ // FIXME: use the `isLegacy` attribute.
+ if (node->root->state.symbols[node->getAttrPath()[0]] != "legacyPackages") {
+ e.addTrace(
+ nullptr, "while evaluating the flake output attribute '%s':", node->getAttrPathStr());
+ throw;
+ }
+ }
+ }
+ });
+ }
+
+ else
+ visitLeaf(Leaf(node));
+}
+
+std::optional> Node::forSystems() const
+{
+ if (auto forSystems = node->maybeGetAttr("forSystems"))
+ return forSystems->getListOfStrings();
+ else
+ return std::nullopt;
+}
+
+ref Node::getOutput(const ref & outputs) const
+{
+ auto res = outputs->findAlongAttrPath(node->getAttrPath());
+ if (!res)
+ throw Error("flake output '%s' should exist according to its schema, but it doesn't", node->getAttrPathStr());
+ return *res;
+}
+
+std::optional Leaf::what() const
+{
+ if (auto what = node->maybeGetAttr("what"))
+ return what->getString();
+ else
+ return std::nullopt;
+}
+
+std::optional Leaf::shortDescription() const
+{
+ if (auto what = node->maybeGetAttr("shortDescription"))
+ return what->getString();
+ return std::nullopt;
+}
+
+std::optional Leaf::derivationAttrPath() const
+{
+ auto n = node->maybeGetAttr("derivationAttrPath");
+ if (!n)
+ return std::nullopt;
+ return AttrPath::fromStrings(node->root->state, n->getListOfStrings());
+}
+
+std::shared_ptr Leaf::derivation(const ref & outputs) const
+{
+ auto path = derivationAttrPath();
+ if (!path) {
+ auto n = node->maybeGetAttr("derivation");
+ if (n)
+ warn(
+ "Flake output '%s' has a schema that uses the deprecated 'derivation' attribute instead of 'derivationAttrPath'. "
+ "Please update the schema to use 'derivationAttrPath' instead. "
+ "You may want to upgrade to version 0.3.0 or higher of https://github.com/DeterminateSystems/flake-schemas.",
+ node->getAttrPathStr());
+ return n;
+ }
+ auto drv = getOutput(outputs)->findAlongAttrPath(*path);
+ if (!drv)
+ throw Error(
+ "flake output '%s' does not have a derivation attribute '%s'",
+ node->getAttrPathStr(),
+ path->to_string(node->root->state));
+ return *drv;
+}
+
+bool Leaf::isFlakeCheck() const
+{
+ auto isFlakeCheck = node->maybeGetAttr("isFlakeCheck");
+ return isFlakeCheck && isFlakeCheck->getBool();
+}
+
+std::optional getOutputInfo(ref inventory, AttrPath attrPath)
+{
+ if (attrPath.empty())
+ return std::nullopt;
+
+ auto outputName = attrPath.front();
+
+ auto schemaInfo = inventory->maybeGetAttr(outputName);
+ if (!schemaInfo)
+ return std::nullopt;
+
+ auto node = schemaInfo->maybeGetAttr("output");
+ if (!node)
+ return std::nullopt;
+
+ auto pathLeft = std::span(attrPath).subspan(1);
+
+ while (!pathLeft.empty()) {
+ auto children = node->maybeGetAttr("children");
+ if (!children)
+ break;
+ auto attr = pathLeft.front();
+ node = children->maybeGetAttr(attr);
+ if (!node)
+ return std::nullopt;
+ pathLeft = pathLeft.subspan(1);
+ }
+
+ return OutputInfo{
+ .schemaInfo = ref(schemaInfo),
+ .nodeInfo = ref(node),
+ .leafAttrPath = AttrPath(pathLeft.begin(), pathLeft.end()),
+ };
+}
+
+Schemas getSchemas(ref inventory)
+{
+ auto & state(inventory->root->state);
+
+ Schemas schemas;
+
+ for (auto & schemaName : inventory->getAttrs()) {
+ auto schema = inventory->getAttr(schemaName);
+
+ SchemaInfo schemaInfo;
+
+ if (auto roles = schema->maybeGetAttr("roles")) {
+ for (auto & roleName : roles->getAttrs()) {
+ schemaInfo.roles.insert(std::string(state.symbols[roleName]));
+ }
+ }
+
+ if (auto appendSystem = schema->maybeGetAttr("appendSystem"))
+ schemaInfo.appendSystem = appendSystem->getBool();
+
+ if (auto defaultAttrPath = schema->maybeGetAttr("defaultAttrPath")) {
+ AttrPath attrPath;
+ for (auto & s : defaultAttrPath->getListOfStrings())
+ attrPath.push_back(state.symbols.create(s));
+ schemaInfo.defaultAttrPath = std::move(attrPath);
+ }
+
+ schemas.insert_or_assign(std::string(state.symbols[schemaName]), std::move(schemaInfo));
+ }
+
+ return schemas;
+}
+
+} // namespace nix::flake_schemas
+
+namespace nix {
+
+MixFlakeSchemas::MixFlakeSchemas()
+{
+ addFlag(
+ {.longName = "default-flake-schemas",
+ .description = "The URL of the flake providing default flake schema definitions.",
+ .labels = {"flake-ref"},
+ .handler = {&defaultFlakeSchemas},
+ .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
+ completeFlakeRef(completions, getStore(), prefix);
+ }}});
+}
+
+std::optional MixFlakeSchemas::getDefaultFlakeSchemas()
+{
+ if (!defaultFlakeSchemas)
+ return std::nullopt;
+ else
+ return parseFlakeRef(fetchSettings, *defaultFlakeSchemas, absPath(getCommandBaseDir()));
+}
+
+} // namespace nix
diff --git a/src/libcmd/include/nix/cmd/command.hh b/src/libcmd/include/nix/cmd/command.hh
index d1b528e2477c..ec2e0d9add4c 100644
--- a/src/libcmd/include/nix/cmd/command.hh
+++ b/src/libcmd/include/nix/cmd/command.hh
@@ -132,7 +132,16 @@ struct MixFlakeOptions : virtual Args, EvalCommand
}
};
-struct SourceExprCommand : virtual Args, MixFlakeOptions
+struct MixFlakeSchemas : virtual Args, virtual StoreCommand
+{
+ std::optional defaultFlakeSchemas;
+
+ MixFlakeSchemas();
+
+ std::optional getDefaultFlakeSchemas();
+};
+
+struct SourceExprCommand : virtual Args, MixFlakeOptions, MixFlakeSchemas
{
std::optional file;
std::optional expr;
@@ -143,9 +152,13 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
ref parseInstallable(ref store, const std::string & installable);
- virtual Strings getDefaultFlakeAttrPaths();
-
- virtual Strings getDefaultFlakeAttrPathPrefixes();
+ /**
+ * Return a set of "roles" that this command implements
+ * (e.g. `nix-build` or `nix-develop`). This is used by flake
+ * schemas to determine which flake outputs are used as default
+ * attrpath prefixes.
+ */
+ virtual StringSet getRoles();
/**
* Complete an installable from the given prefix.
@@ -214,6 +227,8 @@ struct InstallableCommand : virtual Args, SourceExprCommand
{
InstallableCommand();
+ virtual void preRun(ref store);
+
virtual void run(ref store, ref installable) = 0;
void run(ref store) override;
@@ -372,8 +387,7 @@ void completeFlakeRefWithFragment(
AddCompletions & completions,
ref evalState,
flake::LockFlags lockFlags,
- Strings attrPathPrefixes,
- const Strings & defaultFlakeAttrPaths,
+ const StringSet & roles,
std::string_view prefix);
std::string showVersions(const StringSet & versions);
diff --git a/src/libcmd/include/nix/cmd/common-eval-args.hh b/src/libcmd/include/nix/cmd/common-eval-args.hh
index 67cb0714827f..4f9ebb83df53 100644
--- a/src/libcmd/include/nix/cmd/common-eval-args.hh
+++ b/src/libcmd/include/nix/cmd/common-eval-args.hh
@@ -25,9 +25,6 @@ namespace flake {
struct Settings;
}
-/**
- * @todo Get rid of global settings variables
- */
extern fetchers::Settings fetchSettings;
/**
diff --git a/src/libcmd/include/nix/cmd/flake-schemas.hh b/src/libcmd/include/nix/cmd/flake-schemas.hh
new file mode 100644
index 000000000000..bfc2a38cdef0
--- /dev/null
+++ b/src/libcmd/include/nix/cmd/flake-schemas.hh
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "nix/expr/eval-cache.hh"
+#include "nix/flake/flake.hh"
+#include "nix/cmd/command.hh"
+
+namespace nix::flake_schemas {
+
+using namespace eval_cache;
+
+ref call(
+ EvalState & state,
+ std::shared_ptr lockedFlake,
+ std::optional defaultSchemasFlake,
+ bool allowEvalCache = true);
+
+void forEachOutput(
+ ref inventory,
+ std::function output, const std::string & doc, bool isLast)> f);
+
+/**
+ * A convenience wrapper around `AttrCursor` for nodes in the `inventory` tree returned by call-flake-schemas.nix.
+ */
+struct Node
+{
+ const ref node;
+
+ Node(const ref & node)
+ : node(node)
+ {
+ }
+
+ /**
+ * Return the `forSystems` attribute. This can be null, which
+ * means "all systems".
+ */
+ std::optional> forSystems() const;
+
+ /**
+ * Return the actual output corresponding to this info node.
+ */
+ ref getOutput(const ref & outputs) const;
+};
+
+struct Leaf : Node
+{
+ using Node::Node;
+
+ std::optional what() const;
+
+ std::optional shortDescription() const;
+
+ std::optional derivationAttrPath() const;
+
+ /**
+ * Return the attribute corresponding to `derivationAttrPath`, if set.
+ */
+ std::shared_ptr derivation(const ref & outputs) const;
+
+ bool isFlakeCheck() const;
+};
+
+typedef std::function attr, bool isLast)> ForEachChild;
+
+void visit(
+ std::optional system,
+ bool includeLegacy,
+ ref node,
+ std::shared_ptr provenance,
+ std::function visitLeaf,
+ std::function)> visitNonLeaf,
+ std::function node, const std::vector & systems)> visitFiltered,
+ std::function node)> visitLegacy);
+
+struct OutputInfo
+{
+ ref schemaInfo;
+ ref nodeInfo;
+ AttrPath leafAttrPath;
+};
+
+std::optional getOutputInfo(ref inventory, AttrPath attrPath);
+
+struct SchemaInfo
+{
+ std::string doc;
+ StringSet roles;
+ bool appendSystem = false;
+ std::optional defaultAttrPath;
+};
+
+using Schemas = std::map;
+
+Schemas getSchemas(ref root);
+
+} // namespace nix::flake_schemas
diff --git a/src/libcmd/include/nix/cmd/installable-attr-path.hh b/src/libcmd/include/nix/cmd/installable-attr-path.hh
index 474bb358ec91..ef9dac813346 100644
--- a/src/libcmd/include/nix/cmd/installable-attr-path.hh
+++ b/src/libcmd/include/nix/cmd/installable-attr-path.hh
@@ -21,8 +21,6 @@
#include
#include
-#include
-
namespace nix {
class InstallableAttrPath : public InstallableValue
diff --git a/src/libcmd/include/nix/cmd/installable-flake.hh b/src/libcmd/include/nix/cmd/installable-flake.hh
index 9f449ad48f2e..3acce913dcb7 100644
--- a/src/libcmd/include/nix/cmd/installable-flake.hh
+++ b/src/libcmd/include/nix/cmd/installable-flake.hh
@@ -36,11 +36,14 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue
struct InstallableFlake : InstallableValue
{
FlakeRef flakeRef;
- Strings attrPaths;
- Strings prefixes;
+ std::string fragment;
+ AttrPath parsedFragment;
+ StringSet roles;
ExtendedOutputsSpec extendedOutputsSpec;
const flake::LockFlags & lockFlags;
mutable std::shared_ptr _lockedFlake;
+ bool useEvalCache = true;
+ std::optional defaultFlakeSchemas;
InstallableFlake(
SourceExprCommand * cmd,
@@ -48,17 +51,15 @@ struct InstallableFlake : InstallableValue
FlakeRef && flakeRef,
std::string_view fragment,
ExtendedOutputsSpec extendedOutputsSpec,
- Strings attrPaths,
- Strings prefixes,
- const flake::LockFlags & lockFlags);
+ StringSet roles,
+ const flake::LockFlags & lockFlags,
+ std::optional defaultFlakeSchemas);
std::string what() const override
{
- return flakeRef.to_string() + "#" + *attrPaths.begin();
+ return flakeRef.to_string() + "#" + fragment;
}
- std::vector getActualAttrPaths();
-
DerivedPathsWithInfo toDerivedPaths() override;
std::pair toValue(EvalState & state) override;
@@ -67,11 +68,23 @@ struct InstallableFlake : InstallableValue
* Get a cursor to every attrpath in getActualAttrPaths() that
* exists. However if none exists, throw an exception.
*/
- std::vector[> getCursors(EvalState & state) override;
+ std::vector][> getCursors(EvalState & state, bool useDefaultAttrPath) override;
+
+ void getCompletions(const std::string & flakeRefS, AddCompletions & completions);
ref getLockedFlake() const;
FlakeRef nixpkgsFlakeRef() const;
+
+ std::shared_ptr makeProvenance(std::string_view attrPath) const;
+
+ ref openEvalCache() const;
+
+private:
+
+ mutable std::shared_ptr _evalCache;
+
+ std::vector getAttrPaths(bool useDefaultAttrPath, ref inventory);
};
/**
diff --git a/src/libcmd/include/nix/cmd/installable-value.hh b/src/libcmd/include/nix/cmd/installable-value.hh
index 27a1fb9815d4..09178c96c972 100644
--- a/src/libcmd/include/nix/cmd/installable-value.hh
+++ b/src/libcmd/include/nix/cmd/installable-value.hh
@@ -93,7 +93,7 @@ struct InstallableValue : Installable
* However if none exists, throw exception instead of returning
* empty vector.
*/
- virtual std::vector][> getCursors(EvalState & state);
+ virtual std::vector][> getCursors(EvalState & state, bool useDefaultAttrPath = true);
/**
* Get the first and most preferred cursor this Installable could
diff --git a/src/libcmd/include/nix/cmd/installables.hh b/src/libcmd/include/nix/cmd/installables.hh
index 530334e037b7..2ea35261c7fa 100644
--- a/src/libcmd/include/nix/cmd/installables.hh
+++ b/src/libcmd/include/nix/cmd/installables.hh
@@ -96,6 +96,22 @@ typedef std::vector DerivedPathsWithInfo;
struct Installable;
+struct InstallableWithBuildResult
+{
+ ref installable;
+
+ using Success = BuiltPathWithResult;
+
+ using Failure = BuildResult; // must be a `BuildResult::Failure`
+
+ std::variant result;
+
+ /**
+ * Throw an exception if this represents a failure, otherwise returns a `BuiltPathWithResult`.
+ */
+ const BuiltPathWithResult & getSuccess() const;
+};
+
/**
* Shorthand, for less typing and helping us keep the choice of
* collection in sync.
@@ -160,13 +176,15 @@ struct Installable
const Installables & installables,
BuildMode bMode = bmNormal);
- static std::vector, BuiltPathWithResult>> build2(
+ static std::vector build2(
ref evalStore,
ref store,
Realise mode,
const Installables & installables,
BuildMode bMode = bmNormal);
+ static void throwBuildErrors(std::vector & buildResults, const Store & store);
+
static std::set toStorePathSet(
ref evalStore, ref store, Realise mode, OperateOn operateOn, const Installables & installables);
diff --git a/src/libcmd/include/nix/cmd/meson.build b/src/libcmd/include/nix/cmd/meson.build
index 119d0814b9f1..7ab3e596ae40 100644
--- a/src/libcmd/include/nix/cmd/meson.build
+++ b/src/libcmd/include/nix/cmd/meson.build
@@ -9,6 +9,7 @@ headers = files(
'common-eval-args.hh',
'compatibility-settings.hh',
'editor-for.hh',
+ 'flake-schemas.hh',
'installable-attr-path.hh',
'installable-derived-path.hh',
'installable-flake.hh',
diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc
index 28c3db3fc79a..3a80aa384de4 100644
--- a/src/libcmd/installable-attr-path.cc
+++ b/src/libcmd/installable-attr-path.cc
@@ -89,7 +89,8 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
}
DerivedPathsWithInfo res;
- for (auto & [drvPath, outputs] : byDrvPath)
+ for (auto & [drvPath, outputs] : byDrvPath) {
+ state->waitForPath(drvPath);
res.push_back({
.path =
DerivedPath::Built{
@@ -102,6 +103,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
so we can fill in this info. */
}),
});
+ }
return res;
}
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 11bbdbf8429d..ebec82f2e30e 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -17,6 +17,8 @@
#include "nix/util/url.hh"
#include "nix/fetchers/registry.hh"
#include "nix/store/build-result.hh"
+#include "nix/flake/provenance.hh"
+#include "nix/cmd/flake-schemas.hh"
#include
#include
@@ -25,32 +27,14 @@
namespace nix {
-std::vector InstallableFlake::getActualAttrPaths()
-{
- std::vector res;
- if (attrPaths.size() == 1 && attrPaths.front().starts_with(".")) {
- attrPaths.front().erase(0, 1);
- res.push_back(attrPaths.front());
- return res;
- }
-
- for (auto & prefix : prefixes)
- res.push_back(prefix + *attrPaths.begin());
-
- for (auto & s : attrPaths)
- res.push_back(s);
-
- return res;
-}
-
-static std::string showAttrPaths(const std::vector & paths)
+static std::string showAttrPaths(EvalState & state, const std::vector & paths)
{
std::string s;
for (const auto & [n, i] : enumerate(paths)) {
if (n > 0)
s += n + 1 == paths.size() ? " or " : ", ";
s += '\'';
- s += i;
+ s += i.to_string(state);
s += '\'';
}
return s;
@@ -62,15 +46,17 @@ InstallableFlake::InstallableFlake(
FlakeRef && flakeRef,
std::string_view fragment,
ExtendedOutputsSpec extendedOutputsSpec,
- Strings attrPaths,
- Strings prefixes,
- const flake::LockFlags & lockFlags)
+ StringSet roles,
+ const flake::LockFlags & lockFlags,
+ std::optional defaultFlakeSchemas)
: InstallableValue(state)
, flakeRef(flakeRef)
- , attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment})
- , prefixes(fragment == "" ? Strings{} : prefixes)
+ , fragment(fragment)
+ , parsedFragment(AttrPath::parse(*state, fragment))
+ , roles(roles)
, extendedOutputsSpec(std::move(extendedOutputsSpec))
, lockFlags(lockFlags)
+ , defaultFlakeSchemas(defaultFlakeSchemas)
{
if (cmd && cmd->getAutoArgs(*state)->size())
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
@@ -84,6 +70,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
auto attrPath = attr->getAttrPathStr();
+ PushProvenance pushedProvenance(*state, makeProvenance(attrPath));
+
if (!attr->isDerivation()) {
// FIXME: use eval cache?
@@ -102,6 +90,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
}
auto drvPath = attr->forceDerivation();
+ state->waitForPath(drvPath);
std::optional priority;
@@ -157,34 +146,169 @@ std::pair InstallableFlake::toValue(EvalState & state)
return {&getCursor(state)->forceValue(), noPos};
}
-std::vector][> InstallableFlake::getCursors(EvalState & state)
+std::vector InstallableFlake::getAttrPaths(bool useDefaultAttrPath, ref inventory)
{
- auto evalCache = openEvalCache(state, getLockedFlake());
+ if (fragment.starts_with("."))
+ return {AttrPath::parse(*state, fragment.substr(1))};
+
+ std::vector attrPaths;
+
+ auto schemas = flake_schemas::getSchemas(inventory);
+
+ // FIXME: Ugly hack to preserve the historical precedence
+ // between outputs. We should add a way for schemas to declare
+ // priorities.
+ std::vector schemasSorted;
+ std::set schemasSeen;
+ auto doSchema = [&](const std::string & schema) {
+ if (schemas.contains(schema)) {
+ schemasSorted.push_back(schema);
+ schemasSeen.insert(schema);
+ }
+ };
+ doSchema("apps");
+ doSchema("defaultApp");
+ doSchema("devShells");
+ doSchema("devShell");
+ doSchema("packages");
+ doSchema("defaultPackage");
+ doSchema("legacyPackages");
+ for (auto & schema : schemas)
+ if (!schemasSeen.contains(schema.first))
+ schemasSorted.push_back(schema.first);
+
+ for (auto & role : roles) {
+ for (auto & schemaName : schemasSorted) {
+ auto & schema = schemas.find(schemaName)->second;
+ if (schema.roles.contains(role)) {
+ AttrPath attrPath{state->symbols.create(schemaName)};
+ if (schema.appendSystem)
+ attrPath.push_back(state->symbols.create(settings.thisSystem.get()));
+
+ if (useDefaultAttrPath && parsedFragment.empty()) {
+ if (schema.defaultAttrPath) {
+ auto attrPath2{attrPath};
+ for (auto & x : *schema.defaultAttrPath)
+ attrPath2.push_back(x);
+ attrPaths.push_back(attrPath2);
+ }
+ } else {
+ auto attrPath2{attrPath};
+ for (auto & x : parsedFragment)
+ attrPath2.push_back(x);
+ attrPaths.push_back(attrPath2);
+ }
+ }
+ }
+ }
+
+ if (!parsedFragment.empty())
+ attrPaths.push_back(parsedFragment);
+
+ // FIXME: compatibility hack to get `nix repl` to return all
+ // outputs by default.
+ if (parsedFragment.empty() && roles.contains("nix-repl"))
+ attrPaths.push_back({});
+
+ return attrPaths;
+}
+
+std::vector][> InstallableFlake::getCursors(EvalState & state, bool useDefaultAttrPath)
+{
+ auto cache = openEvalCache();
+
+ auto inventory = cache->getRoot()->getAttr("inventory");
+ auto outputs = cache->getRoot()->getAttr("outputs");
- auto root = evalCache->getRoot();
+ auto attrPaths = getAttrPaths(useDefaultAttrPath, inventory);
+
+ if (attrPaths.empty())
+ throw Error(
+ "Flake '%s' does not have any schema that provides a default output for the role(s) %s.",
+ flakeRef,
+ concatStringsSep(", ", roles));
std::vector][> res;
Suggestions suggestions;
- auto attrPaths = getActualAttrPaths();
for (auto & attrPath : attrPaths) {
- debug("trying flake output attribute '%s'", attrPath);
+ debug("trying flake output attribute '%s'", attrPath.to_string(state));
+
+ PushProvenance pushedProvenance(state, makeProvenance(attrPath.to_string(state)));
+
+#if 0
+ auto outputInfo = flake_schemas::getOutputInfo(inventory, attrPath);
+
+ if (outputInfo && outputInfo->leafAttrPath.empty()) {
+ if (auto drv = outputInfo->nodeInfo->maybeGetAttr("derivation")) {
+ res.push_back(ref(drv));
+ continue;
+ }
+ }
+#endif
- auto attr = root->findAlongAttrPath(AttrPath::parse(state, attrPath));
- if (attr) {
+ auto attr = outputs->findAlongAttrPath(attrPath);
+ if (attr)
res.push_back(ref(*attr));
- } else {
+ else
suggestions += attr.getSuggestions();
- }
}
if (res.size() == 0)
- throw Error(suggestions, "flake '%s' does not provide attribute %s", flakeRef, showAttrPaths(attrPaths));
+ throw Error(suggestions, "flake '%s' does not provide attribute %s", flakeRef, showAttrPaths(state, attrPaths));
return res;
}
+void InstallableFlake::getCompletions(const std::string & flakeRefS, AddCompletions & completions)
+{
+ auto cache = openEvalCache();
+
+ auto inventory = cache->getRoot()->getAttr("inventory");
+ auto outputs = cache->getRoot()->getAttr("outputs");
+
+ if (fragment.ends_with(".") || fragment.empty())
+ // Represent that we're looking for attributes starting with the empty prefix (i.e. all attributes inside the
+ // parent.
+ parsedFragment.push_back(state->symbols.create(""));
+
+ auto attrPaths = getAttrPaths(true, inventory);
+
+ if (fragment.empty())
+ // Return all top-level flake outputs.
+ attrPaths.push_back(AttrPath{state->symbols.create("")});
+
+ auto lastAttr = fragment.ends_with(".") || parsedFragment.empty() ? std::string_view("")
+ : state->symbols[parsedFragment.back()];
+ std::string prefix;
+ if (auto dot = fragment.rfind('.'); dot != std::string::npos)
+ prefix = fragment.substr(0, dot);
+ if (fragment.starts_with(".") && !prefix.starts_with("."))
+ prefix = "." + prefix;
+
+ for (auto attrPath : attrPaths) {
+ if (attrPath.empty())
+ attrPath.push_back(state->symbols.create(""));
+
+ auto attrPathParent{attrPath};
+ attrPathParent.pop_back();
+
+ auto attr = outputs->findAlongAttrPath(attrPathParent);
+ if (!attr)
+ continue;
+
+ for (auto & childName : (*attr)->getAttrs()) {
+ if (hasPrefix(state->symbols[childName], lastAttr)) {
+ auto attrPathChild = (*attr)->getAttrPath(childName);
+ completions.add(
+ flakeRefS + "#" + prefix + (prefix.empty() || prefix.ends_with(".") ? "" : ".")
+ + state->symbols[childName]);
+ }
+ }
+ }
+}
+
ref InstallableFlake::getLockedFlake() const
{
if (!_lockedFlake) {
@@ -197,6 +321,14 @@ ref InstallableFlake::getLockedFlake() const
return ref(_lockedFlake);
}
+ref InstallableFlake::openEvalCache() const
+{
+ if (!_evalCache) {
+ _evalCache = flake_schemas::call(*state, getLockedFlake(), defaultFlakeSchemas, useEvalCache);
+ }
+ return ref(_evalCache);
+}
+
FlakeRef InstallableFlake::nixpkgsFlakeRef() const
{
auto lockedFlake = getLockedFlake();
@@ -211,4 +343,12 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const
return defaultNixpkgsFlakeRef();
}
+std::shared_ptr InstallableFlake::makeProvenance(std::string_view attrPath) const
+{
+ auto provenance = getLockedFlake()->flake.provenance;
+ if (!provenance)
+ return nullptr;
+ return std::make_shared(provenance, std::string(attrPath), evalSettings.pureEval);
+}
+
} // namespace nix
diff --git a/src/libcmd/installable-value.cc b/src/libcmd/installable-value.cc
index 3a167af3db49..6c2fd60efd8e 100644
--- a/src/libcmd/installable-value.cc
+++ b/src/libcmd/installable-value.cc
@@ -4,7 +4,7 @@
namespace nix {
-std::vector][> InstallableValue::getCursors(EvalState & state)
+std::vector][> InstallableValue::getCursors(EvalState & state, bool useDefaultAttrPath)
{
auto evalCache =
std::make_shared(std::nullopt, state, [&]() { return toValue(state).first; });
@@ -15,7 +15,7 @@ ref InstallableValue::getCursor(EvalState & state)
{
/* Although getCursors should return at least one element, in case it doesn't,
bound check to avoid an undefined behavior for vector[0] */
- return getCursors(state).at(0);
+ return getCursors(state, true).at(0);
}
static UsageError nonValueInstallable(Installable & installable)
@@ -55,7 +55,7 @@ InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::
else if (v.type() == nString) {
return {{
- .path = DerivedPath::fromSingle(state->coerceToSingleDerivedPath(pos, v, errorCtx)),
+ .path = DerivedPath::fromSingle(state->devirtualize(state->coerceToSingleDerivedPath(pos, v, errorCtx))),
.info = make_ref(),
}};
}
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 7e3861e2f1d3..740e53d74af4 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -21,6 +21,7 @@
#include "nix/util/url.hh"
#include "nix/fetchers/registry.hh"
#include "nix/store/build-result.hh"
+#include "nix/util/exit.hh"
#include
#include
@@ -233,19 +234,9 @@ MixReadOnlyOption::MixReadOnlyOption()
});
}
-Strings SourceExprCommand::getDefaultFlakeAttrPaths()
+StringSet SourceExprCommand::getRoles()
{
- return {"packages." + settings.thisSystem.get() + ".default", "defaultPackage." + settings.thisSystem.get()};
-}
-
-Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
-{
- return {// As a convenience, look for the attribute in
- // 'outputs.packages'.
- "packages." + settings.thisSystem.get() + ".",
- // As a temporary hack until Nixpkgs is properly converted
- // to provide a clean 'packages' set, look in 'legacyPackages'.
- "legacyPackages." + settings.thisSystem.get() + "."};
+ return {"nix-build"};
}
Args::CompleterClosure SourceExprCommand::getCompleteInstallable()
@@ -299,13 +290,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
}
}
} else {
- completeFlakeRefWithFragment(
- completions,
- getEvalState(),
- lockFlags,
- getDefaultFlakeAttrPathPrefixes(),
- getDefaultFlakeAttrPaths(),
- prefix);
+ completeFlakeRefWithFragment(completions, getEvalState(), lockFlags, getRoles(), prefix);
}
} catch (EvalError &) {
// Don't want eval errors to mess-up with the completion engine, so let's just swallow them
@@ -316,91 +301,37 @@ void completeFlakeRefWithFragment(
AddCompletions & completions,
ref evalState,
flake::LockFlags lockFlags,
- Strings attrPathPrefixes,
- const Strings & defaultFlakeAttrPaths,
+ const StringSet & roles,
std::string_view prefix)
-{
- /* Look for flake output attributes that match the
- prefix. */
- try {
- auto hash = prefix.find('#');
- if (hash == std::string::npos) {
- completeFlakeRef(completions, evalState->store, prefix);
- } else {
- completions.setType(AddCompletions::Type::Attrs);
-
- auto fragment = prefix.substr(hash + 1);
- std::string prefixRoot = "";
- if (fragment.starts_with(".")) {
- fragment = fragment.substr(1);
- prefixRoot = ".";
- }
- auto flakeRefS = std::string(prefix.substr(0, hash));
-
- // TODO: ideally this would use the command base directory instead of assuming ".".
- auto flakeRef =
- parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string());
-
- auto evalCache = openEvalCache(
- *evalState, make_ref(lockFlake(flakeSettings, *evalState, flakeRef, lockFlags)));
-
- auto root = evalCache->getRoot();
-
- if (prefixRoot == ".") {
- attrPathPrefixes.clear();
- }
- /* Complete 'fragment' relative to all the
- attrpath prefixes as well as the root of the
- flake. */
- attrPathPrefixes.push_back("");
-
- for (auto & attrPathPrefixS : attrPathPrefixes) {
- auto attrPathPrefix = AttrPath::parse(*evalState, attrPathPrefixS);
- auto attrPathS = attrPathPrefixS + std::string(fragment);
- auto attrPath = AttrPath::parse(*evalState, attrPathS);
-
- std::string lastAttr;
- if (!attrPath.empty() && !hasSuffix(attrPathS, ".")) {
- lastAttr = evalState->symbols[attrPath.back()];
- attrPath.pop_back();
- }
+try {
+ auto hash = prefix.find('#');
+ if (hash == std::string::npos) {
+ completeFlakeRef(completions, evalState->store, prefix);
+ return;
+ }
- auto attr = root->findAlongAttrPath(attrPath);
- if (!attr)
- continue;
+ completions.setType(AddCompletions::Type::Attrs);
- for (auto & attr2 : (*attr)->getAttrs()) {
- if (hasPrefix(evalState->symbols[attr2], lastAttr)) {
- auto attrPath2 = (*attr)->getAttrPath(attr2);
- /* Strip the attrpath prefix. */
- attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
- // FIXME: handle names with dots
- completions.add(flakeRefS + "#" + prefixRoot + attrPath2.to_string(*evalState));
- }
- }
- }
+ auto fragment = prefix.substr(hash + 1);
+ auto flakeRefS = std::string(prefix.substr(0, hash));
- /* And add an empty completion for the default
- attrpaths. */
- if (fragment.empty()) {
- for (auto & attrPath : defaultFlakeAttrPaths) {
- auto attr = root->findAlongAttrPath(AttrPath::parse(*evalState, attrPath));
- if (!attr)
- continue;
- completions.add(flakeRefS + "#" + prefixRoot);
- }
- }
- }
- } catch (Error & e) {
- warn(e.msg());
- }
+ InstallableFlake{
+ nullptr,
+ evalState,
+ // TODO: ideally this would use the command base directory instead of assuming ".".
+ parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string()),
+ fragment,
+ ExtendedOutputsSpec::Default{}, // FIXME: could be that we're completing the outputs spec...
+ roles,
+ lockFlags,
+ {}}
+ .getCompletions(flakeRefS, completions);
+} catch (Error & e) {
+ warn(e.msg());
}
void completeFlakeRef(AddCompletions & completions, ref store, std::string_view prefix)
{
- if (!experimentalFeatureSettings.isEnabled(Xp::Flakes))
- return;
-
if (prefix == "")
completions.add(".");
@@ -510,9 +441,9 @@ Installables SourceExprCommand::parseInstallables(ref store, std::vector<
std::move(flakeRef),
fragment,
std::move(extendedOutputsSpec),
- getDefaultFlakeAttrPaths(),
- getDefaultFlakeAttrPathPrefixes(),
- lockFlags));
+ getRoles(),
+ lockFlags,
+ getDefaultFlakeSchemas()));
continue;
} catch (...) {
ex = std::current_exception();
@@ -554,46 +485,69 @@ static SingleBuiltPath getBuiltPath(ref evalStore, ref store, cons
b.raw());
}
-std::vector Installable::build(
- ref evalStore, ref store, Realise mode, const Installables & installables, BuildMode bMode)
+const BuiltPathWithResult & InstallableWithBuildResult::getSuccess() const
{
- std::vector res;
- for (auto & [_, builtPathWithResult] : build2(evalStore, store, mode, installables, bMode))
- res.push_back(builtPathWithResult);
- return res;
+ if (auto * failure = std::get_if(&result)) {
+ auto failure2 = failure->tryGetFailure();
+ assert(failure2);
+ failure2->rethrow();
+ } else
+ return *std::get_if(&result);
}
-static void throwBuildErrors(std::vector & buildResults, const Store & store)
+void Installable::throwBuildErrors(std::vector & buildResults, const Store & store)
{
- std::vector> failed;
for (auto & buildResult : buildResults) {
- if (auto * failure = buildResult.tryGetFailure()) {
- failed.push_back({&buildResult, failure});
- }
- }
+ if (std::get_if(&buildResult.result)) {
+ // Report success first.
+ for (auto & buildResult : buildResults) {
+ if (std::get_if(&buildResult.result))
+ notice("✅ " ANSI_BOLD "%s" ANSI_NORMAL, buildResult.installable->what());
+ }
- auto failedResult = failed.begin();
- if (failedResult != failed.end()) {
- if (failed.size() == 1) {
- failedResult->second->rethrow();
- } else {
- StringSet failedPaths;
- for (; failedResult != failed.end(); failedResult++) {
- if (!failedResult->second->errorMsg.empty()) {
- logError(
- ErrorInfo{
- .level = lvlError,
- .msg = failedResult->second->errorMsg,
- });
+ // Then cancelled builds.
+ for (auto & buildResult : buildResults) {
+ if (auto failure = std::get_if(&buildResult.result)) {
+ if (failure->isCancelled())
+ notice(
+ "❓ " ANSI_BOLD "%s" ANSI_NORMAL ANSI_FAINT " (cancelled)",
+ buildResult.installable->what());
+ }
+ }
+
+ // Then failures.
+ for (auto & buildResult : buildResults) {
+ if (auto failure = std::get_if(&buildResult.result)) {
+ if (failure->isCancelled())
+ continue;
+ auto failure2 = failure->tryGetFailure();
+ assert(failure2);
+ printError("❌ " ANSI_RED "%s" ANSI_NORMAL, buildResult.installable->what());
+ try {
+ failure2->rethrow();
+ } catch (Error & e) {
+ logError(e.info());
+ }
}
- failedPaths.insert(failedResult->first->path.to_string(store));
}
- throw Error("build of %s failed", concatStringsSep(", ", quoteStrings(failedPaths)));
+
+ throw Exit(1);
}
}
}
-std::vector, BuiltPathWithResult>> Installable::build2(
+std::vector Installable::build(
+ ref evalStore, ref store, Realise mode, const Installables & installables, BuildMode bMode)
+{
+ auto results = build2(evalStore, store, mode, installables, bMode);
+ throwBuildErrors(results, *store);
+ std::vector res;
+ for (auto & b : results)
+ res.push_back(b.getSuccess());
+ return res;
+}
+
+std::vector Installable::build2(
ref evalStore, ref store, Realise mode, const Installables & installables, BuildMode bMode)
{
if (mode == Realise::Nothing)
@@ -615,7 +569,7 @@ std::vector, BuiltPathWithResult>> Installable::build
}
}
- std::vector, BuiltPathWithResult>> res;
+ std::vector res;
switch (mode) {
@@ -630,17 +584,21 @@ std::vector, BuiltPathWithResult>> Installable::build
[&](const DerivedPath::Built & bfd) {
auto outputs = resolveDerivedPath(*store, bfd, &*evalStore);
res.push_back(
- {aux.installable,
- {.path =
- BuiltPath::Built{
- .drvPath =
- make_ref(getBuiltPath(evalStore, store, *bfd.drvPath)),
- .outputs = outputs,
- },
- .info = aux.info}});
+ {.installable = aux.installable,
+ .result = InstallableWithBuildResult::Success{
+ .path =
+ BuiltPath::Built{
+ .drvPath = make_ref(
+ getBuiltPath(evalStore, store, *bfd.drvPath)),
+ .outputs = outputs,
+ },
+ .info = aux.info}});
},
[&](const DerivedPath::Opaque & bo) {
- res.push_back({aux.installable, {.path = BuiltPath::Opaque{bo.path}, .info = aux.info}});
+ res.push_back(
+ {.installable = aux.installable,
+ .result = InstallableWithBuildResult::Success{
+ .path = BuiltPath::Opaque{bo.path}, .info = aux.info}});
},
},
path.raw());
@@ -654,9 +612,13 @@ std::vector, BuiltPathWithResult>> Installable::build
printMissing(store, pathsToBuild, lvlInfo);
auto buildResults = store->buildPathsWithResults(pathsToBuild, bMode, evalStore);
- throwBuildErrors(buildResults, *store);
for (auto & buildResult : buildResults) {
- // If we didn't throw, they must all be sucesses
+ if (buildResult.tryGetFailure()) {
+ for (auto & aux : backmap[buildResult.path]) {
+ res.push_back({.installable = aux.installable, .result = buildResult});
+ }
+ continue;
+ }
auto & success = std::get(buildResult.inner);
for (auto & aux : backmap[buildResult.path]) {
std::visit(
@@ -666,20 +628,22 @@ std::vector, BuiltPathWithResult>> Installable::build
for (auto & [outputName, realisation] : success.builtOutputs)
outputs.emplace(outputName, realisation.outPath);
res.push_back(
- {aux.installable,
- {.path =
- BuiltPath::Built{
- .drvPath =
- make_ref(getBuiltPath(evalStore, store, *bfd.drvPath)),
- .outputs = outputs,
- },
- .info = aux.info,
- .result = buildResult}});
+ {.installable = aux.installable,
+ .result = InstallableWithBuildResult::Success{
+ .path =
+ BuiltPath::Built{
+ .drvPath = make_ref(
+ getBuiltPath(evalStore, store, *bfd.drvPath)),
+ .outputs = outputs,
+ },
+ .info = aux.info,
+ .result = buildResult}});
},
[&](const DerivedPath::Opaque & bo) {
res.push_back(
- {aux.installable,
- {.path = BuiltPath::Opaque{bo.path}, .info = aux.info, .result = buildResult}});
+ {.installable = aux.installable,
+ .result = InstallableWithBuildResult::Success{
+ .path = BuiltPath::Opaque{bo.path}, .info = aux.info, .result = buildResult}});
},
},
buildResult.path.raw());
@@ -840,8 +804,11 @@ InstallableCommand::InstallableCommand()
});
}
+void InstallableCommand::preRun(ref store) {}
+
void InstallableCommand::run(ref store)
{
+ preRun(store);
auto installable = parseInstallable(store, _installable);
run(store, std::move(installable));
}
diff --git a/src/libcmd/meson.build b/src/libcmd/meson.build
index f553afa0ba17..087da84f9293 100644
--- a/src/libcmd/meson.build
+++ b/src/libcmd/meson.build
@@ -67,6 +67,7 @@ config_priv_h = configure_file(
)
subdir('nix-meson-build-support/common')
+subdir('nix-meson-build-support/generate-header')
sources = files(
'built-path.cc',
@@ -74,6 +75,7 @@ sources = files(
'command.cc',
'common-eval-args.cc',
'editor-for.cc',
+ 'flake-schemas.cc',
'installable-attr-path.cc',
'installable-derived-path.cc',
'installable-flake.cc',
@@ -86,6 +88,11 @@ sources = files(
'repl.cc',
)
+sources += [
+ gen_header.process('call-flake-schemas.nix'),
+ gen_header.process('builtin-flake-schemas.nix'),
+]
+
subdir('include/nix/cmd')
subdir('nix-meson-build-support/export-all-symbols')
@@ -99,7 +106,7 @@ this_library = library(
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args : linker_export_flags,
- prelink : true, # For C++ static initializers
+ prelink : prelink, # For C++ static initializers
install : true,
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [],
)
diff --git a/src/libcmd/package.nix b/src/libcmd/package.nix
index c382f0e5760d..1d677142da1d 100644
--- a/src/libcmd/package.nix
+++ b/src/libcmd/package.nix
@@ -35,7 +35,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-cmd";
+ pname = "determinate-nix-cmd";
inherit version;
workDir = ./.;
@@ -49,6 +49,8 @@ mkMesonLibrary (finalAttrs: {
./include/nix/cmd/meson.build
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
+ ./call-flake-schemas.nix
+ ./builtin-flake-schemas.nix
];
buildInputs = [
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 8fbb54dd30de..d8e61b5b5205 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -177,7 +177,7 @@ ReplExitStatus NixRepl::mainLoop()
if (state->debugRepl) {
debuggerNotice = " debugger";
}
- notice("Nix %1%%2%\nType :? for help.", nixVersion, debuggerNotice);
+ notice("Nix %s\nType :? for help.", version(), debuggerNotice);
}
isFirstRepl = false;
@@ -332,6 +332,7 @@ StorePath NixRepl::getDerivationPath(Value & v)
auto drvPath = packageInfo->queryDrvPath();
if (!drvPath)
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
+ state->waitForPath(*drvPath);
if (!state->store->isValidPath(*drvPath))
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
return *drvPath;
diff --git a/src/libexpr-c/meson.build b/src/libexpr-c/meson.build
index c47704ce4112..df1e3c05880c 100644
--- a/src/libexpr-c/meson.build
+++ b/src/libexpr-c/meson.build
@@ -54,7 +54,7 @@ this_library = library(
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args : linker_export_flags,
- prelink : true, # For C++ static initializers
+ prelink : prelink, # For C++ static initializers
install : true,
)
diff --git a/src/libexpr-c/nix_api_expr.cc b/src/libexpr-c/nix_api_expr.cc
index 0dd9fa0a51d8..bfbd0a9c361f 100644
--- a/src/libexpr-c/nix_api_expr.cc
+++ b/src/libexpr-c/nix_api_expr.cc
@@ -71,6 +71,7 @@ nix_err nix_expr_eval_from_string(
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
state->state.eval(parsedExpr, *value->value);
state->state.forceValue(*value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -82,6 +83,7 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n
try {
state->state.callFunction(*fn->value, *arg->value, *value->value, nix::noPos);
state->state.forceValue(*value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -100,6 +102,7 @@ nix_err nix_value_call_multi(
try {
state->state.callFunction(*fn->value, {internal_args.data(), nargs}, *value->value, nix::noPos);
state->state.forceValue(*value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -110,6 +113,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value *
context->last_err_code = NIX_OK;
try {
state->state.forceValue(*value->value, nix::noPos);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
@@ -120,6 +124,7 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
context->last_err_code = NIX_OK;
try {
state->state.forceValueDeep(*value->value);
+ state->state.waitForAllPaths();
}
NIXC_CATCH_ERRS
}
diff --git a/src/libexpr-c/nix_api_value.cc b/src/libexpr-c/nix_api_value.cc
index 7fd8233adec2..b6a838284eff 100644
--- a/src/libexpr-c/nix_api_value.cc
+++ b/src/libexpr-c/nix_api_value.cc
@@ -194,6 +194,8 @@ ValueType nix_get_type(nix_c_context * context, const nix_value * value)
switch (v.type()) {
case nThunk:
return NIX_TYPE_THUNK;
+ case nFailed:
+ return NIX_TYPE_FAILED;
case nInt:
return NIX_TYPE_INT;
case nFloat:
@@ -386,6 +388,7 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
auto attr = v.attrs()->get(s);
if (attr) {
state->state.forceValue(*attr->value, nix::noPos);
+ state->state.waitForAllPaths();
return new_nix_value(attr->value, state->state.mem);
}
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
diff --git a/src/libexpr-c/nix_api_value.h b/src/libexpr-c/nix_api_value.h
index 5bd45da9059d..a01bfb280599 100644
--- a/src/libexpr-c/nix_api_value.h
+++ b/src/libexpr-c/nix_api_value.h
@@ -100,7 +100,10 @@ typedef enum {
/** @brief External value from C++ plugins or C API
* @see Externals
*/
- NIX_TYPE_EXTERNAL
+ NIX_TYPE_EXTERNAL,
+ /** @brief Failed value. Contains an exception that can be rethrown.
+ */
+ NIX_TYPE_FAILED,
} ValueType;
// forward declarations
diff --git a/src/libexpr-c/package.nix b/src/libexpr-c/package.nix
index 694fbc1fe789..ec92ecce1054 100644
--- a/src/libexpr-c/package.nix
+++ b/src/libexpr-c/package.nix
@@ -15,7 +15,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-expr-c";
+ pname = "determinate-nix-expr-c";
inherit version;
workDir = ./.;
diff --git a/src/libexpr-test-support/include/nix/expr/tests/value/context.hh b/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
index 68a0b8dea7d7..2311f3941c13 100644
--- a/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
+++ b/src/libexpr-test-support/include/nix/expr/tests/value/context.hh
@@ -26,6 +26,12 @@ struct Arbitrary
static Gen arbitrary();
};
+template<>
+struct Arbitrary
+{
+ static Gen arbitrary();
+};
+
template<>
struct Arbitrary
{
diff --git a/src/libexpr-test-support/meson.build b/src/libexpr-test-support/meson.build
index df28661b7e78..0fae96b47f1e 100644
--- a/src/libexpr-test-support/meson.build
+++ b/src/libexpr-test-support/meson.build
@@ -50,7 +50,7 @@ this_library = library(
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
# is available. See also ../libutil/build.meson
link_args : linker_export_flags + [ '-lrapidcheck' ],
- prelink : true, # For C++ static initializers
+ prelink : prelink, # For C++ static initializers
install : true,
)
diff --git a/src/libexpr-test-support/package.nix b/src/libexpr-test-support/package.nix
index 5cb4adaa8c46..1879a5716082 100644
--- a/src/libexpr-test-support/package.nix
+++ b/src/libexpr-test-support/package.nix
@@ -18,7 +18,7 @@ let
in
mkMesonLibrary (finalAttrs: {
- pname = "nix-util-test-support";
+ pname = "determinate-nix-util-test-support";
inherit version;
workDir = ./.;
diff --git a/src/libexpr-test-support/tests/value/context.cc b/src/libexpr-test-support/tests/value/context.cc
index d6036601a948..8ce84fb51f54 100644
--- a/src/libexpr-test-support/tests/value/context.cc
+++ b/src/libexpr-test-support/tests/value/context.cc
@@ -16,6 +16,15 @@ Gen Arbitrary::arb
});
}
+Gen Arbitrary::arbitrary()
+{
+ return gen::map(gen::arbitrary(), [](StorePath storePath) {
+ return NixStringContextElem::Path{
+ .storePath = storePath,
+ };
+ });
+}
+
Gen Arbitrary::arbitrary()
{
return gen::mapcat(
@@ -31,6 +40,8 @@ Gen Arbitrary::arbitrary()
case 2:
return gen::map(
gen::arbitrary(), [](NixStringContextElem a) { return a; });
+ case 3:
+ return gen::map(gen::arbitrary(), [](NixStringContextElem a) { return a; });
default:
assert(false);
}
diff --git a/src/libexpr-tests/value/value.cc b/src/libexpr-tests/value/value.cc
index 420db0f31b17..bd8f0da71213 100644
--- a/src/libexpr-tests/value/value.cc
+++ b/src/libexpr-tests/value/value.cc
@@ -13,7 +13,6 @@ TEST_F(ValueTest, unsetValue)
{
Value unsetValue;
ASSERT_EQ(false, unsetValue.isValid());
- ASSERT_EQ(nThunk, unsetValue.type(true));
ASSERT_DEATH(unsetValue.type(), "");
}
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index 575a135422ab..c8b800245881 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -39,6 +39,14 @@ AttrPath AttrPath::parse(EvalState & state, std::string_view s)
return res;
}
+AttrPath AttrPath::fromStrings(EvalState & state, const std::vector & attrNames)
+{
+ AttrPath res;
+ for (auto & attrName : attrNames)
+ res.push_back(state.symbols.create(attrName));
+ return res;
+}
+
std::string AttrPath::to_string(EvalState & state) const
{
return dropEmptyInitThenConcatStringsSep(".", state.symbols.resolve({*this}));
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index 43f10da6eac9..0d6bbdaf4839 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -364,23 +364,33 @@ void AttrCursor::fetchCachedValue()
throw CachedEvalError(parent->first, parent->second);
}
-AttrPath AttrCursor::getAttrPath() const
+AttrPath AttrCursor::getAttrPathRaw() const
{
if (parent) {
- auto attrPath = parent->first->getAttrPath();
+ auto attrPath = parent->first->getAttrPathRaw();
attrPath.push_back(parent->second);
return attrPath;
} else
return {};
}
-AttrPath AttrCursor::getAttrPath(Symbol name) const
+AttrPath AttrCursor::getAttrPath() const
+{
+ return root->cleanupAttrPath(getAttrPathRaw());
+}
+
+AttrPath AttrCursor::getAttrPathRaw(Symbol name) const
{
- auto attrPath = getAttrPath();
+ auto attrPath = getAttrPathRaw();
attrPath.push_back(name);
return attrPath;
}
+AttrPath AttrCursor::getAttrPath(Symbol name) const
+{
+ return root->cleanupAttrPath(getAttrPathRaw(name));
+}
+
std::string AttrCursor::getAttrPathStr() const
{
return getAttrPath().to_string(root->state);
@@ -554,16 +564,17 @@ string_t AttrCursor::getStringWithContext()
if (auto s = std::get_if(&cachedValue->second)) {
bool valid = true;
for (auto & c : s->second) {
- const StorePath & path = std::visit(
+ const StorePath * path = std::visit(
overloaded{
- [&](const NixStringContextElem::DrvDeep & d) -> const StorePath & { return d.drvPath; },
- [&](const NixStringContextElem::Built & b) -> const StorePath & {
- return b.drvPath->getBaseStorePath();
+ [&](const NixStringContextElem::DrvDeep & d) -> const StorePath * { return &d.drvPath; },
+ [&](const NixStringContextElem::Built & b) -> const StorePath * {
+ return &b.drvPath->getBaseStorePath();
},
- [&](const NixStringContextElem::Opaque & o) -> const StorePath & { return o.path; },
+ [&](const NixStringContextElem::Opaque & o) -> const StorePath * { return &o.path; },
+ [&](const NixStringContextElem::Path & p) -> const StorePath * { return nullptr; },
},
c.raw);
- if (!root->state.store->isValidPath(path)) {
+ if (!path || !root->state.store->isValidPath(*path)) {
valid = false;
break;
}
@@ -711,6 +722,7 @@ StorePath AttrCursor::forceDerivation()
/* The eval cache contains 'drvPath', but the actual path has
been garbage-collected. So force it to be regenerated. */
aDrvPath->forceValue();
+ root->state.waitForPath(drvPath);
if (!root->state.store->isValidPath(drvPath))
throw Error(
"don't know how to recreate store derivation '%s'!", root->state.store->printStorePath(drvPath));
diff --git a/src/libexpr/eval-gc.cc b/src/libexpr/eval-gc.cc
index 0d25f38f64de..c1e974e053b8 100644
--- a/src/libexpr/eval-gc.cc
+++ b/src/libexpr/eval-gc.cc
@@ -46,6 +46,88 @@ static void * oomHandler(size_t requested)
throw std::bad_alloc();
}
+static size_t getFreeMem()
+{
+ /* On Linux, use the `MemAvailable` or `MemFree` fields from
+ /proc/cpuinfo. */
+# ifdef __linux__
+ {
+ std::unordered_map fields;
+ for (auto & line :
+ tokenizeString>(readFile(std::filesystem::path("/proc/meminfo")), "\n")) {
+ auto colon = line.find(':');
+ if (colon == line.npos)
+ continue;
+ fields.emplace(line.substr(0, colon), trim(line.substr(colon + 1)));
+ }
+
+ auto i = fields.find("MemAvailable");
+ if (i == fields.end())
+ i = fields.find("MemFree");
+ if (i != fields.end()) {
+ auto kb = tokenizeString>(i->second, " ");
+ if (kb.size() == 2 && kb[1] == "kB")
+ return string2Int(kb[0]).value_or(0) * 1024;
+ }
+ }
+# endif
+
+ /* On non-Linux systems, conservatively assume that 25% of memory is free. */
+ long pageSize = sysconf(_SC_PAGESIZE);
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pageSize > 0 && pages > 0)
+ return (static_cast(pageSize) * static_cast(pages)) / 4;
+ return 0;
+}
+
+/**
+ * When a thread goes into a coroutine, we lose its original sp until
+ * control flow returns to the thread. This causes Boehm GC to crash
+ * since it will scan memory between the coroutine's sp and the
+ * original stack base of the thread. Therefore, we detect when the
+ * current sp is outside of the original thread stack and push the
+ * entire thread stack instead, as an approximation.
+ *
+ * This is not optimal, because it causes the stack below sp to be
+ * scanned. However, we usually we don't have active coroutines during
+ * evaluation, so this is acceptable.
+ *
+ * Note that we don't scan coroutine stacks. It's currently assumed
+ * that we don't have GC roots in coroutines.
+ */
+void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
+{
+ void *& sp = *sp_ptr;
+ auto pthread_id = reinterpret_cast(_pthread_id);
+ size_t osStackSize;
+ char * osStackHi;
+ char * osStackLo;
+
+# ifdef __APPLE__
+ osStackSize = pthread_get_stacksize_np(pthread_id);
+ osStackHi = (char *) pthread_get_stackaddr_np(pthread_id);
+ osStackLo = osStackHi - osStackSize;
+# else
+ pthread_attr_t pattr;
+ if (pthread_attr_init(&pattr))
+ throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
+# ifdef HAVE_PTHREAD_GETATTR_NP
+ if (pthread_getattr_np(pthread_id, &pattr))
+ throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
+# else
+# error "Need `pthread_attr_get_np`"
+# endif
+ if (pthread_attr_getstack(&pattr, (void **) &osStackLo, &osStackSize))
+ throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
+ if (pthread_attr_destroy(&pattr))
+ throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
+ osStackHi = osStackLo + osStackSize;
+# endif
+
+ if (sp >= osStackHi || sp < osStackLo) // sp is outside the os stack
+ sp = osStackLo;
+}
+
static inline void initGCReal()
{
/* Initialise the Boehm garbage collector. */
@@ -76,8 +158,11 @@ static inline void initGCReal()
GC_set_oom_fn(oomHandler);
- /* Set the initial heap size to something fairly big (25% of
- physical RAM, up to a maximum of 384 MiB) so that in most cases
+ GC_set_sp_corrector(&fixupBoehmStackPointer);
+ assert(GC_get_sp_corrector());
+
+ /* Set the initial heap size to something fairly big (80% of
+ free RAM, up to a maximum of 4 GiB) so that in most cases
we don't need to garbage collect at all. (Collection has a
fairly significant overhead.) The heap size can be overridden
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
@@ -88,15 +173,10 @@ static inline void initGCReal()
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
size_t size = 32 * 1024 * 1024;
# if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
- size_t maxSize = 384 * 1024 * 1024;
- long pageSize = sysconf(_SC_PAGESIZE);
- long pages = sysconf(_SC_PHYS_PAGES);
- if (pageSize != -1)
- size = (pageSize * pages) / 4; // 25% of RAM
- if (size > maxSize)
- size = maxSize;
+ size_t maxSize = 4ULL * 1024 * 1024 * 1024;
+ auto free = getFreeMem();
+ size = std::max(size, std::min((size_t) (free * 0.5), maxSize));
# endif
- debug("setting initial heap size to %1% bytes", size);
GC_expand_hp(size);
}
}
diff --git a/src/libexpr/eval-profiler.cc b/src/libexpr/eval-profiler.cc
index e9dc1e021eac..21d2d3f8f4d9 100644
--- a/src/libexpr/eval-profiler.cc
+++ b/src/libexpr/eval-profiler.cc
@@ -165,6 +165,7 @@ class SampleStack : public EvalProfiler
EvalState & state;
std::chrono::nanoseconds sampleInterval;
AutoCloseFD profileFd;
+ // FIXME: this needs to become per-thread to support multi-threaded evaluation.
FrameStack stack;
std::map callCount;
std::chrono::time_point lastStackSample =
diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc
index 04c6193885e1..27205864b8ba 100644
--- a/src/libexpr/eval-settings.cc
+++ b/src/libexpr/eval-settings.cc
@@ -91,9 +91,19 @@ bool EvalSettings::isPseudoUrl(std::string_view s)
std::string EvalSettings::resolvePseudoUrl(std::string_view url)
{
- if (hasPrefix(url, "channel:"))
- return "https://channels.nixos.org/" + std::string(url.substr(8)) + "/nixexprs.tar.xz";
- else
+ if (hasPrefix(url, "channel:")) {
+ auto realUrl = "https://channels.nixos.org/" + std::string(url.substr(8)) + "/nixexprs.tar.xz";
+ static bool haveWarned = false;
+ warnOnce(
+ haveWarned,
+ "Channels are deprecated in favor of flakes in Determinate Nix. "
+ "Instead of '%s', use '%s'. "
+ "See https://zero-to-nix.com for a guide to Nix flakes. "
+ "For details and to offer feedback on the deprecation process, see: https://github.com/DeterminateSystems/nix-src/issues/34.",
+ url,
+ realUrl);
+ return realUrl;
+ } else
return std::string(url);
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index ab3f7b3ff5da..9402a41331de 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -25,6 +25,8 @@
#include "nix/fetchers/tarball.hh"
#include "nix/fetchers/input-cache.hh"
#include "nix/util/current-process.hh"
+#include "nix/store/async-path-writer.hh"
+#include "nix/expr/parallel-eval.hh"
#include "parser-tab.hh"
@@ -44,6 +46,11 @@
#include
#include
#include
+#include
+
+#ifndef _WIN32 // TODO use portable implementation
+# include
+#endif
#include "nix/util/strings-inline.hh"
@@ -155,6 +162,8 @@ std::string_view showType(ValueType type, bool withArticle)
return WA("a", "float");
case nThunk:
return WA("a", "thunk");
+ case nFailed:
+ return WA("a", "failure");
}
unreachable();
}
@@ -193,20 +202,36 @@ PosIdx Value::determinePos(const PosIdx pos) const
return attrs()->pos;
case tLambda:
return lambda().fun->pos;
+#if 0
+ // FIXME: disabled because reading from an app is racy.
case tApp:
return app().left->determinePos(pos);
+#endif
default:
return pos;
}
#pragma GCC diagnostic pop
}
-bool Value::isTrivial() const
+template<>
+bool ValueStorage::isTrivial() const
{
- return !isa()
- && (!isa()
- || (dynamic_cast(thunk().expr) && ((ExprAttrs *) thunk().expr)->dynamicAttrs->empty())
- || dynamic_cast(thunk().expr) || dynamic_cast(thunk().expr));
+ auto p1_ = p1; // must acquire before reading p0, since thunks can change
+ auto p0_ = p0.load(std::memory_order_acquire);
+
+ auto pd = static_cast(p0_ & discriminatorMask);
+
+ if (pd == pdThunk || pd == pdPending || pd == pdAwaited) {
+ bool isApp = p1_ & discriminatorMask;
+ if (isApp)
+ return false;
+ auto expr = untagPointer]