Compare commits

...

107 Commits

Author SHA1 Message Date
Eelco Dolstra
6c7215b278 Merge remote-tracking branch 'cve/fod-cves-2.28' into 2.28-maintenance 2025-06-24 16:06:10 +02:00
mergify[bot]
983d3922ff Merge pull request #13391 from NixOS/mergify/bp/2.28-maintenance/pr-13348
Make the repl test more robust (backport #13348)
2025-06-22 19:38:47 +00:00
Eelco Dolstra
37fe2584c1 Make the repl test more robust
Seen in https://github.com/DeterminateSystems/nix-src/actions/runs/15590867877/job/43909540271:

  nix-functional-tests> grep: repl_output: No such file or directory
  nix-functional-tests> +(repl.sh:174) cat repl_output

This is because there is a small possibility that the `nix repl` child
process hasn't created `repl_output` yet. So make sure it exists.

(cherry picked from commit 9eb46e9cc0)
2025-06-22 19:08:35 +00:00
Eelco Dolstra
24c1aa735a Fixes for GHSA-g948-229j-48j3
Squashed commit of the following:

commit 04fff3a637d455cbb1d75937a235950e43008db9
Author: Eelco Dolstra <edolstra@gmail.com>
Date:   Thu Jun 12 12:30:32 2025 +0200

    Chown structured attr files safely

commit 5417ad445e414c649d0cfc71a05661c7bf8f3ef5
Author: Eelco Dolstra <edolstra@gmail.com>
Date:   Thu Jun 12 12:14:04 2025 +0200

    Replace 'bool sync' with an enum for clarity

    And drop writeFileAndSync().

commit 7ae0141f328d8e8e1094be24665789c05f974ba6
Author: Eelco Dolstra <edolstra@gmail.com>
Date:   Thu Jun 12 11:35:28 2025 +0200

    Drop guessOrInventPathFromFD()

    No need to do hacky stuff like that when we already know the original path.

commit 45b05098bd019da7c57cd4227a89bfd0fa65bb08
Author: Eelco Dolstra <edolstra@gmail.com>
Date:   Thu Jun 12 11:15:58 2025 +0200

    Tweak comment

commit 0af15b31209d1b7ec8addfae9a1a6b60d8f35848
Author: Raito Bezarius <raito@lix.systems>
Date:   Thu Mar 27 12:22:26 2025 +0100

    libstore: ensure that temporary directory is always 0o000 before deletion

    In the case the deletion fails, we should ensure that the temporary
    directory cannot be used for nefarious purposes.

    Change-Id: I498a2dd0999a74195d13642f44a5de1e69d46120
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit 2c20fa37b15cfa03ac6a1a6a47cdb2ed66c0827e
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 12:42:55 2025 +0100

    libutil: ensure that `_deletePath` does NOT use absolute paths with dirfds

    When calling `_deletePath` with a parent file descriptor, `openat` is
    made effective by using relative paths to the directory file descriptor.

    To avoid the problem, the signature is changed to resist misuse with an
    assert in the prologue of the function.

    Change-Id: I6b3fc766bad2afe54dc27d47d1df3873e188de96
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit d3c370bbcae48bb825ce19fd0f73bb4eefd2c9ea
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 01:07:47 2025 +0100

    libstore: ensure that `passAsFile` is created in the original temp dir

    This ensures that `passAsFile` data is created inside the expected
    temporary build directory by `openat()` from the parent directory file
    descriptor.

    This avoids a TOCTOU which is part of the attack chain of CVE-????.

    Change-Id: Ie5273446c4a19403088d0389ae8e3f473af8879a
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit 45d3598724f932d024ef6bc2ffb00c1bb90e6018
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 01:06:03 2025 +0100

    libutil: writeFile variant for file descriptors

    `writeFile` lose its `sync` boolean flag to make things simpler.

    A new `writeFileAndSync` function is created and all call sites are
    converted to it.

    Change-Id: Ib871a5283a9c047db1e4fe48a241506e4aab9192
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit 732bd9b98cabf4aaf95a01fd318923de303f9996
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 01:05:34 2025 +0100

    libstore: chown to builder variant for file descriptors

    We use it immediately for the build temporary directory.

    Change-Id: I180193c63a2b98721f5fb8e542c4e39c099bb947
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit 962c65f8dcd5570dd92c72370a862c7b38942e0d
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 01:04:59 2025 +0100

    libstore: open build directory as a dirfd as well

    We now keep around a proper AutoCloseFD around the temporary directory
    which we plan to use for openat operations and avoiding the build
    directory being swapped out while we are doing something else.

    Change-Id: I18d387b0f123ebf2d20c6405cd47ebadc5505f2a
    Signed-off-by: Raito Bezarius <raito@lix.systems>

commit c9b42462b75b5a37ee6564c2b53cff186c8323da
Author: Raito Bezarius <raito@lix.systems>
Date:   Wed Mar 26 01:04:12 2025 +0100

    libutil: guess or invent a path from file descriptors

    This is useful for certain error recovery paths (no pun intended) that
    does not thread through the original path name.

    Change-Id: I2d800740cb4f9912e64c923120d3f977c58ccb7e
    Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-19 16:40:11 +02:00
Jörg Thalheim
c6d7a1bb42 Merge pull request #13379 from NixOS/mergify/bp/2.28-maintenance/pr-13376
Revert "Drop magic-nix-cache" (backport #13376)
2025-06-19 16:37:48 +02:00
Eelco Dolstra
d3840a1472 Revert "Drop magic-nix-cache"
This reverts commit 9cc8be2674 since
magic-nix-cache works again (thanks @jchv).

(cherry picked from commit 9b57573bae)
2025-06-19 12:12:28 +00:00
Jörg Thalheim
aee067f539 Merge pull request #13329 from NixOS/mergify/bp/2.28-maintenance/pr-13284
lockFlake(): Allow registry lookups for overridden inputs (backport #13284)
2025-06-11 07:25:42 +02:00
Seth Flynn
6f4c2a0a3b lockFlake(): Allow registry lookups for overridden inputs
Fixes #13144

(cherry picked from commit d0a2323829)

Co-authored-by: bryango <bryango@users.noreply.github.com>
2025-06-11 06:53:31 +02:00
mergify[bot]
f3c10d8c6f Merge pull request #13318 from NixOS/mergify/bp/2.28-maintenance/pr-13274
Drop magic-nix-cache (backport #13274)
2025-06-03 14:53:18 +00:00
Eelco Dolstra
ddec59e694 Drop magic-nix-cache
This no longer works, see https://determinate.systems/posts/magic-nix-cache-free-tier-eol/.

(cherry picked from commit 9cc8be2674)
2025-06-03 14:18:50 +00:00
John Ericson
ac328b88d8 Merge pull request #13217 from NixOS/mergify/bp/2.28-maintenance/pr-13212
docs: remove repeated "allowedReferences" and other lexical illusion (backport #13212)
2025-05-16 12:22:08 -04:00
Peder Bergebakken Sundt
a7588b47f2 docs: remove lexical illusions detected with write-good
I made this this non-markdown aware tool somewhat behave with some cursed fd+pandoc invocations

(cherry picked from commit ea5302c4a2)
2025-05-16 15:56:25 +00:00
Peder Bergebakken Sundt
d1e397d2a5 docs: remove repeated "allowedReferences"
This is what write-good lints as a "lexical illusion"

(cherry picked from commit cb16cd707c)
2025-05-16 15:56:25 +00:00
mergify[bot]
a3e6953c71 Merge pull request #13209 from NixOS/mergify/bp/2.28-maintenance/pr-13207
dev-shell: Drop bear dependency (backport #13207)
2025-05-15 22:15:36 +00:00
Sergei Zimmerman
4168ee57ec dev-shell: Drop bear dependency
Since the autotools-based build system has been removed
and meson already generates compile database there's no
need to have it in the devshell.

(cherry picked from commit 67535263a5)
2025-05-15 21:49:11 +00:00
John Ericson
c4d6c6a3ca Merge pull request #13191 from NixOS/mergify/bp/2.28-maintenance/pr-12977
Docs: fix "building" documentation w.r.t. meson (backport #12977)
2025-05-14 18:15:29 -04:00
Jörg Thalheim
58c84bcf8a docs/building: fix attribute for nix-cli-ccacheStdenv
(cherry picked from commit c12fd7b319)
2025-05-14 17:27:02 -04:00
Jörg Thalheim
f8984c4182 docs: update cross compilation section from autotools to meson
fixes https://github.com/NixOS/nix/issues/12934

Update doc/manual/source/development/building.md

Co-authored-by: Eelco Dolstra <edolstra@gmail.com>

Update doc/manual/source/development/building.md

Co-authored-by: John Ericson <git@JohnEricson.me>
(cherry picked from commit 723f2c7352)
2025-05-14 17:27:02 -04:00
Jörg Thalheim
8f5172d026 fix various typos in docs
(cherry picked from commit a70140b55a)
2025-05-14 17:26:55 -04:00
mergify[bot]
47ba78d251 Merge pull request #13187 from NixOS/mergify/bp/2.28-maintenance/pr-13178
docs: Fix miscellaneous typos and formatting issues (backport #13178)
2025-05-14 19:51:10 +00:00
Sergei Zimmerman
b4bfe15559 docs: Fix miscellaneous typos and formatting issues
(cherry picked from commit 20a724d131)
2025-05-14 19:10:59 +00:00
Jörg Thalheim
2e31ed2f19 Merge pull request #13185 from NixOS/mergify/bp/2.28-maintenance/pr-13180
nix repl: remember :load-flake calls for :reload (backport #13180)
2025-05-14 21:09:48 +02:00
Tim Van Baak
0acb13b7fe nix repl: remember :load-flake calls for :reload
Fixes #8753

(cherry picked from commit fb510a9e50)
2025-05-14 18:36:56 +00:00
Eelco Dolstra
c0cef69790 Merge pull request #13172 from NixOS/mergify/bp/2.28-maintenance/pr-13159
Avoid unnecessarily updating old lock files with 'dir' parameters (backport #13159)
2025-05-13 08:31:17 +02:00
Eelco Dolstra
79eed1d9c4 Backward compatibility hack for dealing with dir in URL-style flakerefs
(cherry picked from commit d00682beb2)
2025-05-12 20:35:46 +00:00
mergify[bot]
9fd0cd8ed0 Merge pull request #13133 from NixOS/mergify/bp/2.28-maintenance/pr-13121
fix: allow redirected HTTP uploads (backport #13121)
2025-05-03 08:50:24 +00:00
Jörg Thalheim
68fd62b1fb Merge pull request #13132 from NixOS/mergify/bp/2.28-maintenance/pr-13122
Replace all instances of std::filesystem::directory_iterator with DirectoryIterator (backport #13122)
2025-05-03 09:46:57 +02:00
Thomas Bereknyei
f9dd4e5605 fix: allow redirected HTTP uploads
When a PUT is redirected, some of the data can be sent by curl before headers are read. This means the subsequent PUT operation needs to seek back to origin.

(cherry picked from commit 90deb665eb)
2025-05-03 07:34:43 +00:00
Jörg Thalheim
3d8d19928e replace all instances of std::filesystem::directory_iterator with DirectoryIterator
(cherry picked from commit 1c4496f4e5)
2025-05-03 09:07:00 +02:00
Jörg Thalheim
0f4b17e51f add DirectoryIterator to re-throw std::filesystem::filesystem_error
Co-authored-by: Sergei Zimmerman <145775305+xokdvium@users.noreply.github.com>
(cherry picked from commit 7ccc0d591f)
2025-05-03 09:06:56 +02:00
mergify[bot]
8de4c272dc Merge pull request #13124 from NixOS/mergify/bp/2.28-maintenance/pr-13014
Update `nix fmt` man page with official formatter example (backport #13014)
2025-05-01 13:45:45 +00:00
Jeremy Fleischman
6ba4b1d252 Update nix fmt man page with official formatter example
The current example relies upon [nixfmt's deprecated tree traversal
behavior](https://github.com/NixOS/nixfmt/pull/240). The simplest
alternative is the new `nixfmt-tree` wrapper for `nixfmt`/`treefmt`.

(cherry picked from commit 6f71d8a9c2)
2025-05-01 13:11:54 +00:00
Jörg Thalheim
bf0f35ec69 Merge pull request #13110 from NixOS/mergify/bp/2.28-maintenance/pr-13109
libutil: amend OSC 8 escape stripping for xterm-style separator (backport #13109)
2025-05-01 08:11:47 +02:00
mergify[bot]
ff6e0f5228 Merge pull request #13118 from NixOS/mergify/bp/2.28-maintenance/pr-13112
bugfix in getInteger(const nlohmann::json &) and add bounds checks (backport #13112)
2025-04-30 22:01:31 +00:00
Philipp Otterbein
60a6baa2d7 bugfix in getInteger(const nlohmann::json &) and add bounds checks
improve error messages, too

(cherry picked from commit 788be3f964)
2025-04-30 21:20:57 +00:00
Sergei Trofimovich
1e2e52b66a libutil: amend OSC 8 escape stripping for xterm-style separator
Before the change `nix` was stripping warning flags
reported by `gcc-14` too eagerly:

    $ nix build -f. texinfo4
    error: builder for '/nix/store/i9948l91s3df44ip5jlpp6imbrcs646x-texinfo-4.13a.drv' failed with exit code 2;
           last 25 log lines:
           >  1495 | info_tag (mbi_iterator_t iter, int handle, size_t *plen)
           >       |                                            ~~~~~~~~^~~~
           > window.c:1887:39: error: passing argument 4 of 'printed_representation' from incompatible pointer type []
           >  1887 |                                       &replen);
           >       |                                       ^~~~~~~
           >       |                                       |
           >       |                                       int *

After the change the compiler flag remains:

    $ ~/patched.nix build -f. texinfo4
    error: builder for '/nix/store/i9948l91s3df44ip5jlpp6imbrcs646x-texinfo-4.13a.drv' failed with exit code 2;
       last 25 log lines:
       >  1495 | info_tag (mbi_iterator_t iter, int handle, size_t *plen)
       >       |                                            ~~~~~~~~^~~~
       > window.c:1887:39: error: passing argument 4 of 'printed_representation' from incompatible pointer type [-Wincompatible-pointer-types]
       >  1887 |                                       &replen);
       >       |                                       ^~~~~~~
       >       |                                       |
       >       |                                       int *

Note the difference in flag rendering around the warning.

https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda has a
good sumamry of why it happens. Befomre the change `nix` was handling
just one form or URL separator:

    $ printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n'

Now it also handled another for (used by gcc-14`):

    printf '\e]8;;http://example.com\aThis is a link\e]8;;\a\n'

While at it fixed accumulation of trailing escape `\e\\` symbol.

(cherry picked from commit e322b714dc)
2025-04-29 20:40:34 +00:00
Eelco Dolstra
6b16f919da Bump version 2025-04-29 21:52:24 +02:00
Jörg Thalheim
4d4a91ab8d Merge pull request #13101 from NixOS/mergify/bp/2.28-maintenance/pr-13100
allocate SimpleLogger before forking (backport #13100)
2025-04-28 09:48:32 +02:00
Philipp Otterbein
9ba32a2981 allocate SimpleLogger before forking
(cherry picked from commit 4e95f662db)
2025-04-28 07:02:02 +00:00
mergify[bot]
323e840d17 Merge pull request #13097 from NixOS/mergify/bp/2.28-maintenance/pr-13094
libutil: Add missing format arguments to UsageError ctor (backport #13094)
2025-04-25 14:04:08 +00:00
Sergei Zimmerman
1c9e94789e libutil: Add missing format arguments to UsageError ctor
Once again found by an automated migration to `std::format`.
I've tested that boost::format works fine with `std::string_view`
arguments.

(cherry picked from commit 9fff868e39)
2025-04-25 13:22:58 +00:00
Eelco Dolstra
e20b0d7b29 Merge pull request #13090 from NixOS/mergify/bp/2.28-maintenance/pr-13082
Actually ignore system/user registries during locking (2nd attempt) (backport #13082)
2025-04-25 14:13:27 +02:00
Jörg Thalheim
709f05989d tests/flakes: add regression test for resolving user flakes
(cherry picked from commit 6405d6822d)
2025-04-25 13:32:13 +02:00
Eelco Dolstra
dfbb52e6bd lockFlake(): Allow registry lookups for the top-level flake
Fixes #13050.

(cherry picked from commit 68de26d38a)
2025-04-25 13:31:24 +02:00
mergify[bot]
5a7cdc4373 Merge pull request #13092 from NixOS/mergify/bp/2.28-maintenance/pr-13086
libutil: Fix invalid boost format string in infinite symlink recursion error (backport #13086)
2025-04-25 10:48:47 +00:00
mergify[bot]
357a0f639c Merge pull request #13089 from NixOS/mergify/bp/2.28-maintenance/pr-13087
libutil: Use correct argument to Error format ctor (backport #13087)
2025-04-25 10:01:27 +00:00
Sergei Zimmerman
10350537b1 libutil: Fix invalid boost format string in infinite symlink recursion error
Found while working on an automated migration to `std::format`.

(cherry picked from commit bfb357c40b)
2025-04-25 09:21:22 +00:00
Sergei Zimmerman
b179259d6f libutil: Use correct argument to Error format ctor
It seems that the intention was to format a number in base 8 (as
suggested by the %o format specifier), but `perms` is a `std::string`
and not a number. Looks like `rawMode` is the correct thing to use here.

(cherry picked from commit 1b5c8aac12)
2025-04-25 09:19:52 +00:00
mergify[bot]
3019007eb5 Merge pull request #13083 from NixOS/mergify/bp/2.28-maintenance/pr-13079
nix-cli: restore binary-dist artifact to Hydra static builds (backport #13079)
2025-04-24 18:03:30 +00:00
Cole Helbling
6390b8b7cf nix-cli: restore binary-dist artifact to Hydra static builds
(cherry picked from commit e1b68244ad)
2025-04-24 17:30:39 +00:00
Jörg Thalheim
8686ba906f Merge pull request #13077 from NixOS/mergify/bp/2.28-maintenance/pr-13076
Revert "Actually ignore system/user registries during locking" (backport #13076)
2025-04-24 14:07:10 +02:00
Jörg Thalheim
04fcc879e6 Revert "Actually ignore system/user registries during locking"
This reverts commit 77d4316353.

(cherry picked from commit 3b5f0d9fb3)
2025-04-24 11:34:57 +00:00
mergify[bot]
4da3fada6e Merge pull request #13072 from NixOS/mergify/bp/2.28-maintenance/pr-13067
Move libflake/flake/* to libflake (backport #13067)
2025-04-23 19:39:27 +00:00
Eelco Dolstra
5a2ee1b952 Move libflake/flake/* to libflake
(cherry picked from commit bc67e47298)
2025-04-23 19:06:03 +00:00
mergify[bot]
06cc94432e Merge pull request #13071 from NixOS/mergify/bp/2.28-maintenance/pr-13070
Don't build MonitorFdHup test on Windows (backport #13070)
2025-04-23 18:50:06 +00:00
Eelco Dolstra
d3c79e2b13 Don't build MonitorFdHup on Windows
https://hydra.nixos.org/build/295398462
(cherry picked from commit a9b6213221)
2025-04-23 18:23:51 +00:00
mergify[bot]
70921714cb Merge pull request #13064 from NixOS/mergify/bp/2.28-maintenance/pr-13010
~flake.lock:~ Update Nixpkgs (partial backport #13010)
2025-04-23 15:09:17 +00:00
John Ericson
f666ec3837 Explain the use of "2" in the overlay
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
(cherry picked from commit ef36806898)
2025-04-23 16:42:02 +02:00
Robert Hensing
ba22a85a35 Fix pkgs.nixVersions and installTests
... by moving our stuff out of the way from upstream's
`nixComponents` and `nixDependencies` attrsets.

(I prefer not to use overlays, but let's make it work this way
first)

(cherry picked from commit b257ea94e3)
2025-04-23 16:42:02 +02:00
Eelco Dolstra
e555207048 Bump version 2025-04-17 14:00:34 +02:00
mergify[bot]
8a7b8dce5f Merge pull request #13033 from NixOS/mergify/bp/2.28-maintenance/pr-13032
Improve derivation "advanced attrs" test, fix almost-bug (backport #13032)
2025-04-15 19:06:26 +00:00
John Ericson
29ae14114e Remove stray assignment side affect in lambda
This was almost a bug! It wasn't simply because another assignment would
clobber it later.

(cherry picked from commit 32409dd7d7)
2025-04-15 14:25:16 -04:00
John Ericson
30d900b313 Derivation "advanced attrs" test: Ensure fields are set to distinct values
We had fields set to the same values before in our test data. This is
not a problem per-se, but does mean we wouldn't catch certain mixups.
Now, the fields are set to distinct values (where possible), which makes
the test more robust.

(cherry picked from commit a0b2b75f59)
2025-04-15 14:25:13 -04:00
John Ericson
5f0ddd7467 Merge pull request #13028 from NixOS/mergify/bp/2.28-maintenance/pr-13022
Test derivation options with content-addressing too (backport #13022)
2025-04-15 12:11:55 -04:00
John Ericson
f19184191e Test derivation options with content-addressing too
Now, both the unit and functional tests relating to derivation options
are tested both ways -- with input addressing and content-addressing
derivations.

(cherry picked from commit 307dbe9914)
2025-04-15 11:25:07 -04:00
John Ericson
37bcd29e5f Use the same variable for content addressing in functional tests
`CONTENT_ADDRESSED` -> `NIX_TESTS_CA_BY_DEFAULT`

(cherry picked from commit 7acc229c8f)
2025-04-15 11:19:45 -04:00
Eelco Dolstra
5ecbf6b9dc Merge pull request #13029 from NixOS/mergify/bp/2.28-maintenance/pr-13026
Fix issue #13018, `sourceInfo` strict in `outputs` (backport #13026)
2025-04-15 14:24:59 +02:00
Jörg Thalheim
f233a99cc8 Merge pull request #13027 from NixOS/mergify/bp/2.28-maintenance/pr-12603
libstore: curl retry: reset content-encoding and don't use string after move (backport #12603)
2025-04-15 14:00:13 +02:00
Robert Hensing
818fc68db6 fix: Evaluate flake parent source without evaluating its outputs
This requires that we refer to the `sourceInfo` instead of the
`result`. However, `sourceInfo` does not create a chain of basedir
resolution, so we add that back with `flakeDir`.

(cherry picked from commit 2109a5a206)
2025-04-15 11:52:46 +00:00
Robert Hensing
671364748c call-flake.nix: allNodes.${key} -> allNodes.${key}.result
(cherry picked from commit 9de9410f29)
2025-04-15 11:52:45 +00:00
Robert Hensing
9a969e29cf call-flake.nix: refactor: Bring mapAttrs into scope
(cherry picked from commit 674375b021)
2025-04-15 11:52:45 +00:00
Philipp Otterbein
a603401cdd libstore: curl retry: reset content-encoding and don't use string after move
(cherry picked from commit b129fc8237)
2025-04-15 11:22:25 +00:00
Eelco Dolstra
3e895be4e4 Merge pull request #13021 from NixOS/mergify/bp/2.28-maintenance/pr-13019
Mention BLAKE3 in the Nix 2.27 release notes (backport #13019)
2025-04-14 16:13:07 +02:00
Eelco Dolstra
b1a1f4bd2f Mention BLAKE3 in the Nix 2.27 release notes
(cherry picked from commit c0ed07755a)
2025-04-14 13:47:57 +00:00
Jörg Thalheim
f18180a045 Merge pull request #13011 from NixOS/mergify/bp/2.28-maintenance/pr-13009
Fix typo in string context docs (backport #13009)
2025-04-14 12:41:39 +02:00
Anthony Wang
9156550493 Fix typo in string context docs
(cherry picked from commit f64b8957c7)
2025-04-12 23:58:45 +00:00
mergify[bot]
011f6e06a2 Merge pull request #13006 from NixOS/mergify/bp/2.28-maintenance/pr-12538
libstore S3: fix progress bar and make file transfers interruptible (backport #12538)
2025-04-11 22:54:15 +00:00
Philipp Otterbein
61bb405839 add isInterrupted() call and replace some checkInterrupt() occurrences
(cherry picked from commit 49f757c24a)
2025-04-11 22:15:12 +00:00
Philipp Otterbein
c53bd8905b libstore: same progress bar behavior for PUT and POST requests
- no differentiation between uploads and downloads in CLI

(cherry picked from commit db297d3dda)
2025-04-11 22:15:12 +00:00
Philipp Otterbein
beab9eb978 libstore S3: fix progress bar and make file transfers interruptible
(cherry picked from commit 9da01e69f9)
2025-04-11 22:15:11 +00:00
mergify[bot]
4d990f1459 Merge pull request #12989 from NixOS/mergify/bp/2.28-maintenance/pr-12986
Fix another machine config parsing bug (backport #12986)
2025-04-09 20:51:33 +00:00
John Ericson
f9c262c3d5 Fix another machine config parsing bug
We were ignorning the result of `trim`, and after my last change we were
also trimmming too early.

(cherry picked from commit b74b0f4e1c)
2025-04-09 20:13:30 +00:00
mergify[bot]
bb8af4ceb7 Merge pull request #12985 from NixOS/mergify/bp/2.28-maintenance/pr-12984
Fix `;` and `#` bug in machine file parsing (backport #12984)
2025-04-09 19:04:07 +00:00
John Ericson
2892b758b3 Fix ; and # bug in machine file parsing
Comments go to the end of the line, not merely the next ; *or* \n. Fix
by splitting on `;` *within* lines, and test.

(cherry picked from commit f8b13cce19)
2025-04-09 18:27:16 +00:00
mergify[bot]
e191b93a0e Merge pull request #12983 from NixOS/mergify/bp/2.28-maintenance/pr-12699
tests/functional/flakes: Add test case for subflake locking (backport #12699)
2025-04-09 17:54:32 +00:00
Rodney Lorrimar
080950b0fe tests/functional/flakes: Add test case for subflake locking
This adds a test case where the lockfile of a relative path flake
dependency is updated.

It was reported by a user here: https://discourse.nixos.org/t/updating-local-subflakes-inputs-when-building-root-flake/61682

I think this test case relates to issue #7730.

Because the issue is not resolved, this test case would fail without
the `|| true` clause.

(cherry picked from commit 1bc82d1c86)
2025-04-09 17:20:31 +00:00
mergify[bot]
6d98cef93f Merge pull request #12982 from NixOS/mergify/bp/2.28-maintenance/pr-12979
Actually ignore system/user registries during locking (backport #12979)
2025-04-09 17:07:38 +00:00
Eelco Dolstra
a08477975d Actually ignore system/user registries during locking
Something went wrong in #12068 so this didn't work. Also added a test.

(cherry picked from commit 77d4316353)
2025-04-09 16:33:47 +00:00
Eelco Dolstra
c548e92860 Merge pull request #12966 from NixOS/mergify/bp/2.28-maintenance/pr-12958
Fix some unlinked tests (backport #12958)
2025-04-08 13:55:54 +02:00
mergify[bot]
a7f078aa84 Merge pull request #12972 from NixOS/mergify/bp/2.28-maintenance/pr-12967
Add trailing commas on addFlag incantations (backport #12967)
2025-04-07 23:56:11 +00:00
Graham Christensen
cd7e01526e format as required
(cherry picked from commit 9b47b2b217)
2025-04-07 23:16:28 +00:00
Graham Christensen
16a2cddfb9 Add trailing commas on addFlag incantations
(cherry picked from commit 06acbd37bd)
2025-04-07 23:16:27 +00:00
mergify[bot]
1a4332fd3a Merge pull request #12965 from NixOS/mergify/bp/2.28-maintenance/pr-12962
Fix some clang-tidy warnings (backport #12962)
2025-04-07 21:17:06 +00:00
Eelco Dolstra
3a4dc47c22 Remove unused tracing-file-system-object-sink.{hh,cc}
(cherry picked from commit 611fd806cb)
2025-04-07 20:42:08 +00:00
Eelco Dolstra
f0ed61bb4e Fix/run monitorfdhup test
(cherry picked from commit 340fa00d52)
2025-04-07 20:42:08 +00:00
Eelco Dolstra
85902fad58 Fix some clang-tidy warnings
(cherry picked from commit c0ad5d36c4)
2025-04-07 20:38:07 +00:00
mergify[bot]
467a1df842 Merge pull request #12964 from NixOS/mergify/bp/2.28-maintenance/pr-12959
Keep fchmodat2-compat.hh private (backport #12959)
2025-04-07 20:32:05 +00:00
Eelco Dolstra
aa1c690ebf Keep fchmodat2-compat.hh private
Since it references store-config-private.hh.

(cherry picked from commit 04e9dc27ac)
2025-04-07 19:18:46 +00:00
mergify[bot]
3a758fc348 Merge pull request #12963 from NixOS/mergify/bp/2.28-maintenance/pr-12961
Make lexer-helpers.hh internal to fix a clang-tidy error (backport #12961)
2025-04-07 19:04:29 +00:00
Eelco Dolstra
17de9dd275 Make lexer-helpers.hh internal to fix a clang-tidy error
(cherry picked from commit 8be24f58f2)
2025-04-07 18:29:08 +00:00
mergify[bot]
6dde30bacf Merge pull request #12960 from NixOS/mergify/bp/2.28-maintenance/pr-12956
Fix meson warnings on minimum version (backport #12956)
2025-04-07 18:26:02 +00:00
Sandro
5b21c94fab Fix meson warnings on minimum version
nix> meson.build:216: WARNING: Project targets '>= 1.1' but uses feature introduced in '1.4.0': fs.name with build_tgt, custom_tgt, and custom_idx.
nix> meson.build:222: WARNING: Project targets '>= 1.1' but uses feature introduced in '1.4.0': fs.name with build_tgt, custom_tgt, and custom_idx.
nix> meson.build:235: WARNING: Project targets '>= 1.1' but uses feature introduced in '1.4.0': fs.name with build_tgt, custom_tgt, and custom_idx.
nix> meson.build:236: WARNING: Project targets '>= 1.1' but uses feature introduced in '1.4.0': fs.name with build_tgt, custom_tgt, and custom_idx.
nix> meson.build:242: WARNING: Project targets '>= 1.1' but uses feature introduced in '1.4.0': fs.name with build_tgt, custom_tgt, and custom_idx.

(cherry picked from commit 14a829acbb)
2025-04-07 17:51:44 +00:00
mergify[bot]
a4962f73b5 Merge pull request #12955 from NixOS/mergify/bp/2.28-maintenance/pr-12951
tests/functional/repl: fix race condition (backport #12951)
2025-04-07 12:52:09 +00:00
Jörg Thalheim
288fee2d14 tests/functional/repl: fix race condition
the sleep 1 is not enough in some circumstances. Switching to a fifo
helps.

(cherry picked from commit 1de951d31d)
2025-04-07 12:20:05 +00:00
mergify[bot]
42ba32f1ff Merge pull request #12949 from NixOS/mergify/bp/2.28-maintenance/pr-12944
maintainers/release-notes: Let it fail (backport #12944)
2025-04-07 09:58:20 +00:00
Eelco Dolstra
e0778c2796 Bump version 2025-04-07 10:55:37 +02:00
Robert Hensing
e7dbf0fc0a maintainers/release-notes: Let it fail
Fail when a command fails.

Basic error handling was missing, which would lead to errors getting
obscured a bit by subsequent successful logging.

(cherry picked from commit da36c34db7)
2025-04-07 08:53:33 +00:00
167 changed files with 1788 additions and 708 deletions

View File

@@ -1 +1 @@
2.28.1
2.28.4

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -170,9 +170,9 @@ sensitive.
```shell
$ nix init --template=template#pyton
$ nix init --template=template#python
------------------------------------------------------------------------
Error! Template `template#pyton` not found.
Error! Template `template#python` not found.
------------------------------------------------------------------------
Initializing Nix project at `/path/to/here`.
Select a template for you new project:

View File

@@ -320,7 +320,7 @@
See [Nix Archive](store/file-system-object/content-address.html#serial-nix-archive) for details.
- [`∅`]{#gloss-emtpy-set}
- [`∅`]{#gloss-empty-set}
The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile.

View File

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

View File

@@ -115,7 +115,7 @@ It creates an [attribute set] representing the string context, which can be insp
## Clearing string contexts
[`buitins.unsafeDiscardStringContext`](./builtins.md#builtins-unsafeDiscardStringContext) will make a copy of a string, but with an empty string context.
[`builtins.unsafeDiscardStringContext`](./builtins.md#builtins-unsafeDiscardStringContext) will make a copy of a string, but with an empty string context.
The returned string can be used in more ways, e.g. by operators that require the string context to be empty.
The requirement to explicitly discard the string context in such use cases helps ensure that string context elements are not lost by mistake.
The "unsafe" marker is only there to remind that Nix normally guarantees that dependencies are tracked, whereas the returned string has lost them.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,6 +38,15 @@
Curl created sockets without setting `FD_CLOEXEC`/`SOCK_CLOEXEC`. This could previously cause connections to remain open forever when using commands like `nix shell`. This change sets the `FD_CLOEXEC` flag using a `CURLOPT_SOCKOPTFUNCTION` callback.
- Add BLAKE3 hash algorithm [#12379](https://github.com/NixOS/nix/pull/12379)
Nix now supports the BLAKE3 hash algorithm as an experimental feature (`blake3-hashes`):
```console
# nix hash file ./file --type blake3 --extra-experimental-features blake3-hashes
blake3-34P4p+iZXcbbyB1i4uoF7eWCGcZHjmaRn6Y7QdynLwU=
```
# Contributors
This release was made possible by the following 21 contributors:

View File

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

View File

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

View File

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

View File

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

View File

@@ -143,14 +143,15 @@
# without "polluting" the top level "`pkgs`" attrset.
# This also has the benefit of providing us with a distinct set of packages
# we can iterate over.
nixComponents =
# The `2` suffix is here because otherwise it interferes with `nixVersions.latest`, which is used in daemon compat tests.
nixComponents2 =
lib.makeScopeWithSplicing'
{
inherit (final) splicePackages;
inherit (final.nixDependencies) newScope;
inherit (final.nixDependencies2) newScope;
}
{
otherSplices = final.generateSplicesForMkScope "nixComponents";
otherSplices = final.generateSplicesForMkScope "nixComponents2";
f = import ./packaging/components.nix {
inherit (final) lib;
inherit officialRelease;
@@ -161,22 +162,23 @@
};
# The dependencies are in their own scope, so that they don't have to be
# in Nixpkgs top level `pkgs` or `nixComponents`.
nixDependencies =
# in Nixpkgs top level `pkgs` or `nixComponents2`.
# The `2` suffix is here because otherwise it interferes with `nixVersions.latest`, which is used in daemon compat tests.
nixDependencies2 =
lib.makeScopeWithSplicing'
{
inherit (final) splicePackages;
inherit (final) newScope; # layered directly on pkgs, unlike nixComponents above
inherit (final) newScope; # layered directly on pkgs, unlike nixComponents2 above
}
{
otherSplices = final.generateSplicesForMkScope "nixDependencies";
otherSplices = final.generateSplicesForMkScope "nixDependencies2";
f = import ./packaging/dependencies.nix {
inherit inputs stdenv;
pkgs = final;
};
};
nix = final.nixComponents.nix-cli;
nix = final.nixComponents2.nix-cli;
# See https://github.com/NixOS/nixpkgs/pull/214409
# Remove when fixed in this flake's nixpkgs
@@ -277,7 +279,7 @@
# memory leaks with detect_leaks=0.
"" = rec {
nixpkgs = nixpkgsFor.${system}.native;
nixComponents = nixpkgs.nixComponents.overrideScope (
nixComponents = nixpkgs.nixComponents2.overrideScope (
nixCompFinal: nixCompPrev: {
mesonComponentOverrides = _finalAttrs: prevAttrs: {
mesonFlags =
@@ -305,7 +307,7 @@
nixpkgsPrefix:
{
nixpkgs,
nixComponents ? nixpkgs.nixComponents,
nixComponents ? nixpkgs.nixComponents2,
}:
flatMapAttrs nixComponents (
pkgName: pkg:
@@ -335,9 +337,9 @@
binaryTarball = self.hydraJobs.binaryTarball.${system};
# TODO probably should be `nix-cli`
nix = self.packages.${system}.nix-everything;
nix-manual = nixpkgsFor.${system}.native.nixComponents.nix-manual;
nix-internal-api-docs = nixpkgsFor.${system}.native.nixComponents.nix-internal-api-docs;
nix-external-api-docs = nixpkgsFor.${system}.native.nixComponents.nix-external-api-docs;
nix-manual = nixpkgsFor.${system}.native.nixComponents2.nix-manual;
nix-internal-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-internal-api-docs;
nix-external-api-docs = nixpkgsFor.${system}.native.nixComponents2.nix-external-api-docs;
}
# We need to flatten recursive attribute sets of derivations to pass `flake check`.
//
@@ -389,9 +391,9 @@
}:
{
# These attributes go right into `packages.<system>`.
"${pkgName}" = nixpkgsFor.${system}.native.nixComponents.${pkgName};
"${pkgName}-static" = nixpkgsFor.${system}.native.pkgsStatic.nixComponents.${pkgName};
"${pkgName}-llvm" = nixpkgsFor.${system}.native.pkgsLLVM.nixComponents.${pkgName};
"${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 (_: { })) (
@@ -399,7 +401,7 @@
{ }:
{
# These attributes go right into `packages.<system>`.
"${pkgName}-${crossSystem}" = nixpkgsFor.${system}.cross.${crossSystem}.nixComponents.${pkgName};
"${pkgName}-${crossSystem}" = nixpkgsFor.${system}.cross.${crossSystem}.nixComponents2.${pkgName};
}
)
)
@@ -409,7 +411,7 @@
{
# These attributes go right into `packages.<system>`.
"${pkgName}-${stdenvName}" =
nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.nixComponents.${pkgName};
nixpkgsFor.${system}.nativeForStdenv.${stdenvName}.nixComponents2.${pkgName};
}
)
)

View File

@@ -172,14 +172,14 @@
''^src/libfetchers/include/nix/fetchers/tarball\.hh$''
''^src/libfetchers/git\.cc$''
''^src/libfetchers/mercurial\.cc$''
''^src/libflake/flake/config\.cc$''
''^src/libflake/flake/flake\.cc$''
''^src/libflake/config\.cc$''
''^src/libflake/flake\.cc$''
''^src/libflake/include/nix/flake/flake\.hh$''
''^src/libflake/flake/flakeref\.cc$''
''^src/libflake/flakeref\.cc$''
''^src/libflake/include/nix/flake/flakeref\.hh$''
''^src/libflake/flake/lockfile\.cc$''
''^src/libflake/lockfile\.cc$''
''^src/libflake/include/nix/flake/lockfile\.hh$''
''^src/libflake/flake/url-name\.cc$''
''^src/libflake/url-name\.cc$''
''^src/libmain/common-args\.cc$''
''^src/libmain/include/nix/main/common-args\.hh$''
''^src/libmain/loggers\.cc$''

View File

@@ -2,6 +2,8 @@
# vim: set filetype=bash:
#!nix shell .#changelog-d --command bash
set -euo pipefail
# --- CONFIGURATION ---
# This does double duty for

View File

@@ -5,11 +5,11 @@
{ pkgs }:
pkgs.nixComponents.nix-util.overrideAttrs (
pkgs.nixComponents2.nix-util.overrideAttrs (
attrs:
let
stdenv = pkgs.nixDependencies.stdenv;
stdenv = pkgs.nixDependencies2.stdenv;
buildCanExecuteHost = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
modular = devFlake.getSystem stdenv.buildPlatform.system;
transformFlag =
@@ -79,26 +79,26 @@ pkgs.nixComponents.nix-util.overrideAttrs (
};
mesonFlags =
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents.nix-util.mesonFlags)
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents.nix-store.mesonFlags)
++ map (transformFlag "libfetchers") (ignoreCrossFile pkgs.nixComponents.nix-fetchers.mesonFlags)
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents2.nix-store.mesonFlags)
++ map (transformFlag "libfetchers") (ignoreCrossFile pkgs.nixComponents2.nix-fetchers.mesonFlags)
++ lib.optionals havePerl (
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents.nix-perl-bindings.mesonFlags)
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
)
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents.nix-expr.mesonFlags)
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents.nix-cmd.mesonFlags);
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
nativeBuildInputs =
attrs.nativeBuildInputs or [ ]
++ pkgs.nixComponents.nix-util.nativeBuildInputs
++ pkgs.nixComponents.nix-store.nativeBuildInputs
++ pkgs.nixComponents.nix-fetchers.nativeBuildInputs
++ pkgs.nixComponents.nix-expr.nativeBuildInputs
++ lib.optionals havePerl pkgs.nixComponents.nix-perl-bindings.nativeBuildInputs
++ lib.optionals buildCanExecuteHost pkgs.nixComponents.nix-manual.externalNativeBuildInputs
++ pkgs.nixComponents.nix-internal-api-docs.nativeBuildInputs
++ pkgs.nixComponents.nix-external-api-docs.nativeBuildInputs
++ pkgs.nixComponents.nix-functional-tests.externalNativeBuildInputs
++ pkgs.nixComponents2.nix-util.nativeBuildInputs
++ pkgs.nixComponents2.nix-store.nativeBuildInputs
++ pkgs.nixComponents2.nix-fetchers.nativeBuildInputs
++ pkgs.nixComponents2.nix-expr.nativeBuildInputs
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.nativeBuildInputs
++ lib.optionals buildCanExecuteHost pkgs.nixComponents2.nix-manual.externalNativeBuildInputs
++ pkgs.nixComponents2.nix-internal-api-docs.nativeBuildInputs
++ pkgs.nixComponents2.nix-external-api-docs.nativeBuildInputs
++ pkgs.nixComponents2.nix-functional-tests.externalNativeBuildInputs
++ lib.optional (
!buildCanExecuteHost
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
@@ -114,23 +114,20 @@ pkgs.nixComponents.nix-util.overrideAttrs (
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
pkgs.buildPackages.nixfmt-rfc-style
]
# TODO: Remove the darwin check once
# https://github.com/NixOS/nixpkgs/pull/291814 is available
++ lib.optional (stdenv.cc.isClang && !stdenv.buildPlatform.isDarwin) pkgs.buildPackages.bear
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
lib.hiPrio pkgs.buildPackages.clang-tools
);
buildInputs =
attrs.buildInputs or [ ]
++ pkgs.nixComponents.nix-util.buildInputs
++ pkgs.nixComponents.nix-store.buildInputs
++ pkgs.nixComponents.nix-store-tests.externalBuildInputs
++ pkgs.nixComponents.nix-fetchers.buildInputs
++ pkgs.nixComponents.nix-expr.buildInputs
++ pkgs.nixComponents.nix-expr.externalPropagatedBuildInputs
++ pkgs.nixComponents.nix-cmd.buildInputs
++ lib.optionals havePerl pkgs.nixComponents.nix-perl-bindings.externalBuildInputs
++ pkgs.nixComponents2.nix-util.buildInputs
++ pkgs.nixComponents2.nix-store.buildInputs
++ pkgs.nixComponents2.nix-store-tests.externalBuildInputs
++ pkgs.nixComponents2.nix-fetchers.buildInputs
++ pkgs.nixComponents2.nix-expr.buildInputs
++ pkgs.nixComponents2.nix-expr.externalPropagatedBuildInputs
++ pkgs.nixComponents2.nix-cmd.buildInputs
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.externalBuildInputs
++ lib.optional havePerl pkgs.perl;
}
)

View File

@@ -19,14 +19,14 @@ let
testNixVersions =
pkgs: daemon:
pkgs.nixComponents.nix-functional-tests.override {
pkgs.nixComponents2.nix-functional-tests.override {
pname = "nix-daemon-compat-tests";
version = "${pkgs.nix.version}-with-daemon-${daemon.version}";
test-daemon = daemon;
};
# Technically we could just return `pkgs.nixComponents`, but for Hydra it's
# Technically we could just return `pkgs.nixComponents2`, but for Hydra it's
# convention to transpose it, and to transpose it efficiently, we need to
# enumerate them manually, so that we don't evaluate unnecessary package sets.
# See listingIsComplete below.
@@ -85,7 +85,7 @@ in
} (_: null);
actualPkgs = lib.concatMapAttrs (
k: v: if lib.strings.hasPrefix "nix-" k then { ${k} = null; } else { }
) nixpkgsFor.${arbitrarySystem}.native.nixComponents;
) nixpkgsFor.${arbitrarySystem}.native.nixComponents2;
diff = lib.concatStringsSep "\n" (
lib.concatLists (
lib.mapAttrsToList (
@@ -111,7 +111,7 @@ in
# Binary package for various platforms.
build = forAllPackages (
pkgName: forAllSystems (system: nixpkgsFor.${system}.native.nixComponents.${pkgName})
pkgName: forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.${pkgName})
);
shellInputs = removeAttrs (forAllSystems (
@@ -121,7 +121,7 @@ in
buildStatic = forAllPackages (
pkgName:
lib.genAttrs linux64BitSystems (
system: nixpkgsFor.${system}.native.pkgsStatic.nixComponents.${pkgName}
system: nixpkgsFor.${system}.native.pkgsStatic.nixComponents2.${pkgName}
)
);
@@ -138,7 +138,7 @@ in
forAllCrossSystems (
crossSystem:
lib.genAttrs [ "x86_64-linux" ] (
system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents.${pkgName}
system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents2.${pkgName}
)
)
)
@@ -148,7 +148,7 @@ in
let
components = forAllSystems (
system:
nixpkgsFor.${system}.native.nixComponents.overrideScope (
nixpkgsFor.${system}.native.nixComponents2.overrideScope (
self: super: {
nix-expr = super.nix-expr.override { enableGC = false; };
}
@@ -157,7 +157,7 @@ in
in
forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
buildNoTests = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents.nix-cli);
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.
@@ -165,7 +165,7 @@ in
let
components = forAllSystems (
system:
nixpkgsFor.${system}.native.nixComponents.overrideScope (
nixpkgsFor.${system}.native.nixComponents2.overrideScope (
self: super: {
nix-cmd = super.nix-cmd.override {
enableMarkdown = false;
@@ -178,7 +178,7 @@ in
forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName}));
# Perl bindings for various platforms.
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents.nix-perl-bindings);
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-perl-bindings);
# Binary tarball for various platforms, containing a Nix store
# with the closure of 'nix' package, and the second half of
@@ -228,13 +228,13 @@ in
# };
# Nix's manual
manual = nixpkgsFor.x86_64-linux.native.nixComponents.nix-manual;
manual = nixpkgsFor.x86_64-linux.native.nixComponents2.nix-manual;
# API docs for Nix's unstable internal C++ interfaces.
internal-api-docs = nixpkgsFor.x86_64-linux.native.nixComponents.nix-internal-api-docs;
internal-api-docs = nixpkgsFor.x86_64-linux.native.nixComponents2.nix-internal-api-docs;
# API docs for Nix's C bindings.
external-api-docs = nixpkgsFor.x86_64-linux.native.nixComponents.nix-external-api-docs;
external-api-docs = nixpkgsFor.x86_64-linux.native.nixComponents2.nix-external-api-docs;
# System tests.
tests =

View File

@@ -237,12 +237,13 @@ void StorePathCommand::run(ref<Store> store, StorePaths && storePaths)
MixProfile::MixProfile()
{
addFlag(
{.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath});
addFlag({
.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath,
});
}
void MixProfile::updateProfile(const StorePath & storePath)

View File

@@ -63,7 +63,7 @@ MixEvalArgs::MixEvalArgs()
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
.category = category,
.labels = {"name", "expr"},
.handler = {[&](std::string name, std::string expr) { autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}}); }}
.handler = {[&](std::string name, std::string expr) { autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}}); }},
});
addFlag({
@@ -80,7 +80,7 @@ MixEvalArgs::MixEvalArgs()
.category = category,
.labels = {"name", "path"},
.handler = {[&](std::string name, std::string path) { autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}}); }},
.completer = completePath
.completer = completePath,
});
addFlag({
@@ -105,7 +105,7 @@ MixEvalArgs::MixEvalArgs()
.labels = {"path"},
.handler = {[&](std::string s) {
lookupPath.elements.emplace_back(LookupPath::Elem::parse(s));
}}
}},
});
addFlag({
@@ -131,7 +131,7 @@ MixEvalArgs::MixEvalArgs()
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, openStore(), prefix);
}}
}},
});
addFlag({

View File

@@ -40,7 +40,7 @@ void completeFlakeInputAttrPath(
std::string_view prefix)
{
for (auto & flakeRef : flakeRefs) {
auto flake = flake::getFlake(*evalState, flakeRef, true);
auto flake = flake::getFlake(*evalState, flakeRef, fetchers::UseRegistries::All);
for (auto & input : flake.inputs)
if (hasPrefix(input.first, prefix))
completions.add(input.first);
@@ -64,21 +64,21 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&]() {
lockFlags.recreateLockFile = true;
warn("'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead.");
}}
}},
});
addFlag({
.longName = "no-update-lock-file",
.description = "Do not allow any updates to the flake's lock file.",
.category = category,
.handler = {&lockFlags.updateLockFile, false}
.handler = {&lockFlags.updateLockFile, false},
});
addFlag({
.longName = "no-write-lock-file",
.description = "Do not write the flake's newly generated lock file.",
.category = category,
.handler = {&lockFlags.writeLockFile, false}
.handler = {&lockFlags.writeLockFile, false},
});
addFlag({
@@ -94,14 +94,14 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&]() {
lockFlags.useRegistries = false;
warn("'--no-registries' is deprecated; use '--no-use-registries'");
}}
}},
});
addFlag({
.longName = "commit-lock-file",
.description = "Commit changes to the flake's lock file.",
.category = category,
.handler = {&lockFlags.commitLockFile, true}
.handler = {&lockFlags.commitLockFile, true},
});
addFlag({
@@ -121,7 +121,7 @@ MixFlakeOptions::MixFlakeOptions()
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}}
}},
});
addFlag({
@@ -141,7 +141,7 @@ MixFlakeOptions::MixFlakeOptions()
} else if (n == 1) {
completeFlakeRef(completions, getEvalState()->store, prefix);
}
}}
}},
});
addFlag({
@@ -152,7 +152,7 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&](std::string lockFilePath) {
lockFlags.referenceLockFilePath = {getFSSourceAccessor(), CanonPath(absPath(lockFilePath))};
}},
.completer = completePath
.completer = completePath,
});
addFlag({
@@ -163,7 +163,7 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&](std::string lockFilePath) {
lockFlags.outputLockFilePath = lockFilePath;
}},
.completer = completePath
.completer = completePath,
});
addFlag({
@@ -190,7 +190,7 @@ MixFlakeOptions::MixFlakeOptions()
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getEvalState()->store, prefix);
}}
}},
});
}
@@ -206,7 +206,7 @@ SourceExprCommand::SourceExprCommand()
.category = installablesCategory,
.labels = {"file"},
.handler = {&file},
.completer = completePath
.completer = completePath,
});
addFlag({
@@ -214,7 +214,7 @@ SourceExprCommand::SourceExprCommand()
.description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.",
.category = installablesCategory,
.labels = {"expr"},
.handler = {&expr}
.handler = {&expr},
});
}
@@ -834,7 +834,7 @@ RawInstallablesCommand::RawInstallablesCommand()
addFlag({
.longName = "stdin",
.description = "Read installables from the standard input. No default installable applied.",
.handler = {&readFromStdIn, true}
.handler = {&readFromStdIn, true},
});
expectArgs({

View File

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

View File

@@ -20,7 +20,6 @@ headers = [config_pub_h] + files(
'gc-small-vector.hh',
'get-drvs.hh',
'json-to-value.hh',
# internal: 'lexer-helpers.hh',
'nixexpr.hh',
'parser-state.hh',
'primops.hh',

View File

@@ -65,7 +65,7 @@ struct DocComment {
struct AttrName
{
Symbol symbol;
Expr * expr;
Expr * expr = nullptr;
AttrName(Symbol s) : symbol(s) {};
AttrName(Expr * e) : expr(e) {};
};
@@ -159,7 +159,7 @@ struct ExprVar : Expr
`nullptr`: Not from a `with`.
Valid pointer: the nearest, innermost `with` expression to query first. */
ExprWith * fromWith;
ExprWith * fromWith = nullptr;
/* In the former case, the value is obtained by going `level`
levels up from the current environment and getting the
@@ -167,7 +167,7 @@ struct ExprVar : Expr
value is obtained by getting the attribute named `name` from
the set stored in the environment that is `level` levels up
from the current one.*/
Level level;
Level level = 0;
Displacement displ = 0;
ExprVar(Symbol name) : name(name) { };

View File

@@ -1,7 +1,4 @@
#include "lexer-tab.hh"
#include "parser-tab.hh"
#include "nix/expr/lexer-helpers.hh"
#include "lexer-helpers.hh"
void nix::lexer::internal::initLoc(YYLTYPE * loc)
{

View File

@@ -25,8 +25,7 @@
#endif
#include "nix/expr/nixexpr.hh"
#include "parser-tab.hh"
#include "nix/expr/lexer-helpers.hh"
#include "lexer-helpers.hh"
namespace nix {
struct LexerState;

View File

@@ -181,7 +181,7 @@ static void fetchTree(
}
if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes))
input = lookupInRegistries(state.store, input).first;
input = lookupInRegistries(state.store, input, fetchers::UseRegistries::Limited).first;
if (state.settings.pureEval && !input.isLocked()) {
if (input.getNarHash())

View File

@@ -65,7 +65,11 @@ void overrideRegistry(
const Input & to,
const Attrs & extraAttrs);
using RegistryFilter = std::function<bool(Registry::RegistryType)>;
enum class UseRegistries : int {
No,
All,
Limited, // global and flag registry only
};
/**
* Rewrite a flakeref using the registries. If `filter` is set, only
@@ -74,6 +78,6 @@ using RegistryFilter = std::function<bool(Registry::RegistryType)>;
std::pair<Input, Attrs> lookupInRegistries(
ref<Store> store,
const Input & input,
const RegistryFilter & filter = {});
UseRegistries useRegistries);
}

View File

@@ -14,6 +14,8 @@ std::shared_ptr<Registry> Registry::read(
const Settings & settings,
const Path & path, RegistryType type)
{
debug("reading registry '%s'", path);
auto registry = std::make_shared<Registry>(settings, type);
if (!pathExists(path))
@@ -179,29 +181,36 @@ Registries getRegistries(const Settings & settings, ref<Store> store)
std::pair<Input, Attrs> lookupInRegistries(
ref<Store> store,
const Input & _input,
const RegistryFilter & filter)
UseRegistries useRegistries)
{
Attrs extraAttrs;
int n = 0;
Input input(_input);
if (useRegistries == UseRegistries::No)
return {input, extraAttrs};
restart:
n++;
if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string());
for (auto & registry : getRegistries(*input.settings, store)) {
if (filter && !filter(registry->type)) continue;
if (useRegistries == UseRegistries::Limited
&& !(registry->type == fetchers::Registry::Flag || registry->type == fetchers::Registry::Global))
continue;
// FIXME: O(n)
for (auto & entry : registry->entries) {
if (entry.exact) {
if (entry.from == input) {
debug("resolved flakeref '%s' against registry %d exactly", input.to_string(), registry->type);
input = entry.to;
extraAttrs = entry.extraAttrs;
goto restart;
}
} else {
if (entry.from.contains(input)) {
debug("resolved flakeref '%s' against registry %d", input.to_string(), registry->type);
input = entry.to.applyOverrides(
!entry.from.getRef() && input.getRef() ? input.getRef() : std::optional<std::string>(),
!entry.from.getRev() && input.getRev() ? input.getRev() : std::optional<Hash>());

View File

@@ -14,6 +14,7 @@ overrides:
fetchTreeFinal:
let
inherit (builtins) mapAttrs;
lockFile = builtins.fromJSON lockFileStr;
@@ -35,19 +36,26 @@ let
(resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
(builtins.tail path);
allNodes = builtins.mapAttrs (
allNodes = mapAttrs (
key: node:
let
parentNode = allNodes.${getInputByPath lockFile.root node.parent};
flakeDir =
let
dir = overrides.${key}.dir or node.locked.path or "";
parentDir = parentNode.flakeDir;
in
if node ? parent then parentDir + ("/" + dir) else dir;
sourceInfo =
if overrides ? ${key} then
overrides.${key}.sourceInfo
else if node.locked.type == "path" && builtins.substring 0 1 node.locked.path != "/" then
parentNode.sourceInfo
// {
outPath = parentNode.outPath + ("/" + node.locked.path);
outPath = parentNode.sourceInfo.outPath + ("/" + flakeDir);
}
else
# FIXME: remove obsolete node.info.
@@ -60,7 +68,7 @@ let
flake = import (outPath + "/flake.nix");
inputs = builtins.mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}) (
inputs = mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}.result) (
node.inputs or { }
);
@@ -85,12 +93,17 @@ let
};
in
if node.flake or true then
assert builtins.isFunction flake.outputs;
result
else
sourceInfo
{
result =
if node.flake or true then
assert builtins.isFunction flake.outputs;
result
else
sourceInfo;
inherit flakeDir sourceInfo;
}
) lockFile.nodes;
in
allNodes.${lockFile.root}
allNodes.${lockFile.root}.result

View File

@@ -45,7 +45,7 @@ static std::optional<FetchedFlake> lookupInFlakeCache(
static std::tuple<ref<SourceAccessor>, FlakeRef, FlakeRef> fetchOrSubstituteTree(
EvalState & state,
const FlakeRef & originalRef,
bool useRegistries,
fetchers::UseRegistries useRegistries,
FlakeCache & flakeCache)
{
auto fetched = lookupInFlakeCache(flakeCache, originalRef);
@@ -56,14 +56,8 @@ static std::tuple<ref<SourceAccessor>, FlakeRef, FlakeRef> fetchOrSubstituteTree
auto [accessor, lockedRef] = originalRef.lazyFetch(state.store);
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .accessor = accessor});
} else {
if (useRegistries) {
resolvedRef = originalRef.resolve(
state.store,
[](fetchers::Registry::RegistryType type) {
/* Only use the global registry and CLI flags
to resolve indirect flakerefs. */
return type == fetchers::Registry::Flag || type == fetchers::Registry::Global;
});
if (useRegistries != fetchers::UseRegistries::No) {
resolvedRef = originalRef.resolve(state.store, useRegistries);
fetched = lookupInFlakeCache(flakeCache, originalRef);
if (!fetched) {
auto [accessor, lockedRef] = resolvedRef.lazyFetch(state.store);
@@ -396,7 +390,7 @@ static FlakeRef applySelfAttrs(
static Flake getFlake(
EvalState & state,
const FlakeRef & originalRef,
bool useRegistries,
fetchers::UseRegistries useRegistries,
FlakeCache & flakeCache,
const InputAttrPath & lockRootAttrPath)
{
@@ -415,7 +409,7 @@ static Flake getFlake(
// FIXME: need to remove attrs that are invalidated by the changed input attrs, such as 'narHash'.
newLockedRef.input.attrs.erase("narHash");
auto [accessor2, resolvedRef2, lockedRef2] = fetchOrSubstituteTree(
state, newLockedRef, false, flakeCache);
state, newLockedRef, fetchers::UseRegistries::No, flakeCache);
accessor = accessor2;
lockedRef = lockedRef2;
}
@@ -427,7 +421,7 @@ static Flake getFlake(
return readFlake(state, originalRef, resolvedRef, lockedRef, state.storePath(storePath), lockRootAttrPath);
}
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries)
Flake getFlake(EvalState & state, const FlakeRef & originalRef, fetchers::UseRegistries useRegistries)
{
FlakeCache flakeCache;
return getFlake(state, originalRef, useRegistries, flakeCache, {});
@@ -455,8 +449,15 @@ LockedFlake lockFlake(
FlakeCache flakeCache;
auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries);
auto useRegistriesTop = useRegistries ? fetchers::UseRegistries::All : fetchers::UseRegistries::No;
auto useRegistriesInputs = useRegistries ? fetchers::UseRegistries::Limited : fetchers::UseRegistries::No;
auto flake = getFlake(state, topRef, useRegistries, flakeCache, {});
auto flake = getFlake(
state,
topRef,
useRegistriesTop,
flakeCache,
{});
if (lockFlags.applyNixConfig) {
flake.config.apply(settings);
@@ -626,12 +627,17 @@ LockedFlake lockFlake(
/* Get the input flake, resolve 'path:./...'
flakerefs relative to the parent flake. */
auto getInputFlake = [&](const FlakeRef & ref)
auto getInputFlake = [&](const FlakeRef & ref, const fetchers::UseRegistries useRegistries)
{
if (auto resolvedPath = resolveRelativePath()) {
return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath);
} else {
return getFlake(state, ref, useRegistries, flakeCache, inputAttrPath);
return getFlake(
state,
ref,
useRegistries,
flakeCache,
inputAttrPath);
}
};
@@ -647,7 +653,7 @@ LockedFlake lockFlake(
oldLock = *oldLock3;
if (oldLock
&& oldLock->originalRef == *input.ref
&& oldLock->originalRef.canonicalize() == input.ref->canonicalize()
&& oldLock->parentInputAttrPath == overridenParentPath
&& !hasCliOverride)
{
@@ -712,7 +718,7 @@ LockedFlake lockFlake(
}
if (mustRefetch) {
auto inputFlake = getInputFlake(oldLock->lockedRef);
auto inputFlake = getInputFlake(oldLock->lockedRef, useRegistriesInputs);
nodePaths.emplace(childNode, inputFlake.path.parent());
computeLocks(inputFlake.inputs, childNode, inputAttrPath, oldLock, followsPrefix,
inputFlake.path, false);
@@ -737,10 +743,11 @@ LockedFlake lockFlake(
nuked the next time we update the lock
file. That is, overrides are sticky unless you
use --no-write-lock-file. */
auto ref = (input2.ref && explicitCliOverrides.contains(inputAttrPath)) ? *input2.ref : *input.ref;
auto inputIsOverride = explicitCliOverrides.contains(inputAttrPath);
auto ref = (input2.ref && inputIsOverride) ? *input2.ref : *input.ref;
if (input.isFlake) {
auto inputFlake = getInputFlake(*input.ref);
auto inputFlake = getInputFlake(*input.ref, inputIsOverride ? fetchers::UseRegistries::All : useRegistriesInputs);
auto childNode = make_ref<LockedNode>(
inputFlake.lockedRef,
@@ -780,7 +787,7 @@ LockedFlake lockFlake(
return {*resolvedPath, *input.ref};
} else {
auto [accessor, resolvedRef, lockedRef] = fetchOrSubstituteTree(
state, *input.ref, useRegistries, flakeCache);
state, *input.ref, useRegistriesInputs, flakeCache);
// FIXME: allow input to be lazy.
auto storePath = copyInputToStore(state, lockedRef.input, input.ref->input, accessor);
@@ -895,7 +902,10 @@ LockedFlake lockFlake(
repo, so we should re-read it. FIXME: we could
also just clear the 'rev' field... */
auto prevLockedRef = flake.lockedRef;
flake = getFlake(state, topRef, useRegistries);
flake = getFlake(
state,
topRef,
useRegistriesTop);
if (lockFlags.commitLockFile &&
flake.lockedRef.input.getRev() &&

View File

@@ -37,9 +37,9 @@ std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
FlakeRef FlakeRef::resolve(
ref<Store> store,
const fetchers::RegistryFilter & filter) const
fetchers::UseRegistries useRegistries) const
{
auto [input2, extraAttrs] = lookupInRegistries(store, input);
auto [input2, extraAttrs] = lookupInRegistries(store, input, useRegistries);
return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
}
@@ -289,6 +289,55 @@ std::pair<ref<SourceAccessor>, FlakeRef> FlakeRef::lazyFetch(ref<Store> store) c
return {accessor, FlakeRef(std::move(lockedInput), subdir)};
}
FlakeRef FlakeRef::canonicalize() const
{
auto flakeRef(*this);
/* Backward compatibility hack: In old versions of Nix, if you had
a flake input like
inputs.foo.url = "git+https://foo/bar?dir=subdir";
it would result in a lock file entry like
"original": {
"dir": "subdir",
"type": "git",
"url": "https://foo/bar?dir=subdir"
}
New versions of Nix remove `?dir=subdir` from the `url` field,
since the subdirectory is intended for `FlakeRef`, not the
fetcher (and specifically the remote server), that is, the
flakeref is parsed into
"original": {
"dir": "subdir",
"type": "git",
"url": "https://foo/bar"
}
However, this causes new versions of Nix to consider the lock
file entry to be stale since the `original` ref no longer
matches exactly.
For this reason, we canonicalise the `original` ref by
filtering the `dir` query parameter from the URL. */
if (auto url = fetchers::maybeGetStrAttr(flakeRef.input.attrs, "url")) {
try {
auto parsed = parseURL(*url);
if (auto dir2 = get(parsed.query, "dir")) {
if (flakeRef.subdir != "" && flakeRef.subdir == *dir2)
parsed.query.erase("dir");
}
flakeRef.input.attrs.insert_or_assign("url", parsed.to_string());
} catch (BadURL &) {
}
}
return flakeRef;
}
std::tuple<FlakeRef, std::string, ExtendedOutputsSpec> parseFlakeRefWithFragmentAndExtendedOutputsSpec(
const fetchers::Settings & fetchSettings,
const std::string & url,

View File

@@ -115,7 +115,7 @@ struct Flake
}
};
Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool useRegistries);
Flake getFlake(EvalState & state, const FlakeRef & flakeRef, fetchers::UseRegistries useRegistries);
/**
* Fingerprint of a locked flake; used as a cache key.

View File

@@ -65,13 +65,19 @@ struct FlakeRef
FlakeRef resolve(
ref<Store> store,
const fetchers::RegistryFilter & filter = {}) const;
fetchers::UseRegistries useRegistries = fetchers::UseRegistries::All) const;
static FlakeRef fromAttrs(
const fetchers::Settings & fetchSettings,
const fetchers::Attrs & attrs);
std::pair<ref<SourceAccessor>, FlakeRef> lazyFetch(ref<Store> store) const;
/**
* Canonicalize a flakeref for the purpose of comparing "old" and
* "new" `original` fields in lock files.
*/
FlakeRef canonicalize() const;
};
std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef);

View File

@@ -39,13 +39,13 @@ foreach header : [
endforeach
sources = files(
'flake/config.cc',
'flake/flake.cc',
'flake/flakeref.cc',
'flake/lockfile.cc',
'flake/flake-primops.cc',
'flake/settings.cc',
'flake/url-name.cc',
'config.cc',
'flake.cc',
'flakeref.cc',
'lockfile.cc',
'flake-primops.cc',
'settings.cc',
'url-name.cc',
)
subdir('include/nix/flake')

View File

@@ -57,7 +57,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
if (hasPrefix(s.first, prefix))
completions.add(s.first, fmt("Set the `%s` setting.", s.first));
}
}
},
});
addFlag({
@@ -75,7 +75,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
.labels = Strings{"jobs"},
.handler = {[=](std::string s) {
settings.set("max-jobs", s);
}}
}},
});
std::string cat = "Options to override configuration settings";

View File

@@ -6,6 +6,7 @@
#include "nix/util/config-global.hh"
#include "nix/util/signals.hh"
#include "nix/util/file-system.hh"
namespace nix {
@@ -77,13 +78,13 @@ void initPlugins()
for (const auto & pluginFile : pluginSettings.pluginFiles.get()) {
std::vector<std::filesystem::path> pluginFiles;
try {
auto ents = std::filesystem::directory_iterator{pluginFile};
auto ents = DirectoryIterator{pluginFile};
for (const auto & ent : ents) {
checkInterrupt();
pluginFiles.emplace_back(ent.path());
}
} catch (std::filesystem::filesystem_error & e) {
if (e.code() != std::errc::not_a_directory)
} catch (SysError & e) {
if (e.errNo != ENOTDIR)
throw;
pluginFiles.emplace_back(pluginFile);
}

View File

@@ -231,7 +231,7 @@ LegacyArgs::LegacyArgs(const std::string & programName,
.handler = {[=](std::string s) {
auto n = string2IntWithUnitPrefix<uint64_t>(s);
settings.set(dest, std::to_string(n));
}}
}},
});
};

View File

@@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-defaults.drv

View File

@@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-structured-attrs-defaults.drv

View File

@@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-structured-attrs.drv

View File

@@ -1,41 +0,0 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"],\"disallowedRequisites\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"],\"allowedRequisites\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin",
"dev": "/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev",
"out": "/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs"
},
"inputDrvs": {
"/nix/store/4xm4wccqsvagz9gjksn24s7rip2fdy7v-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"out"
]
},
"/nix/store/plsq5jbr5nhgqwcgb2qxw7jchc09dnl8-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"path": "/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin"
},
"dev": {
"path": "/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev"
},
"out": {
"path": "/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs"
}
},
"system": "my-system"
}

View File

@@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes.drv

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-defaults.drv

View File

@@ -0,0 +1,25 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"builder": "/bin/bash",
"name": "advanced-attributes-defaults",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9",
"outputHashAlgo": "sha256",
"outputHashMode": "recursive",
"system": "my-system"
},
"inputDrvs": {},
"inputSrcs": [],
"name": "advanced-attributes-defaults",
"outputs": {
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-structured-attrs-defaults.drv

View File

@@ -0,0 +1,26 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"builder\":\"/bin/bash\",\"name\":\"advanced-attributes-structured-attrs-defaults\",\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"dev\"],\"system\":\"my-system\"}",
"dev": "/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
},
"inputDrvs": {},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs-defaults",
"outputs": {
"dev": {
"hashAlgo": "sha256",
"method": "nar"
},
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv

View File

@@ -0,0 +1,46 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m",
"dev": "/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"hashAlgo": "sha256",
"method": "nar"
},
"dev": {
"hashAlgo": "sha256",
"method": "nar"
},
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes.drv

View File

@@ -0,0 +1,52 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__darwinAllowLocalNetworking": "1",
"__impureHostDeps": "/usr/bin/ditto",
"__noChroot": "1",
"__sandboxProfile": "sandcastle",
"allowSubstitutes": "",
"allowedReferences": "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9",
"allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z",
"builder": "/bin/bash",
"disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g",
"disallowedRequisites": "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8",
"impureEnvVars": "UNICORN",
"name": "advanced-attributes",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9",
"outputHashAlgo": "sha256",
"outputHashMode": "recursive",
"preferLocalBuild": "1",
"requiredSystemFeatures": "rainbow uid-range",
"system": "my-system"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes",
"outputs": {
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-defaults.drv

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-structured-attrs-defaults.drv

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv

View File

@@ -0,0 +1,43 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/nix/store/qjjj3zrlimpjbkk686m052b3ks9iz2sl-advanced-attributes-structured-attrs-bin",
"dev": "/nix/store/lpz5grl48v93pdadavyg5is1rqvfdipf-advanced-attributes-structured-attrs-dev",
"out": "/nix/store/nzvz1bmh1g89a5dkpqcqan0av7q3hgv3-advanced-attributes-structured-attrs"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"path": "/nix/store/qjjj3zrlimpjbkk686m052b3ks9iz2sl-advanced-attributes-structured-attrs-bin"
},
"dev": {
"path": "/nix/store/lpz5grl48v93pdadavyg5is1rqvfdipf-advanced-attributes-structured-attrs-dev"
},
"out": {
"path": "/nix/store/nzvz1bmh1g89a5dkpqcqan0av7q3hgv3-advanced-attributes-structured-attrs"
}
},
"system": "my-system"
}

View File

@@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes.drv

View File

@@ -0,0 +1,49 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__darwinAllowLocalNetworking": "1",
"__impureHostDeps": "/usr/bin/ditto",
"__noChroot": "1",
"__sandboxProfile": "sandcastle",
"allowSubstitutes": "",
"allowedReferences": "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo",
"allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev",
"builder": "/bin/bash",
"disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar",
"disallowedRequisites": "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev",
"impureEnvVars": "UNICORN",
"name": "advanced-attributes",
"out": "/nix/store/swkj0mrq0cq3dfli95v4am0427mi2hxf-advanced-attributes",
"preferLocalBuild": "1",
"requiredSystemFeatures": "rainbow uid-range",
"system": "my-system"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes",
"outputs": {
"out": {
"path": "/nix/store/swkj0mrq0cq3dfli95v4am0427mi2hxf-advanced-attributes"
}
},
"system": "my-system"
}

View File

@@ -18,68 +18,93 @@ using nlohmann::json;
class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest
{
std::filesystem::path unitTestData = getUnitTestData() / "derivation";
protected:
std::filesystem::path unitTestData = getUnitTestData() / "derivation" / "ia";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
/**
* We set these in tests rather than the regular globals so we don't have
* to worry about race conditions if the tests run concurrently.
*/
ExperimentalFeatureSettings mockXpSettings;
};
#define TEST_ATERM_JSON(STEM, NAME) \
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_json) \
{ \
readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*store, std::move(aterm), NAME); \
Derivation got = Derivation::fromJSON(*store, encoded); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_to_json) \
{ \
writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \
return parseDerivation(*store, std::move(aterm), NAME).toJSON(*store); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_aterm) \
{ \
readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*store, json); \
auto got = parseDerivation(*store, std::move(encoded), NAME); \
EXPECT_EQ(got.toJSON(*store), expected.toJSON(*store)); \
EXPECT_EQ(got, expected); \
}); \
} \
\
class CaDerivationAdvancedAttrsTest : public DerivationAdvancedAttrsTest
{
void SetUp() override
{
unitTestData = getUnitTestData() / "derivation" / "ca";
mockXpSettings.set("experimental-features", "ca-derivations");
}
};
template<class Fixture>
class DerivationAdvancedAttrsBothTest : public Fixture
{};
using BothFixtures = ::testing::Types<DerivationAdvancedAttrsTest, CaDerivationAdvancedAttrsTest>;
TYPED_TEST_SUITE(DerivationAdvancedAttrsBothTest, BothFixtures);
#define TEST_ATERM_JSON(STEM, NAME) \
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_json) \
{ \
this->readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings); \
Derivation got = Derivation::fromJSON(*this->store, encoded, this->mockXpSettings); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_to_json) \
{ \
this->writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
return parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings) \
.toJSON(*this->store); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_aterm) \
{ \
this->readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(this->goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*this->store, json, this->mockXpSettings); \
auto got = parseDerivation(*this->store, std::move(encoded), NAME, this->mockXpSettings); \
EXPECT_EQ(got.toJSON(*this->store), expected.toJSON(*this->store)); \
EXPECT_EQ(got, expected); \
}); \
} \
\
/* No corresponding write test, because we need to read the drv to write the json file */
TEST_ATERM_JSON(advancedAttributes_defaults, "advanced-attributes-defaults");
TEST_ATERM_JSON(advancedAttributes, "advanced-attributes-defaults");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attributes-structured-attrs");
TEST_ATERM_JSON(advancedAttributes_defaults, "advanced-attributes");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs, "advanced-attributes-structured-attrs-defaults");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attributes-structured-attrs");
#undef TEST_ATERM_JSON
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
{
readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
@@ -101,25 +126,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
EXPECT_EQ(checksForAllOutputs.disallowedReferences, StringSet{});
EXPECT_EQ(checksForAllOutputs.disallowedRequisites, StringSet{});
}
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet());
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true);
EXPECT_EQ(options.useUidRange(got), false);
});
};
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
@@ -128,34 +178,88 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"});
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
checksForAllOutputs.allowedRequisites,
StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ(
checksForAllOutputs.disallowedRequisites, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
checksForAllOutputs.disallowedRequisites,
StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
}
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttrs_defaults)
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes)
{
readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences,
StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites,
StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences,
StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
checksForAllOutputs.disallowedRequisites,
StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
@@ -176,25 +280,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(checksPerOutput.size(), 0);
}
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet());
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true);
EXPECT_EQ(options.useUidRange(got), false);
});
};
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttrs)
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{
readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
@@ -204,14 +333,40 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true);
{
auto output_ = get(std::get<1>(options.outputChecks), "dev");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909);
}
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
}
{
@@ -219,25 +374,54 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.disallowedReferences, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
EXPECT_EQ(output.disallowedRequisites, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "dev");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909);
EXPECT_EQ(output.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(
output.disallowedReferences, StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};

View File

@@ -73,6 +73,32 @@ TEST(machines, getMachinesWithSemicolonSeparator) {
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesWithCommentsAndSemicolonSeparator) {
auto actual = Machine::parseConfig({},
"# This is a comment ; this is still that comment\n"
"nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl\n"
"# This is also a comment ; this also is still that comment\n"
"nix@scabby.labs.cs.uu.nl\n");
EXPECT_THAT(actual, SizeIs(3));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scabby.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesWithFunnyWhitespace) {
auto actual = Machine::parseConfig({},
" # commment ; comment\n"
" nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl \n"
"\n \n"
"\n ;;; \n"
"\n ; ; \n"
"nix@scabby.labs.cs.uu.nl\n\n");
EXPECT_THAT(actual, SizeIs(3));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scabby.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) {
auto actual = Machine::parseConfig({},
"nix@scratchy.labs.cs.uu.nl i686-linux "

View File

@@ -18,12 +18,12 @@ struct State
/* For each activated package, create symlinks */
static void createLinks(State & state, const Path & srcDir, const Path & dstDir, int priority)
{
std::filesystem::directory_iterator srcFiles;
DirectoryIterator srcFiles;
try {
srcFiles = std::filesystem::directory_iterator{srcDir};
} catch (std::filesystem::filesystem_error & e) {
if (e.code() == std::errc::not_a_directory) {
srcFiles = DirectoryIterator{srcDir};
} catch (SysError & e) {
if (e.errNo == ENOTDIR) {
warn("not including '%s' in the user environment because it's not a directory", srcDir);
return;
}

View File

@@ -29,13 +29,9 @@ void builtinUnpackChannel(
size_t fileCount;
std::string fileName;
try {
auto entries = fs::directory_iterator{out};
fileName = entries->path().string();
fileCount = std::distance(fs::begin(entries), fs::end(entries));
} catch (fs::filesystem_error &) {
throw SysError("failed to read directory %1%", out.string());
}
auto entries = DirectoryIterator{out};
fileName = entries->path().string();
fileCount = std::distance(entries.begin(), entries.end());
if (fileCount != 1)
throw Error("channel tarball '%s' contains more than one file", src);

View File

@@ -68,7 +68,6 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
throw Error("attribute '%s' must be a list of strings", name);
res.insert(j->get<std::string>());
}
checks.disallowedRequisites = res;
return res;
}
return {};

View File

@@ -1368,7 +1368,7 @@ Derivation Derivation::fromJSON(
for (auto & [outputName, output] : getObject(valueAt(json, "outputs"))) {
res.outputs.insert_or_assign(
outputName,
DerivationOutput::fromJSON(store, res.name, outputName, output));
DerivationOutput::fromJSON(store, res.name, outputName, output, xpSettings));
}
} catch (Error & e) {
e.addTrace({}, "while reading key 'outputs'");

View File

@@ -22,10 +22,8 @@
#include <curl/curl.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <random>
#include <thread>
@@ -95,7 +93,7 @@ struct curlFileTransfer : public FileTransfer
: fileTransfer(fileTransfer)
, request(request)
, act(*logger, lvlTalkative, actFileTransfer,
request.post ? "" : fmt(request.data ? "uploading '%s'" : "downloading '%s'", request.uri),
fmt("%sing '%s'", request.verb(), request.uri),
{request.uri}, request.parentAct)
, callback(std::move(callback))
, finalSink([this](std::string_view data) {
@@ -272,19 +270,11 @@ struct curlFileTransfer : public FileTransfer
return getInterrupted();
}
int silentProgressCallback(curl_off_t dltotal, curl_off_t dlnow)
{
return getInterrupted();
}
static int progressCallbackWrapper(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
return ((TransferItem *) userp)->progressCallback(dltotal, dlnow);
}
static int silentProgressCallbackWrapper(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
return ((TransferItem *) userp)->silentProgressCallback(dltotal, dlnow);
auto & item = *static_cast<TransferItem *>(userp);
auto isUpload = bool(item.request.data);
return item.progressCallback(isUpload ? ultotal : dltotal, isUpload ? ulnow : dlnow);
}
static int debugCallback(CURL * handle, curl_infotype type, char * data, size_t size, void * userptr)
@@ -319,6 +309,23 @@ struct curlFileTransfer : public FileTransfer
}
#endif
size_t seekCallback(curl_off_t offset, int origin)
{
if (origin == SEEK_SET) {
readOffset = offset;
} else if (origin == SEEK_CUR) {
readOffset += offset;
} else if (origin == SEEK_END) {
readOffset = request.data->length() + offset;
}
return CURL_SEEKFUNC_OK;
}
static size_t seekCallbackWrapper(void *clientp, curl_off_t offset, int origin)
{
return ((TransferItem *) clientp)->seekCallback(offset, origin);
}
void init()
{
if (!req) req = curl_easy_init();
@@ -351,10 +358,7 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_HEADERFUNCTION, TransferItem::headerCallbackWrapper);
curl_easy_setopt(req, CURLOPT_HEADERDATA, this);
if (request.post)
curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, silentProgressCallbackWrapper);
else
curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, progressCallbackWrapper);
curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, progressCallbackWrapper);
curl_easy_setopt(req, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(req, CURLOPT_NOPROGRESS, 0);
@@ -374,6 +378,8 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_READFUNCTION, readCallbackWrapper);
curl_easy_setopt(req, CURLOPT_READDATA, this);
curl_easy_setopt(req, CURLOPT_INFILESIZE_LARGE, (curl_off_t) request.data->length());
curl_easy_setopt(req, CURLOPT_SEEKFUNCTION, seekCallbackWrapper);
curl_easy_setopt(req, CURLOPT_SEEKDATA, this);
}
if (request.verifyTLS) {
@@ -447,8 +453,7 @@ struct curlFileTransfer : public FileTransfer
if (httpStatus == 304 && result.etag == "")
result.etag = request.expectedETag;
if (!request.post)
act.progress(result.bodySize, result.bodySize);
act.progress(result.bodySize, result.bodySize);
done = true;
callback(std::move(result));
}
@@ -537,6 +542,8 @@ struct curlFileTransfer : public FileTransfer
warn("%s; retrying from offset %d in %d ms", exc.what(), writtenToSink, ms);
else
warn("%s; retrying in %d ms", exc.what(), ms);
decompressionSink.reset();
errorSink.reset();
embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms);
fileTransfer.enqueueItem(shared_from_this());
}
@@ -789,10 +796,6 @@ struct curlFileTransfer : public FileTransfer
S3Helper s3Helper(profile, region, scheme, endpoint);
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("downloading '%s'", request.uri),
{request.uri}, request.parentAct);
// FIXME: implement ETag
auto s3Res = s3Helper.getObject(bucketName, key);
FileTransferResult res;

View File

@@ -164,7 +164,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
{
/* Read the `temproots' directory for per-process temporary root
files. */
for (auto & i : std::filesystem::directory_iterator{tempRootsDir}) {
for (auto & i : DirectoryIterator{tempRootsDir}) {
checkInterrupt();
auto name = i.path().filename().string();
if (name[0] == '.') {
@@ -232,7 +232,7 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
type = std::filesystem::symlink_status(path).type();
if (type == std::filesystem::file_type::directory) {
for (auto & i : std::filesystem::directory_iterator{path}) {
for (auto & i : DirectoryIterator{path}) {
checkInterrupt();
findRoots(i.path().string(), i.symlink_status().type(), roots);
}

View File

@@ -278,21 +278,21 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
.aliases = aliases,
.description = "Enable sandboxing.",
.category = category,
.handler = {[this]() { override(smEnabled); }}
.handler = {[this]() { override(smEnabled); }},
});
args.addFlag({
.longName = "no-" + name,
.aliases = aliases,
.description = "Disable sandboxing.",
.category = category,
.handler = {[this]() { override(smDisabled); }}
.handler = {[this]() { override(smDisabled); }},
});
args.addFlag({
.longName = "relaxed-" + name,
.aliases = aliases,
.description = "Enable sandboxing, but allow builds to disable it.",
.category = category,
.handler = {[this]() { override(smRelaxed); }}
.handler = {[this]() { override(smRelaxed); }},
});
}

View File

@@ -77,7 +77,7 @@ struct FileTransferRequest
FileTransferRequest(std::string_view uri)
: uri(uri), parentAct(getCurActivity()) { }
std::string verb()
std::string verb() const
{
return data ? "upload" : "download";
}

View File

@@ -1,6 +1,5 @@
include_dirs += include_directories('../..')
headers += files(
'fchmodat2-compat.hh',
'personality.hh',
)

View File

@@ -84,7 +84,7 @@ protected:
{
StorePathSet paths;
for (auto & entry : std::filesystem::directory_iterator{binaryCacheDir}) {
for (auto & entry : DirectoryIterator{binaryCacheDir}) {
checkInterrupt();
auto name = entry.path().filename().string();
if (name.size() != 40 ||

View File

@@ -85,7 +85,7 @@ The parts of a local overlay store are as follows:
> The location of the database instead depends on the [`state`](#store-experimental-local-overlay-store-state) setting.
> It is always `${state}/db`.
This contains the metadata of all of the upper layer [store objects][store object] (everything beyond their file system objects), and also duplicate copies of some lower layer store object's metadta.
This contains the metadata of all of the upper layer [store objects][store object] (everything beyond their file system objects), and also duplicate copies of some lower layer store object's metadata.
The duplication is so the metadata for the [closure](@docroot@/glossary.md#gloss-closure) of upper layer [store objects][store object] can be found entirely within the upper layer.
(This allows us to use the same SQL Schema as the [local store]'s SQLite database, as foreign keys in that schema enforce closure metadata to be self-contained in this way.)

View File

@@ -249,7 +249,7 @@ LocalStore::LocalStore(
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
openDB(*state, true);
writeFile(schemaPath, fmt("%1%", curSchema), 0666, true);
writeFile(schemaPath, fmt("%1%", curSchema), 0666, FsSync::Yes);
}
else if (curSchema < nixSchemaVersion) {
@@ -300,7 +300,7 @@ LocalStore::LocalStore(
txn.commit();
}
writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true);
writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, FsSync::Yes);
lockFile(globalLock.get(), ltRead, true);
}
@@ -1386,7 +1386,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
printInfo("checking link hashes...");
for (auto & link : std::filesystem::directory_iterator{linksDir}) {
for (auto & link : DirectoryIterator{linksDir}) {
checkInterrupt();
auto name = link.path().filename();
printMsg(lvlTalkative, "checking contents of '%s'", name);
@@ -1479,7 +1479,7 @@ LocalStore::VerificationResult LocalStore::verifyAllValidPaths(RepairFlag repair
database and the filesystem) in the loop below, in order to catch
invalid states.
*/
for (auto & i : std::filesystem::directory_iterator{realStoreDir.to_string()}) {
for (auto & i : DirectoryIterator{realStoreDir.to_string()}) {
checkInterrupt();
try {
storePathsInStoreDir.insert({i.path().filename().string()});

View File

@@ -105,28 +105,31 @@ ref<Store> Machine::openStore() const
static std::vector<std::string> expandBuilderLines(const std::string & builders)
{
std::vector<std::string> result;
for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n;")) {
trim(line);
for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n")) {
line.erase(std::find(line.begin(), line.end(), '#'), line.end());
if (line.empty()) continue;
for (auto entry : tokenizeString<std::vector<std::string>>(line, ";")) {
entry = trim(entry);
if (line[0] == '@') {
const std::string path = trim(std::string(line, 1));
std::string text;
try {
text = readFile(path);
} catch (const SysError & e) {
if (e.errNo != ENOENT)
throw;
debug("cannot find machines file '%s'", path);
if (entry.empty()) {
// skip blank entries
} else if (entry[0] == '@') {
const std::string path = trim(std::string_view{entry}.substr(1));
std::string text;
try {
text = readFile(path);
} catch (const SysError & e) {
if (e.errNo != ENOENT)
throw;
debug("cannot find machines file '%s'", path);
continue;
}
const auto entrys = expandBuilderLines(text);
result.insert(end(result), begin(entrys), end(entrys));
} else {
result.emplace_back(entry);
}
const auto lines = expandBuilderLines(text);
result.insert(end(result), begin(lines), end(lines));
continue;
}
result.emplace_back(line);
}
return result;
}

View File

@@ -176,7 +176,7 @@ NarInfo NarInfo::fromJSON(
std::nullopt);
if (json.contains("downloadSize"))
res.fileSize = getInteger(valueAt(json, "downloadSize"));
res.fileSize = getUnsigned(valueAt(json, "downloadSize"));
return res;
}

View File

@@ -192,7 +192,7 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(
auto & json = getObject(_json);
res.narHash = Hash::parseAny(getString(valueAt(json, "narHash")), std::nullopt);
res.narSize = getInteger(valueAt(json, "narSize"));
res.narSize = getUnsigned(valueAt(json, "narSize"));
try {
auto references = getStringList(valueAt(json, "references"));
@@ -216,7 +216,7 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(
if (json.contains("registrationTime"))
if (auto * rawRegistrationTime = getNullable(valueAt(json, "registrationTime")))
res.registrationTime = getInteger(*rawRegistrationTime);
res.registrationTime = getInteger<time_t>(*rawRegistrationTime);
if (json.contains("ultimate"))
res.ultimate = getBoolean(valueAt(json, "ultimate"));

View File

@@ -136,7 +136,7 @@ static void canonicalisePathMetaData_(
#endif
if (S_ISDIR(st.st_mode)) {
for (auto & i : std::filesystem::directory_iterator{path}) {
for (auto & i : DirectoryIterator{path}) {
checkInterrupt();
canonicalisePathMetaData_(
i.path().string(),

View File

@@ -38,7 +38,7 @@ std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path pro
std::filesystem::path profileDir = dirOf(profile);
auto profileName = std::string(baseNameOf(profile));
for (auto & i : std::filesystem::directory_iterator{profileDir}) {
for (auto & i : DirectoryIterator{profileDir}) {
checkInterrupt();
if (auto n = parseName(profileName, i.path().filename().string())) {
auto path = i.path().string();

View File

@@ -160,7 +160,10 @@ ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(
S3Helper::FileTransferResult S3Helper::getObject(
const std::string & bucketName, const std::string & key)
{
debug("fetching 's3://%s/%s'...", bucketName, key);
std::string uri = "s3://" + bucketName + "/" + key;
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("downloading '%s'", uri),
Logger::Fields{uri}, getCurActivity());
auto request =
Aws::S3::Model::GetObjectRequest()
@@ -171,6 +174,22 @@ S3Helper::FileTransferResult S3Helper::getObject(
return Aws::New<std::stringstream>("STRINGSTREAM");
});
size_t bytesDone = 0;
size_t bytesExpected = 0;
request.SetDataReceivedEventHandler([&](const Aws::Http::HttpRequest * req, Aws::Http::HttpResponse * resp, long long l) {
if (!bytesExpected && resp->HasHeader("Content-Length")) {
if (auto length = string2Int<size_t>(resp->GetHeader("Content-Length"))) {
bytesExpected = *length;
}
}
bytesDone += l;
act.progress(bytesDone, bytesExpected);
});
request.SetContinueRequestHandler([](const Aws::Http::HttpRequest*) {
return !isInterrupted();
});
FileTransferResult res;
auto now1 = std::chrono::steady_clock::now();
@@ -180,6 +199,8 @@ S3Helper::FileTransferResult S3Helper::getObject(
auto result = checkAws(fmt("AWS error fetching '%s'", key),
client->GetObject(request));
act.progress(result.GetContentLength(), result.GetContentLength());
res.data = decompress(result.GetContentEncoding(),
dynamic_cast<std::stringstream &>(result.GetBody()).str());
@@ -307,11 +328,35 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::shared_ptr<TransferManager> transferManager;
std::once_flag transferManagerCreated;
struct AsyncContext : public Aws::Client::AsyncCallerContext
{
mutable std::mutex mutex;
mutable std::condition_variable cv;
const Activity & act;
void notify() const
{
cv.notify_one();
}
void wait() const
{
std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk);
}
AsyncContext(const Activity & act) : act(act) {}
};
void uploadFile(const std::string & path,
std::shared_ptr<std::basic_iostream<char>> istream,
const std::string & mimeType,
const std::string & contentEncoding)
{
std::string uri = "s3://" + bucketName + "/" + path;
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("uploading '%s'", uri),
Logger::Fields{uri}, getCurActivity());
istream->seekg(0, istream->end);
auto size = istream->tellg();
istream->seekg(0, istream->beg);
@@ -330,16 +375,25 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
transferConfig.bufferSize = bufferSize;
transferConfig.uploadProgressCallback =
[](const TransferManager *transferManager,
const std::shared_ptr<const TransferHandle>
&transferHandle)
[](const TransferManager * transferManager,
const std::shared_ptr<const TransferHandle> & transferHandle)
{
//FIXME: find a way to properly abort the multipart upload.
//checkInterrupt();
debug("upload progress ('%s'): '%d' of '%d' bytes",
transferHandle->GetKey(),
transferHandle->GetBytesTransferred(),
transferHandle->GetBytesTotalSize());
auto context = std::dynamic_pointer_cast<const AsyncContext>(transferHandle->GetContext());
size_t bytesDone = transferHandle->GetBytesTransferred();
size_t bytesTotal = transferHandle->GetBytesTotalSize();
try {
checkInterrupt();
context->act.progress(bytesDone, bytesTotal);
} catch (...) {
context->notify();
}
};
transferConfig.transferStatusUpdatedCallback =
[](const TransferManager * transferManager,
const std::shared_ptr<const TransferHandle> & transferHandle)
{
auto context = std::dynamic_pointer_cast<const AsyncContext>(transferHandle->GetContext());
context->notify();
};
transferManager = TransferManager::Create(transferConfig);
@@ -353,29 +407,51 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
if (contentEncoding != "")
throw Error("setting a content encoding is not supported with S3 multi-part uploads");
auto context = std::make_shared<AsyncContext>(act);
std::shared_ptr<TransferHandle> transferHandle =
transferManager->UploadFile(
istream, bucketName, path, mimeType,
Aws::Map<Aws::String, Aws::String>(),
nullptr /*, contentEncoding */);
context /*, contentEncoding */);
transferHandle->WaitUntilFinished();
TransferStatus status = transferHandle->GetStatus();
while (status == TransferStatus::IN_PROGRESS || status == TransferStatus::NOT_STARTED) {
if (!isInterrupted()) {
context->wait();
} else {
transferHandle->Cancel();
transferHandle->WaitUntilFinished();
}
status = transferHandle->GetStatus();
}
act.progress(transferHandle->GetBytesTransferred(), transferHandle->GetBytesTotalSize());
if (transferHandle->GetStatus() == TransferStatus::FAILED)
if (status == TransferStatus::FAILED)
throw Error("AWS error: failed to upload 's3://%s/%s': %s",
bucketName, path, transferHandle->GetLastError().GetMessage());
if (transferHandle->GetStatus() != TransferStatus::COMPLETED)
if (status != TransferStatus::COMPLETED)
throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state",
bucketName, path);
} else {
act.progress(0, size);
auto request =
Aws::S3::Model::PutObjectRequest()
.WithBucket(bucketName)
.WithKey(path);
size_t bytesSent = 0;
request.SetDataSentEventHandler([&](const Aws::Http::HttpRequest * req, long long l) {
bytesSent += l;
act.progress(bytesSent, size);
});
request.SetContinueRequestHandler([](const Aws::Http::HttpRequest*) {
return !isInterrupted();
});
request.SetContentType(mimeType);
if (contentEncoding != "")
@@ -385,6 +461,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto result = checkAws(fmt("AWS error uploading '%s'", path),
s3Helper.client->PutObject(request));
act.progress(size, size);
}
auto now2 = std::chrono::steady_clock::now();

View File

@@ -42,7 +42,7 @@
/* Includes required for chroot support. */
#ifdef __linux__
# include "nix/store/fchmodat2-compat.hh"
# include "linux/fchmodat2-compat.hh"
# include <sys/ioctl.h>
# include <net/if.h>
# include <netinet/ip.h>
@@ -567,7 +567,14 @@ void LocalDerivationGoal::startBuilder()
} else {
tmpDir = topTmpDir;
}
chownToBuilder(tmpDir);
/* The TOCTOU between the previous mkdir call and this open call is unavoidable due to
POSIX semantics.*/
tmpDirFd = AutoCloseFD{open(tmpDir.c_str(), O_RDONLY | O_NOFOLLOW | O_DIRECTORY)};
if (!tmpDirFd)
throw SysError("failed to open the build temporary directory descriptor '%1%'", tmpDir);
chownToBuilder(tmpDirFd.get(), tmpDir);
for (auto & [outputName, status] : initialOutputs) {
/* Set scratch path we'll actually use during the build.
@@ -1159,9 +1166,7 @@ void LocalDerivationGoal::initTmpDir()
} else {
auto hash = hashString(HashAlgorithm::SHA256, i.first);
std::string fn = ".attr-" + hash.to_string(HashFormat::Nix32, false);
Path p = tmpDir + "/" + fn;
writeFile(p, rewriteStrings(i.second, inputRewrites));
chownToBuilder(p);
writeBuilderFile(fn, rewriteStrings(i.second, inputRewrites));
env[i.first + "Path"] = tmpDirInSandbox + "/" + fn;
}
}
@@ -1266,11 +1271,9 @@ void LocalDerivationGoal::writeStructuredAttrs()
auto jsonSh = writeStructuredAttrsShell(json);
writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites));
chownToBuilder(tmpDir + "/.attrs.sh");
writeBuilderFile(".attrs.sh", rewriteStrings(jsonSh, inputRewrites));
env["NIX_ATTRS_SH_FILE"] = tmpDirInSandbox + "/.attrs.sh";
writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites));
chownToBuilder(tmpDir + "/.attrs.json");
writeBuilderFile(".attrs.json", rewriteStrings(json.dump(), inputRewrites));
env["NIX_ATTRS_JSON_FILE"] = tmpDirInSandbox + "/.attrs.json";
}
}
@@ -1781,6 +1784,24 @@ void setupSeccomp()
#endif
}
void LocalDerivationGoal::chownToBuilder(int fd, const Path & path)
{
if (!buildUser) return;
if (fchown(fd, buildUser->getUID(), buildUser->getGID()) == -1)
throw SysError("cannot change ownership of file '%1%'", path);
}
void LocalDerivationGoal::writeBuilderFile(
const std::string & name,
std::string_view contents)
{
auto path = std::filesystem::path(tmpDir) / name;
AutoCloseFD fd{openat(tmpDirFd.get(), name.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC | O_EXCL | O_NOFOLLOW, 0666)};
if (!fd)
throw SysError("creating file %s", path);
writeFile(fd, path, contents);
chownToBuilder(fd.get(), path);
}
void LocalDerivationGoal::runChild()
{
@@ -3000,6 +3021,15 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
void LocalDerivationGoal::deleteTmpDir(bool force)
{
if (topTmpDir != "") {
/* As an extra precaution, even in the event of `deletePath` failing to
* clean up, the `tmpDir` will be chowned as if we were to move
* it inside the Nix store.
*
* This hardens against an attack which smuggles a file descriptor
* to make use of the temporary directory.
*/
chmod(topTmpDir.c_str(), 0000);
/* Don't keep temporary directories for builtins because they
might have privileged stuff (like a copy of netrc). */
if (settings.keepFailed && !force && !drv->isBuiltin()) {

View File

@@ -37,6 +37,11 @@ struct LocalDerivationGoal : public DerivationGoal
*/
Path topTmpDir;
/**
* The file descriptor of the temporary directory.
*/
AutoCloseFD tmpDirFd;
/**
* The path of the temporary directory in the sandbox.
*/
@@ -239,9 +244,24 @@ struct LocalDerivationGoal : public DerivationGoal
/**
* Make a file owned by the builder.
*
* SAFETY: this function is prone to TOCTOU as it receives a path and not a descriptor.
* It's only safe to call in a child of a directory only visible to the owner.
*/
void chownToBuilder(const Path & path);
/**
* Make a file owned by the builder addressed by its file descriptor.
*/
void chownToBuilder(int fd, const Path & path);
/**
* Create a file in `tmpDir` owned by the builder.
*/
void writeBuilderFile(
const std::string & name,
std::string_view contents);
int getChildStatus() override;
/**

View File

@@ -1,41 +0,0 @@
#pragma once
#include "nix/util/fs-sink.hh"
namespace nix::test {
/**
* A `FileSystemObjectSink` that traces calls, writing to stderr.
*/
class TracingFileSystemObjectSink : public virtual FileSystemObjectSink
{
FileSystemObjectSink & sink;
public:
TracingFileSystemObjectSink(FileSystemObjectSink & sink)
: sink(sink)
{
}
void createDirectory(const CanonPath & path) override;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn) override;
void createSymlink(const CanonPath & path, const std::string & target) override;
};
/**
* A `ExtendedFileSystemObjectSink` that traces calls, writing to stderr.
*/
class TracingExtendedFileSystemObjectSink : public TracingFileSystemObjectSink, public ExtendedFileSystemObjectSink
{
ExtendedFileSystemObjectSink & sink;
public:
TracingExtendedFileSystemObjectSink(ExtendedFileSystemObjectSink & sink)
: TracingFileSystemObjectSink(sink)
, sink(sink)
{
}
void createHardlink(const CanonPath & path, const CanonPath & target) override;
};
}

View File

@@ -1,34 +0,0 @@
#include <iostream>
#include "nix/tracing-file-system-object-sink.hh"
namespace nix::test {
void TracingFileSystemObjectSink::createDirectory(const CanonPath & path)
{
std::cerr << "createDirectory(" << path << ")\n";
sink.createDirectory(path);
}
void TracingFileSystemObjectSink::createRegularFile(
const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn)
{
std::cerr << "createRegularFile(" << path << ")\n";
sink.createRegularFile(path, [&](CreateRegularFileSink & crf) {
// We could wrap this and trace about the chunks of data and such
fn(crf);
});
}
void TracingFileSystemObjectSink::createSymlink(const CanonPath & path, const std::string & target)
{
std::cerr << "createSymlink(" << path << ", target: " << target << ")\n";
sink.createSymlink(path, target);
}
void TracingExtendedFileSystemObjectSink::createHardlink(const CanonPath & path, const CanonPath & target)
{
std::cerr << "createHardlink(" << path << ", target: " << target << ")\n";
sink.createHardlink(path, target);
}
} // namespace nix::test

View File

@@ -1,3 +1,4 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "nix/util/file-content-address.hh"
@@ -26,8 +27,11 @@ TEST(FileSerialisationMethod, testRoundTripPrintParse_2) {
}
}
TEST(FileSerialisationMethod, testParseFileSerialisationMethodOptException) {
EXPECT_THROW(parseFileSerialisationMethod("narwhal"), UsageError);
TEST(FileSerialisationMethod, testParseFileSerialisationMethodOptException)
{
EXPECT_THAT(
[]() { parseFileSerialisationMethod("narwhal"); },
testing::ThrowsMessage<UsageError>(testing::HasSubstr("narwhal")));
}
/* ----------------------------------------------------------------------------
@@ -54,8 +58,11 @@ TEST(FileIngestionMethod, testRoundTripPrintParse_2) {
}
}
TEST(FileIngestionMethod, testParseFileIngestionMethodOptException) {
EXPECT_THROW(parseFileIngestionMethod("narwhal"), UsageError);
TEST(FileIngestionMethod, testParseFileIngestionMethodOptException)
{
EXPECT_THAT(
[]() { parseFileIngestionMethod("narwhal"); },
testing::ThrowsMessage<UsageError>(testing::HasSubstr("narwhal")));
}
}

View File

@@ -275,4 +275,26 @@ TEST(makeParentCanonical, root)
{
ASSERT_EQ(makeParentCanonical("/"), "/");
}
/* ----------------------------------------------------------------------------
* DirectoryIterator
* --------------------------------------------------------------------------*/
TEST(DirectoryIterator, works)
{
auto tmpDir = nix::createTempDir();
nix::AutoDelete delTmpDir(tmpDir, true);
nix::writeFile(tmpDir + "/somefile", "");
for (auto path : DirectoryIterator(tmpDir)) {
ASSERT_EQ(path.path().string(), tmpDir + "/somefile");
}
}
TEST(DirectoryIterator, nonexistent)
{
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SysError);
}
}

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