Compare commits

...

767 Commits

Author SHA1 Message Date
internal-nix-ci[bot]
d340f188c6 Merge pull request #15342 from NixOS/backport-15341-to-2.32-maintenance
[Backport 2.32-maintenance] Fix the nix-community/patsh/0.2.1 flake regression test (again)
2026-02-26 00:14:00 +00:00
Eelco Dolstra
3c23b8170c Fix the nix-community/patsh/0.2.1 flake regression test (again)
(cherry picked from commit 2334977863)
2026-02-25 23:39:53 +00:00
Sergei Zimmerman
5968add551 Bump version 2026-02-25 14:27:40 +03:00
Sergei Zimmerman
8dce03d1bf Merge pull request #15260 from obsidiansystems/backport-15252-to-2.32-maintenance
[Backport 2.32-maintenance] upload-release: disable containerd image store to preserve gzip layer compression
2026-02-17 02:23:28 +03:00
Amaan Qureshi
e08987ac51 upload-release: disable containerd image store to preserve gzip layer compression
(cherry picked from commit 2ccb8a9a56)
2026-02-16 17:52:27 -05:00
internal-nix-ci[bot]
ebd7b8f6ed Merge pull request #15165 from NixOS/backport-15160-to-2.32-maintenance
[Backport 2.32-maintenance] builtins.flakeRefToString: Evaluate attributes
2026-02-06 19:30:14 +00:00
Eelco Dolstra
afc4aced62 builtins.flakeRefToString: Evaluate attributes
Fixes "attribute 'x' is a thunk".

(cherry picked from commit 2989a23fca)
2026-02-06 18:59:56 +00:00
internal-nix-ci[bot]
59209bf9ba Merge pull request #15139 from NixOS/backport-15134-to-2.32-maintenance
[Backport 2.32-maintenance] Fix: `QueryPathInfo` throws on invalid path error in daemon
2026-02-03 23:11:24 +00:00
Peter Bynum
aa9553503d Fix QueryPathInfo in daemon
(cherry picked from commit b9c77ecafc)
2026-02-03 22:19:23 +00:00
John Ericson
989f7a3f12 Merge pull request #15087 from NixOS/backport-15078-to-2.32-maintenance
[Backport 2.33-maintenance] Fix destruction of DerivationBuilder implementations
2026-01-26 16:20:59 -05:00
Sergei Zimmerman
3ca2ce200f Fix destruction of DerivationBuilder implementations
This unsures that we call the correct virtual functions when destroying a particular
DerivationBuilder.

Usually the order of destructors is in the reverse order of inheritance:

ChrootLinuxDerivationBuilder -> ChrootDerivationBuilder -> DerivationBuilderImpl

autoDelChroot was being destroyed before the DerivationBuilderImpl::killChild was
run and it would fail to clean up the chroot directory, since there were still processes
writing to it. Note that ChrootLinuxDerivationBuilder::killSandbox was never run in
the interrupted case at all, since virtual functions in destructors do not call derived class
methods.

I could reproduce the issue with the following derivation:

let
  pkgs = import <nixpkgs> { };
in
pkgs.runCommand "chroot-cleanup-race" { } ''
  mkdir -p $out

  for i in $(seq 1 200); do
    (
      mkfifo $out/fifo$i
      cat $out/fifo$i > /dev/null &

      while true; do
        : > $out/file$i
      done
    ) &
  done

  sleep 0.05
  echo done > $out/main
''

While interrupting it manually when it would hang.

Wrapping the unique pointer in a custom deleter function we can run all
of the necessary clean up code consistently and calling the right virtual
functions. Ideally we'd have a lint that bans the usage of virtual functions
in destructors completely.

(cherry picked from commit b752c5cb64)
(cherry picked from commit 70ecd8c8a9)
2026-01-26 14:45:48 -05:00
internal-nix-ci[bot]
c3687f4f95 Merge pull request #15066 from NixOS/backport-15062-to-2.32-maintenance
[Backport 2.32-maintenance] ci: Drop magic-nix-cache
2026-01-23 01:08:10 +00:00
Sergei Zimmerman
278d8e58d2 ci: Drop magic-nix-cache
We are now seeing. I guess we are out with the cache. When the API responds with 418 (I'm a teapot)
it seems like the only reasonable solution is to oblige.

error: unable to download 'http://127.0.0.1:37515/7ms9f25xyxavf32pvdc3vb28nzzmkbn3.narinfo': HTTP error 418
       response body:
       GitHub API error: GitHub Actions Cache throttled Magic Nix Cache. Not trying to use it again on this run.
(cherry picked from commit dae41e06e8)
2026-01-23 00:35:21 +00:00
internal-nix-ci[bot]
9713638cda Merge pull request #15035 from NixOS/backport-15031-to-2.32-maintenance
[Backport 2.32-maintenance] ci: Bump magic-nix-cache to disable on 429
2026-01-21 05:23:03 +00:00
Sergei Zimmerman
f170bb7b41 ci: Bump magic-nix-cache to disable on 429
(cherry picked from commit 1555677cd5)
2026-01-21 04:50:15 +00:00
internal-nix-ci[bot]
b601b44de5 Merge pull request #14976 from NixOS/backport-14961-to-2.32-maintenance
[Backport 2.32-maintenance] libutil/union-source-accessor: Barf on non-existent directories
2026-01-11 19:39:19 +00:00
Sergei Zimmerman
2a79b7765c libutil/union-source-accessor: Barf on non-existent directories
Previously builtins.readDir would return an empty attribute set
instead of barfing on non-existent paths. This is a regression from
2.32 for impure eval.

(cherry picked from commit 4ab2cdacfc)
2026-01-11 19:02:53 +00:00
internal-nix-ci[bot]
5a842aa155 Merge pull request #14943 from NixOS/backport-14778-to-2.32-maintenance
[Backport 2.32-maintenance] test: add shebangs to shell.nix test scripts
2026-01-07 14:23:00 +00:00
Agustín Covarrubias
803eaf9ef3 test: add shebangs to shell.nix test scripts
Fix intermittent SIGSEGV (exit code 139) on macOS when running
  nix-shell and shebang tests inside the nix sandbox.

  The foo, bar, and ruby test scripts were created without shebangs,
  which causes intermittent crashes when executed via command
  substitution on macOS. Adding proper shebangs resolves the flakiness.

  Potentially closes: #13106

(cherry picked from commit 7b3d7eb634)
2026-01-07 13:50:17 +00:00
Sergei Zimmerman
394a8da9dd Bump version 2026-01-02 18:17:09 +03:00
Sergei Zimmerman
0398ee1f7e Release notes 2026-01-02 16:12:03 +03:00
internal-nix-ci[bot]
105e54078f Merge pull request #14907 from NixOS/backport-14903-to-2.32-maintenance
[Backport 2.32-maintenance] upload-release.pl: Fix up nix-channels bucket location, use awscli2
2026-01-01 21:31:06 +00:00
Sergei Zimmerman
e7b9f0167f upload-release.pl: Fix up nix-channels bucket location, use awscli2
I messed up and accidentally configured the S3 client to use the same
host as the nix-releases bucket, but nix-channels is us-east-1 and
nix-releases is eu-west-1.

(cherry picked from commit 0900638f1d)
2026-01-01 21:17:48 +00:00
internal-nix-ci[bot]
41ed8d3c62 Merge pull request #14901 from NixOS/backport-14888-to-2.32-maintenance
[Backport 2.32-maintenance] ci: GitHub releng for release automation
2026-01-01 15:16:47 +00:00
Sergei Zimmerman
544f8e24b0 release-process: Document usage of upload-release.yml workflow
(cherry picked from commit 84ff2ef347)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
29acca3ad6 upload-release: Only upload the newly created tag
(cherry picked from commit 3933e45d52)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
44cfdd0b01 upload-release: Also push to GHCR as part of the release process
(cherry picked from commit a1569458cc)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
485d9c522f ci: Add upload-release.yml
This workflow is supposed to automate release uploads by using OIDC
for AWS setup. DockerHub still uses long-lived credentials, but that's
not fixable. In a follow-up we could set up release uploads to GHCR too.

(cherry picked from commit 4599daa10e)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
4b161a8684 maintainers: Document git tag signing
Previously it was only Eeclo doing releases that were signed with
B541D55301270E0BCF15CA5D8170B4726D7198DE. Other linux distributions
have the expectation (rightfully so) that our tags are signed. Let's
document this.

We could do cross-signing to make tracing the chain of trust easier
for all Nix team members [1].

[1]: https://nixos.org/community/teams/nix/

(cherry picked from commit 6cb8b58a47)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
c5eebac667 maintainers/upload-release.pl: Make more configurable
This allows for testing with a local minio deployment like:

./upload-release.pl --skip-docker --skip-git --s3-endpoint http://localhost:9000 --s3-host localhost:9000 1821360

(cherry picked from commit d19b8d5f99)
2026-01-01 14:45:31 +00:00
Sergei Zimmerman
feafdeb174 Merge pull request #14882 from xokdvium/backport-14874-to-2.32-maintenance 2025-12-28 20:24:21 +03:00
Sergei Zimmerman
d6342a8656 ci: Make docker-push workflow more configurable
This should allow reusing this workflow (with more tweaks)
in the releng workflow.

(cherry picked from commit c867ed6726)
2025-12-28 19:14:59 +03:00
Sergei Zimmerman
4624f61dfb ci: Pin actions in docker-push reusable workflow
(cherry picked from commit fb05f6de0d)
2025-12-28 19:14:58 +03:00
Sergei Zimmerman
be2053886d ci: Move docker_push_image into a separate workflow
Best reviewed with -w --color-moved. This just moves the code
into a separate workflow. This will allow us to reuse it in
the release job for github releng of releases.

(cherry picked from commit 745983dfc0)
2025-12-28 19:14:55 +03:00
Sergei Zimmerman
9e842a3bfc ci: Bump magic-nix-cache with post-build-hook fix
No tagged release with the fix for [^].

[^]: 578f01e147

(cherry picked from commit 4c4eb5d07f)
2025-12-28 19:14:41 +03:00
Sergei Zimmerman
7644508957 ci: Move magic-nix-cache-action into install-nix-action composite
This reduces duplication and pins the underlying version of magic-nix-cache,
as we already do with other actions.

(cherry picked from commit ad5c6a53b9)
2025-12-28 19:14:40 +03:00
Seth Flynn
47c4378634 ci: allow for using the latest build of the experimental installer
Until these repos are potentially merged, this is good for dogfooding
alongside the experimental installer. It also uses the more official
`artifacts.nixos.org` endpoint to install stable releases now

More immediately though, we need a patch for the experimental installer
to really work in CI at all, and that hasn't landed in a tag yet. So,
this lets us use it right from `main`!

(cherry picked from commit 92d7381826)
2025-12-28 19:14:39 +03:00
Seth Flynn
b245f7a744 ci: enable use of the experimental installer
(cherry picked from commit 2cbbb63628)
2025-12-28 19:14:35 +03:00
internal-nix-ci[bot]
271a0b784e Merge pull request #14859 from NixOS/backport-14792-to-2.32-maintenance
[Backport 2.32-maintenance] Fix `curl` with `c-ares` failing to resolve DNS inside sandbox on macOS
2025-12-23 10:24:26 +00:00
Michael Hoang
4517c162d6 Fix curl with c-ares failing to resolve DNS inside sandbox on macOS
(cherry picked from commit 7541129f04)
2025-12-23 09:53:32 +00:00
internal-nix-ci[bot]
5b4fec4125 Merge pull request #14849 from NixOS/backport-14785-to-2.32-maintenance
[Backport 2.32-maintenance] libstore: include path in the world-writable error
2025-12-21 19:11:02 +00:00
yawkar
5b0b65ee6a libstore: include path in the world-writable error
The previous error message was ambiguous about which specific directory failed the check.

This commit updates checkNotWorldWritable to return the failing path so it can be included in the error message, making debugging easier.

(cherry picked from commit a1e24fa6ce)
2025-12-21 18:37:23 +00:00
internal-nix-ci[bot]
e398f43632 Merge pull request #14839 from NixOS/backport-14837-to-2.32-maintenance
[Backport 2.32-maintenance] libstore/store-api: Do not query all substituters for substitutable p…
2025-12-19 15:25:30 +00:00
Sergei Zimmerman
f9f38cddd2 libstore/store-api: Do not query all substituters for substitutable path infos
This was broken in 11d7c80370.

(cherry picked from commit 2308f200c8)
2025-12-19 14:48:24 +00:00
internal-nix-ci[bot]
256fdf31e6 Merge pull request #14782 from NixOS/backport-14772-to-2.32-maintenance
[Backport 2.32-maintenance] [libstore]: Fix a heap-use-after-free bug
2025-12-13 01:37:03 +00:00
Graham Dennis
103b38bfdc [libstore]: Fix a heap-use-after-free bug
(cherry picked from commit 819a61acae)
2025-12-13 01:07:54 +00:00
internal-nix-ci[bot]
ad0fa9e2c6 Merge pull request #14748 from NixOS/backport-14745-to-2.32-maintenance
[Backport 2.32-maintenance] Correct `build-dir` error in manual, link relevant settings
2025-12-09 02:05:36 +00:00
John Ericson
36a1dc34fc Correct build-dir error in manual, link relevant settings
This fixes out-of-date information that is no longer true, and makes the
up-to-date information more accessible.

(cherry picked from commit c5fa5e503a)
2025-12-09 01:32:38 +00:00
internal-nix-ci[bot]
7060505b26 Merge pull request #14730 from NixOS/backport-14729-to-2.32-maintenance
[Backport 2.32-maintenance] Fix Non-virtual interface pattern for `RestrictedStore::addDependency`
2025-12-07 18:49:14 +00:00
John Ericson
d9fc17d299 Fix Non-virtual interface pattern for RestrictedStore::addDependency
I didn't do things quite right in 496e43ec72:

- Forgot to remove the now-redundant `isAllowed` check.

- Called the non-virtual, not the superclass's impl, in
  `addDependencyPrep`, causing bad recursion / UB.

Doing this fixes a crash I encountered with manual testing an Nix Ninja
--- hopefully we will get Nix Ninja or similar in a NixOS test longer
term to defend against this thing happening again.

(cherry picked from commit 4652345ac3)
2025-12-07 18:11:53 +00:00
internal-nix-ci[bot]
ba5bede9f5 Merge pull request #14693 from NixOS/backport-14690-to-2.32-maintenance
[Backport 2.32-maintenance] Support mdbook 0.5
2025-12-02 14:39:28 +00:00
Robert Hensing
de4df1e90b maint: Fix lowdown override compatibility with newer nixpkgs
Use `or ""` fallback for postInstall attribute which may not exist in
newer nixpkgs versions of lowdown.

(cherry picked from commit 0aef1ddb9e)
2025-12-02 14:06:25 +00:00
Robert Hensing
6ac33ab878 maint: Remove mdbook-linkcheck and support mdbook 0.5.x
Fixes #14628

- Remove mdbook-linkcheck dependency and configuration (was blocking
  upgrades to mdbook 0.5.0+, configured with warning-policy = "ignore"
  due to false positives, and redundant with lychee-based link checking)
- Update substitute.py and anchors.jq to handle 'items' (mdbook 0.5.x)
  in addition to 'sections' (mdbook 0.4.x), as per mdbook 0.5.0
  changelog: "Book::sections was renamed to Book::items"
  https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#05-migration-guide

(cherry picked from commit 2636f50dd4)
2025-12-02 14:06:25 +00:00
internal-nix-ci[bot]
0f4073f9d7 Merge pull request #14680 from NixOS/backport-14676-to-2.32-maintenance
[Backport 2.32-maintenance] libstore: Use makeTempPath in optimizePath_, assorted fs fixes
2025-12-01 03:42:56 +00:00
Sergei Zimmerman
cf0e563f38 libutil: Make AutoDelete non-copyable and non-movable
This is a good precaution, since we don't want to delete
directories twice accidentally.

(cherry picked from commit 40e3f5c0a4)
2025-12-01 02:48:07 +00:00
Sergei Zimmerman
fb79e6a7a1 libutil: Propagate error code in createSymlink
(cherry picked from commit bf7c53f2d3)
2025-12-01 02:48:07 +00:00
Sergei Zimmerman
3e50cadbe6 libstore: Actually correctly call remove in case rename fails
(cherry picked from commit 1cc337bb5f)
2025-12-01 02:48:07 +00:00
Sergei Zimmerman
6c4dc93d9b libstore: Use makeTempPath in optimizePath_
This was intended to be cherry-picked in 6aed9d877c,
but was left hanging. This is actually important for fixing [^]. emilazy let me know
of this bad cherry-pick and its significance.

[^]: https://github.com/NixOS/nix/issues/7273

Originally fixed by Lily Ballard <lily@ballards.net> in https://gerrit.lix.systems/c/lix/+/2100.

(cherry picked from commit d888846b68)
2025-12-01 02:48:07 +00:00
internal-nix-ci[bot]
bd0522c15b Merge pull request #14673 from NixOS/backport-14672-to-2.32-maintenance
[Backport 2.32-maintenance] libfetchers: Fix fetchGit with ref = "HEAD"
2025-11-30 02:13:00 +00:00
Sergei Zimmerman
1d1d553083 libfetchers: Fix fetchGit with ref = "HEAD"
This seems to have been broken in ee9fa0d360.
Adding the HEAD:HEAD refspec looks like the correct solution.

Suggested-by: hxtmdev on github
(cherry picked from commit 18f3598d57)
2025-11-30 01:42:07 +00:00
Taeer Bar-Yam
ca5f35fcf7 Merge pull request #14646 from NixOS/fix-14642-2.32
[Backport 2.32-maintenance] Fix dynamic attributes that are simple string expressions
2025-11-25 17:39:55 -05:00
Sergei Zimmerman
1e190d840a Revert "libexpr: introduce arena to hold ExprString strings"
This reverts commit eab467ecfb.

Simpler to revert the offending patch that lead to dynamic attributes
regression than to fix it.
2025-11-26 00:39:36 +03:00
Taeer Bar-Yam
d56115eeb4 tests: add tests for dynamic attribute in let and inherit
Without a follow-up revert these tests will fail.

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
Co-authored-by: piegames <git@piegames.de>

(cherry picked from commit 0c0a41a81a)
2025-11-26 00:29:27 +03:00
John Ericson
0167a50133 Merge pull request #14572 from NixOS/segfault-nonexistent-drv
treewide: Add Store::requireStoreObjectAccessor, simplify uses of get…
2025-11-15 08:38:24 -05:00
Sergei Zimmerman
379564981a treewide: Add Store::requireStoreObjectAccessor, simplify uses of getFSAccessor
This is a simple wrapper around getFSAccessor that throws an InvalidPath
error. This simplifies usage in callsites that only care about getting
a non-null accessor.

(cherry picked from commit 0c32fb3fa2)
2025-11-15 14:44:52 +03:00
Eelco Dolstra
450cceb5ad Bump version 2025-11-13 17:14:05 +01:00
internal-nix-ci[bot]
a5f9651163 Merge pull request #14558 from NixOS/backport-14551-to-2.32-maintenance
[Backport 2.32-maintenance] Remove static data from headers
2025-11-13 16:01:23 +00:00
David McFarland
4a8b515260 Remove static data from headers
We don't want to duplicate any of these across libraries, which is what
happens when the platform doesn't support unique symbols.

(cherry picked from commit 1b5af49fd0)
2025-11-13 15:26:49 +00:00
internal-nix-ci[bot]
d7fc293353 Merge pull request #14534 from NixOS/backport-14531-to-2.32-maintenance
[Backport 2.32-maintenance] Restore isAllowed check in ChrootLinuxDerivationBuilder
2025-11-10 20:47:31 +00:00
Sergei Zimmerman
46a43dede9 Restore isAllowed check in ChrootLinuxDerivationBuilder
This early return was lost in d4ef822add.

By doing some
https://en.wikipedia.org/wiki/Non-virtual_interface_pattern, we can
ensure that we don't make this mistake again --- implementations are no
longer responsible for implementing the caching/memoization mechanism.

(cherry picked from commit 496e43ec72)
2025-11-10 20:15:50 +00:00
internal-nix-ci[bot]
5b8c24fb31 Merge pull request #14524 from NixOS/backport-14515-to-2.32-maintenance
[Backport 2.32-maintenance] libexpr: Don't use nix::dirOf in prim_dirOf (fix 2.23 regression)
2025-11-09 18:14:03 +00:00
Sergei Zimmerman
be250f00b9 libexpr: Don't use nix::dirOf in prim_dirOf
This gets us back to pre-2.23 behavior of this primop.
Done by inlining the code of `nix::dirOf` from 2.2-maintenance.

(cherry picked from commit a33fccf55a)
2025-11-09 17:43:04 +00:00
Sergei Zimmerman
b591265a05 tests/functional: Add tests for builtins.dirOf
These will change in the next commit to fix the silent regression from 2.23
in the handling of multiple subsequent path separators.

(cherry picked from commit 86f090837b)
2025-11-09 17:43:04 +00:00
internal-nix-ci[bot]
70b7c059fd Merge pull request #14511 from NixOS/backport-14509-to-2.32-maintenance
[Backport 2.32-maintenance] build: Disable libstdc++ TBB backend to avoid unnecessary dependency
2025-11-07 22:04:04 +00:00
Jörg Thalheim
287b54b49c build: Disable libstdc++ TBB backend to avoid unnecessary dependency
boost::concurrent_flat_map (used in libutil and libstore) includes the
C++17 <execution> header. GCC's libstdc++ implements parallel algorithms
using Intel TBB as the backend, which creates a link-time dependency on
libtbb even though we don't actually use any parallel algorithms.

Disable the TBB backend for libstdc++ by setting
_GLIBCXX_USE_TBB_PAR_BACKEND=0. This makes parallel algorithms fall back
to serial execution, which is acceptable since we don't use them anyway.

This only affects libstdc++ (GCC's standard library); other standard
libraries like libc++ (LLVM) are unaffected.

(cherry picked from commit 2f3ec16793)
2025-11-07 21:33:37 +00:00
Eelco Dolstra
441aba4823 Bump version 2025-11-07 10:41:17 +01:00
Eelco Dolstra
aa657c1679 Revert "Merge pull request #14382 from NixOS/backport-14364-to-2.32-maintenance"
This reverts commit 5c9481de19,
reversing changes made to
291e8ab6bd. This is a behaviour change
that should be avoided on maintenance branches.
2025-11-06 22:10:42 +01:00
internal-nix-ci[bot]
a4fb83a239 Merge pull request #14498 from NixOS/backport-14491-to-2.32-maintenance
[Backport 2.32-maintenance] Don't crash on flakerefs containing newlines
2025-11-06 19:38:36 +00:00
Eelco Dolstra
47ba375285 Don't crash on flakerefs containing newlines
Fixes #14311.

(cherry picked from commit c1317017e9)
2025-11-06 19:18:16 +00:00
internal-nix-ci[bot]
5c9e22d75a Merge pull request #14485 from NixOS/backport-14482-to-2.32-maintenance
[Backport 2.32-maintenance] nix flake check: Remove incorrect assertion
2025-11-05 20:23:17 +00:00
Eelco Dolstra
e6d823e46d nix flake check: Remove incorrect assertion
The assumption that no unknown paths can be returned is incorrect. It
can happen if a derivation has outputs that are substitutable, but
that have references that cannot be substituted (i.e. an incomplete
closure in the binary cache). This can easily happen with
magic-nix-cache.

(cherry picked from commit a828cf777a)
2025-11-05 19:51:29 +00:00
internal-nix-ci[bot]
038cc7913b Merge pull request #14461 from NixOS/backport-14450-to-2.32-maintenance
[Backport 2.32-maintenance] flake: Update, nixos-25.05-small -> nixos-25.05
2025-11-03 17:43:37 +00:00
Robert Hensing
828bf74cd0 Apply updated nixfmt
(cherry picked from commit 81a2809a52)
2025-11-03 17:08:34 +00:00
Robert Hensing
ec122cbfda flake: Update, nixos-25.05-small -> nixos-25.05
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/d98ce345cdab58477ca61855540999c86577d19d?narHash=sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8%3D' (2025-08-26)
  → 'github:NixOS/nixpkgs/daf6dc47aa4b44791372d6139ab7b25269184d55?narHash=sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8%2BON/0Yy8%2Ba5vsDU%3D' (2025-10-27)

(cherry picked from commit 233bd250d1)
2025-11-03 17:08:34 +00:00
internal-nix-ci[bot]
e1ff27324b Merge pull request #14438 from NixOS/backport-14434-to-2.32-maintenance
[Backport 2.32-maintenance] libstore: Improve store-reference back-compat with IPv6 ZoneId literals
2025-11-01 00:18:55 +00:00
Sergei Zimmerman
7b41563055 libstore: Improve store-reference back-compat with IPv6 ZoneId literals
This restores the pre-2.31 handling of ZoneID identifiers in store references.
It's the only place we reasonably care about this back-compat.

(cherry picked from commit 8dbc2475f7)
2025-10-31 23:50:22 +00:00
internal-nix-ci[bot]
7f9b9c3638 Merge pull request #14436 from NixOS/backport-14431-to-2.32-maintenance
[Backport 2.32-maintenance] libfetchers: Restore plain git inputs recognition
2025-10-31 23:25:25 +00:00
Sergei Zimmerman
ed09f1b4d9 libfetchers: Restore plain git inputs recognition
Accidentally broken in dbc235cc62.
Adds a bit of tests for this, even though this protocol is mostly deprecated
everywhere.

(cherry picked from commit ade3d5d746)
2025-10-31 23:01:54 +00:00
internal-nix-ci[bot]
fc6811cb51 Merge pull request #14435 from NixOS/backport-14432-to-2.32-maintenance
[Backport 2.32-maintenance] meson: Also split version string at '+' for Darwin
2025-10-31 22:24:18 +00:00
Sergei Zimmerman
a24df3d4e5 meson: Also split version string at '+' for Darwin
(cherry picked from commit 1ca6e9ef54)
2025-10-31 21:47:27 +00:00
internal-nix-ci[bot]
e6003b5c4f Merge pull request #14430 from NixOS/backport-14137-to-2.32-maintenance
[Backport 2.32-maintenance] fix(libstore/build/derivation-goal): don't assert on partially valid outputs
2025-10-31 20:59:43 +00:00
Bernardo Meurer Costa
f566957dc4 fix(libstore/build/derivation-goal): don't assert on partially valid outputs
Fixes: #14130
(cherry picked from commit 9eecee3d4e)
2025-10-31 23:30:03 +03:00
internal-nix-ci[bot]
f434a3e3c6 Merge pull request #14413 from NixOS/backport-14410-to-2.32-maintenance
[Backport 2.32-maintenance] zsh/completion: put compdef on first line
2025-10-29 16:17:24 +00:00
bryango
939f81c2e6 zsh/completion: put compdef on first line
Some zsh setups (including mine) do not load the
completion if `#compdef` is not on the first line.

So we move the `# shellcheck` comment to the
second line to avoid this issue.

(cherry picked from commit 956fffdd6f)
2025-10-29 15:58:06 +00:00
internal-nix-ci[bot]
758dacacf4 Merge pull request #14409 from NixOS/backport-14289-to-2.32-maintenance
[Backport 2.32-maintenance] Fix issue #14287
2025-10-29 08:29:01 +00:00
John Ericson
9e4177bc67 Fix issue #14287
The test added in the previous commit now passes.

Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
(cherry picked from commit de192794c9)
2025-10-29 07:59:08 +00:00
John Ericson
328a3bbbd0 Regression test for issue #14287
This will currently fail, until the bug is fixed.

Co-Authored-By: Sergei Zimmerman <sergei@zimmerman.foo>
(cherry picked from commit 246dbe1c05)
2025-10-29 07:59:08 +00:00
internal-nix-ci[bot]
5c9481de19 Merge pull request #14382 from NixOS/backport-14364-to-2.32-maintenance
[Backport 2.32-maintenance] diff-closures: print sizes with dynamic unit
2025-10-27 20:52:05 +00:00
Marcel
ebadea0734 treewide: replace manual MiB calculations with renderSize
(cherry picked from commit 584a8e8a00)
2025-10-27 19:43:40 +00:00
Marcel
7d7ca3fe96 refactor(libutil): remove showBytes() in favor of renderSize()
The `showBytes()` function was redundant with `renderSize()` as the
latter automatically selects the appropriate unit (KiB, MiB, GiB, etc.)
based on the value, whereas `showBytes()` always formatted as MiB
regardless of size.

Co-authored-by: Bernardo Meurer Costa <beme@anthropic.com>
(cherry picked from commit f234633e27)
2025-10-27 19:43:40 +00:00
Marcel
3a92f83e75 diff-closures: print sizes with dynamic unit
(cherry picked from commit 9d4d10954a)
2025-10-27 19:43:40 +00:00
Eelco Dolstra
291e8ab6bd Merge pull request #14372 from NixOS/backport-14362-to-2.32-maintenance
[Backport 2.32-maintenance] libexpr: Speed up BindingsBuilder::finishSizeIfNecessary
2025-10-27 16:41:28 +01:00
Eelco Dolstra
19441dd317 Bump version 2025-10-27 16:36:00 +01:00
internal-nix-ci[bot]
71ec2cf62d Merge pull request #14371 from NixOS/backport-14340-to-2.32-maintenance
[Backport 2.32-maintenance] nix-2.32 needs boost-1.87+ for `try_emplace_and_cvisit`
2025-10-27 15:01:12 +00:00
Sergei Zimmerman
b36f8043d2 libexpr: Speed up BindingsBuilder::finishSizeIfNecessary
Instead of iterating over the newly built bindings we can
do a cheaper set_intersection to count duplicates or fall back
to a per-element binary search over the "base" bindings.

This speeds up `hello` evaluation by around 10ms (0.196s -> 0.187s) and
`nixos.closures.ec2.x86_64-linux` by 140ms (2.744s -> 2.609s).

This addresses a somewhat steep performance regression from 82315c3807
that reduced memory requirements of attribute set merges. With this patch
we get back around to 2.31 level of eval performance while keeping the memory
usage optimization.

Also document the optimization a bit more.

(cherry picked from commit ec2fd2dc23)
2025-10-27 14:40:17 +00:00
Jens Petersen
4d1f72a324 libexpr needs boost-1.87+ for try_emplace_and_cvisit
Since 2.32, nix now needs boost 1.87 or later to build,
due to using unordered::concurrent_flat_map try_emplace_and_cvisit

../src/libexpr/eval.cc: In member function ‘void nix::EvalState::evalFile(const nix::SourcePath&, nix::Value&, bool)’:
../src/libexpr/eval.cc:1096:20: error: ‘class boost::unordered::concurrent_flat_map<nix::SourcePath, nix::Value*, std::hash<nix::SourcePath>, std::equal_to<nix::SourcePath>, traceable_allocator<std::pair<const nix::SourcePath, nix::Value*> > >’ has no member named ‘try_emplace_and_cvisit’; did you mean ‘try_emplace_or_cvisit’?
 1096 |     fileEvalCache->try_emplace_and_cvisit(
      |                    ^~~~~~~~~~~~~~~~~~~~~~
      |                    try_emplace_or_cvisit

See 834580b539

(cherry picked from commit f594a8e11e)
2025-10-27 14:28:38 +00:00
internal-nix-ci[bot]
ac3532d0f2 Merge pull request #14354 from NixOS/backport-14343-to-2.32-maintenance
[Backport 2.32-maintenance] Revert "libmain: Catch logger exceptions in `handleExceptions`"
2025-10-25 00:00:15 +00:00
Sergei Zimmerman
84dbf182d4 Revert "libmain: Catch logger exceptions in handleExceptions"
This reverts commit 90d1ff4805.

The initial issue with EPIPE was solved in 9f680874c5.
Now this patch does move bad than good by eating up boost::io::format_error that are
bugs.

(cherry picked from commit 4f5af471fb)
2025-10-24 23:28:53 +00:00
internal-nix-ci[bot]
4a27d70132 Merge pull request #14280 from NixOS/backport-14276-to-2.32-maintenance
[Backport 2.32-maintenance] libstore/registerOutputs: Don't try to optimize a non-existent actual…
2025-10-16 22:17:53 +00:00
Sergei Zimmerman
dadb5b01b7 libstore/registerOutputs: Don't try to optimize a non-existent actualPath
Since 3c610df550 this resulted in `getting status of`
errors on paths inside the chroot if a path was already valid. Careful inspection
of the logic shows that if buildMode != bmCheck actualPath gets reassigned to
store.toRealPath(finalDestPath). The only branch that cares about actualPath is
the buildMode == bmCheck case, which doesn't lead to optimisePath anyway.

(cherry picked from commit 4cbcaad435)
2025-10-16 21:46:08 +00:00
internal-nix-ci[bot]
3c39583e55 Merge pull request #14267 from NixOS/backport-14263-to-2.32-maintenance
[Backport 2.32-maintenance] Restore `ServeProto::Command::ImportPaths`
2025-10-16 00:07:32 +00:00
Sergei Zimmerman
a038c92d38 Restore ServeProto::Command::ImportPaths
This partially reverts commit 5e46df973f,
partially reversing changes made to
8c789db05b.

We do this because Hydra, while using the newer version of the protocol,
still uses this command, even though Nix (as a client) doesn't use it.
On that basis, we don't want to remove it (or consider it only part of
the older versions of the protocol) until Hydra no longer uses the
Legacy SSH Protocol.

(cherry picked from commit 0deb492b3d)
2025-10-15 23:38:26 +00:00
internal-nix-ci[bot]
cf6ad228ae Merge pull request #14259 from NixOS/backport-14253-to-2.32-maintenance
[Backport 2.32-maintenance] libfetchers/git-utils: Be more correct about validating refnames
2025-10-15 20:33:35 +00:00
Sergei Zimmerman
44701007b4 libfetchers/git-utils: Be more correct about validating refnames
Turns out there's a much better API for this that doesn't have the
footguns of the previous method.

isLegalRefName is somewhat of a misnomer, since it's mainly used to
validate user inputs that can be either references, branch names,
psedorefs or tags.

(cherry picked from commit 5d1178b817)
2025-10-15 20:08:43 +00:00
internal-nix-ci[bot]
ff1f145992 Merge pull request #14256 from NixOS/backport-14205-to-2.32-maintenance
[Backport 2.32-maintenance] Improved backwards compatibility hack for git URLs using dir=...
2025-10-15 16:31:21 +00:00
Graham Dennis
3519ad2ca6 Improve comment
(cherry picked from commit 8d9e9bc400)
2025-10-15 15:58:18 +00:00
Graham Dennis
16af6a8ed1 Improved backwards compatibility hack for git URLs using dir=... attribute
(cherry picked from commit 43b01b6790)
2025-10-15 15:58:18 +00:00
Eelco Dolstra
549a2e8272 Bump version 2025-10-14 11:26:39 +02:00
internal-nix-ci[bot]
2531dcad75 Merge pull request #14238 from NixOS/backport-14237-to-2.32-maintenance
[Backport 2.32-maintenance] Remove validation of URLs passed to FileTransferRequest verbatim
2025-10-13 21:23:05 +00:00
Sergei Zimmerman
11f9c59140 Remove validation of URLs passed to FileTransferRequest verbatim
CURL is not very strict about validation of URLs passed to it. We
should reflect this in our handling of URLs that we get from the user
in <nix/fetchurl.nix> or builtins.fetchurl. ValidURL was an attempt to
rectify this, but it turned out to be too strict. The only good way to
resolve this is to pass (in some cases) the user-provided string verbatim
to CURL. Other usages in libfetchers still benefit from using structured
ParsedURL and validation though.

nix store prefetch-file --name foo 'https://cdn.skypack.dev/big.js@^5.2.2'
error: 'https://cdn.skypack.dev/big.js@^5.2.2' is not a valid URL: leftover

(cherry picked from commit 47f427a172)
2025-10-13 20:48:15 +00:00
internal-nix-ci[bot]
a25a219e79 Merge pull request #14213 from NixOS/backport-14194-to-2.32-maintenance
[Backport 2.32-maintenance] libutil: Print stack trace on assertion failure
2025-10-11 00:40:50 +00:00
Sergei Zimmerman
f07486b205 libutil: Print stack trace on assertion failure
This change overrides __assert_fail on glibc/musl
to instead call std::terminate that we have a custom
handler for. This ensures that we have more context
to diagnose issues encountered by users in the wild.

(cherry picked from commit 46382ade74)
2025-10-11 00:08:36 +00:00
internal-nix-ci[bot]
9ec98f7844 Merge pull request #14212 from NixOS/backport-14210-to-2.32-maintenance
[Backport 2.32-maintenance] libstore: Fix double-quoting of paths in logs
2025-10-10 23:26:18 +00:00
Sergei Zimmerman
634e1d3b65 libstore: Fix double-quoting of paths in logs
std::filesystem::path is already quoted by boost::format with double quotes (").
(cherry picked from commit f30cb8667b)
2025-10-10 22:54:22 +00:00
internal-nix-ci[bot]
70655061e3 Merge pull request #14202 from NixOS/backport-14199-to-2.32-maintenance
[Backport 2.32-maintenance] packaging: only override `toml11` when necessary
2025-10-09 18:04:05 +00:00
Seth Flynn
da328e6004 packaging: only override toml11 when necessary
v4.4.0 hit Nixpkgs in https://github.com/NixOS/nixpkgs/pull/442682.
Ideally we'd just use that, but this keeps the fallback behavior until
it's more widespread

(cherry picked from commit 0f016f9bf5)
2025-10-09 17:56:10 +00:00
internal-nix-ci[bot]
6b16af8c0e Merge pull request #14197 from NixOS/backport-14191-to-2.32-maintenance
[Backport 2.32-maintenance] libutil: Fix renderAuthorityAndPath unreachable for path:/ URLs
2025-10-09 00:00:28 +00:00
internal-nix-ci[bot]
010b78e0cf Merge pull request #14196 from NixOS/backport-14189-to-2.32-maintenance
[Backport 2.32-maintenance] exportReferencesGraph: Handle heterogeneous arrays
2025-10-08 23:43:51 +00:00
Sergei Zimmerman
98b7654390 libutil: Fix renderAuthorityAndPath unreachable for path:/ URLs
This was mistakenly triggered by path:/ URL, since the `//` would
correspond to 3 empty segments.

(cherry picked from commit 1d8dd77e1d)
2025-10-08 23:24:01 +00:00
Eelco Dolstra
c5799aa62c exportReferencesGraph: Handle heterogeneous arrays
This barfed with

   error: [json.exception.type_error.302] type must be string, but is array

on `nix build github:malt3/bazel-env#bazel-env` because it has a `exportReferencesGraph` with a value like `["string",...["string"]]`.

(cherry picked from commit 94f410b628)
2025-10-08 23:13:09 +00:00
Eelco Dolstra
72e3dd396c Bump version 2025-10-07 17:14:49 +02:00
Eelco Dolstra
d069633b3d Mark official release 2025-10-07 13:30:16 +02:00
Eelco Dolstra
6c21c810b9 Merge pull request #14164 from NixOS/release-notes
Release notes for Nix 2.32
2025-10-07 12:48:53 +02:00
John Ericson
eea6d75783 Merge pull request #14168 from xokdvium/nar-require-contents
libutil: Throw if `str("contents")` not found
2025-10-06 19:39:26 -04:00
Samuel Connelly
242f362567 libutil: Throw if str("contents") not found
This was broken in 7aa3e7e3a5 (since 2.25).
2025-10-07 01:04:49 +03:00
Sergei Zimmerman
0068ee6ca7 Release note for attrset optimization 2025-10-06 22:16:21 +03:00
Eelco Dolstra
1e709554d5 Merge pull request #14050 from NixOS/fix-fetch-to-store-caching
Fix fetchToStore caching
2025-10-06 19:39:41 +02:00
Eelco Dolstra
8f71ef7ede Update doc/manual/source/release-notes/rl-2.32.md
Co-authored-by: Taeer Bar-Yam <Radvendii@users.noreply.github.com>
2025-10-06 19:27:30 +02:00
Eelco Dolstra
8142989e67 Merge pull request #14166 from lovesegfault/nix-rl-notes
docs(release-notes): note fix for fetchTarball/fetchurl substitution
2025-10-06 19:11:18 +02:00
Bernardo Meurer Costa
776038f842 docs(release-notes): note fix for fetchTarball/fetchurl substitution 2025-10-06 17:09:34 +00:00
Eelco Dolstra
f4e44040d4 Release note for external derivation builders 2025-10-06 16:26:29 +02:00
Eelco Dolstra
0376112a51 Organize release notes 2025-10-06 16:11:24 +02:00
Eelco Dolstra
c1761b867b Contributors 2025-10-06 16:11:15 +02:00
Eelco Dolstra
9f6ed70429 release notes: 2.32.0 2025-10-06 16:04:58 +02:00
Eelco Dolstra
35b3557fe4 Merge pull request #14162 from NixOS/fix-windows-build
Don't build getPtsName() on Windows
2025-10-06 14:55:39 +02:00
Eelco Dolstra
8aa0acb9e8 Don't build getPtsName() on Windows
It's not needed.

https://hydra.nixos.org/build/309215536
2025-10-06 13:26:36 +02:00
Eelco Dolstra
5e65584edf Merge pull request #14145 from NixOS/external-derivation-builder
External derivation builders
2025-10-06 12:13:01 +02:00
Eelco Dolstra
e7e2ac97f8 Merge remote-tracking branch 'origin/master' into external-derivation-builder 2025-10-06 11:40:56 +02:00
Eelco Dolstra
e9c5d721d8 ExternalDerivationBuilder: Emit a version field 2025-10-06 11:36:26 +02:00
Eelco Dolstra
68bd2e40f4 ExternalDerivationBuilder: Pass the (scratch) outputs 2025-10-06 11:33:29 +02:00
Eelco Dolstra
6c0d67769d ExternalDerivationBuilder: Pass inputPaths 2025-10-06 11:29:15 +02:00
Eelco Dolstra
e5ae81c21a Merge pull request #14158 from fzakaria/fzakaria/small-clang-tidy-fix
clang-tidy fix for src/libstore/build/derivation-check.cc
2025-10-06 11:11:48 +02:00
Sergei Zimmerman
d5fa131cfb Merge pull request #14161 from Radvendii/exprophasattr-alloc
libexpr: fixup ExprOpHasAttr() to take allocator reference
2025-10-05 22:49:17 +00:00
Taeer Bar-Yam
14b119c948 libexpr: fixup ExprOpHasAttr() to take allocator reference 2025-10-05 18:28:47 -04:00
Sergei Zimmerman
29f3da1305 Merge branch 'master' into fzakaria/small-clang-tidy-fix 2025-10-05 21:27:39 +00:00
John Ericson
34bca9212a Merge pull request #14156 from NixOS/fix-ub
treewide: Squash some user-after-free bugs
2025-10-05 16:49:22 -04:00
John Ericson
cd9c208baf Merge pull request #14159 from NixOS/revert-resolution-goal
Revert #14097, #14022
2025-10-05 16:28:33 -04:00
Sergei Zimmerman
ce749454dc Revert "Merge pull request #14022 from obsidiansystems/derivation-resolution-goal"
This reverts commit d02dca099f, reversing
changes made to 9bd09155ac.
2025-10-05 21:54:59 +03:00
Sergei Zimmerman
7e39ab4dc7 Revert "Merge pull request #14097 from obsidiansystems/light-realisation-improvements"
This reverts commit dc8c1461da, reversing
changes made to 28adcfda32.
2025-10-05 21:54:32 +03:00
Farid Zakaria
06a82da6f5 clang-tidy fix for src/libstore/build/derivation-check.cc 2025-10-05 11:18:30 -07:00
Sergei Zimmerman
be1ade7373 libexpr: Use use-after-move in SampleStack::saveProfile() 2025-10-05 16:57:13 +03:00
Sergei Zimmerman
452ec09fe0 libstore: Fix use-after-move in DerivationGoal::repairClosure 2025-10-05 16:55:41 +03:00
Jörg Thalheim
7ba3ef21a6 Merge pull request #14154 from NixOS/fix-segfault-toView
treewide: Remove toView() because it leads to segfaults when compiled…
2025-10-05 13:38:40 +02:00
Sergei Zimmerman
dce1a893d0 treewide: Remove toView() because it leads to segfaults when compiled with newer nixpkgs
Firstly, this is now available on darwin where the default in llvm 19.
Secondly, this leads to very weird segfaults when building with newer nixpkgs for some reason.
(It's UB after all).

This appears when building with the following:

mesonComponentOverrides = finalAttrs: prevAttrs: {
mesonBuildType = "debugoptimized";
dontStrip = true;
doCheck = false;
separateDebugInfo = false;
preConfigure = (prevAttrs.preConfigure or "") + ''
  case "$mesonBuildType" in
  release|minsize|debugoptimized) appendToVar mesonFlags "-Db_lto=true"  ;;
  *)                              appendToVar mesonFlags "-Db_lto=false" ;;
  esac
'';
};

And with the following nixpkgs input:

nix build ".#nix-cli" -L --override-input nixpkgs "https://releases.nixos.org/nixos/unstable/nixos-25.11pre870157.7df7ff7d8e00/nixexprs.tar.xz"

Stacktrace:

 #0  0x00000000006afdc0 in ?? ()
 #1  0x00007ffff71cebb6 in _Unwind_ForcedUnwind_Phase2 () from /nix/store/41ym1jm1b7j3rhglk82gwg9jml26z1km-gcc-14.3.0-lib/lib/libgcc_s.so.1
 #2  0x00007ffff71cf5b5 in _Unwind_Resume () from /nix/store/41ym1jm1b7j3rhglk82gwg9jml26z1km-gcc-14.3.0-lib/lib/libgcc_s.so.1
 #3  0x00007ffff7eac7d8 in std::basic_ios<char, std::char_traits<char> >::~basic_ios (this=<optimized out>, this=<optimized out>)
     at /nix/store/82kmz7r96navanrc2fgckh2bamiqrgsw-gcc-14.3.0/include/c++/14.3.0/bits/basic_ios.h:286
 #4  std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::basic_ostringstream (this=<optimized out>, this=<optimized out>)
     at /nix/store/82kmz7r96navanrc2fgckh2bamiqrgsw-gcc-14.3.0/include/c++/14.3.0/sstream:806
 #5  nix::SimpleLogger::logEI (this=<optimized out>, ei=...) at ../logging.cc:121
 #6  0x00007ffff7515794 in nix::Logger::logEI (this=0x675450, lvl=nix::lvlError, ei=...) at /nix/store/bkshji3nnxmrmgwa4n2kaxadajkwvn65-nix-util-2.32.0pre-dev/include/nix/util/logging.hh:144
 #7  nix::handleExceptions (programName=..., fun=...) at ../shared.cc:336
 #8  0x000000000047b76b in main (argc=<optimized out>, argv=<optimized out>) at /nix/store/82kmz7r96navanrc2fgckh2bamiqrgsw-gcc-14.3.0/include/c++/14.3.0/bits/new_allocator.h:88
2025-10-05 02:30:21 +03:00
Sergei Zimmerman
35d7719f46 Merge pull request #14149 from Radvendii/exprophasattr-alloc
libexpr: allocate ExprOpHasAttr's AttrPath in Exprs::alloc
2025-10-03 23:50:46 +03:00
Taeer Bar-Yam
39109c05be libexpr: allocate ExprOpHasAttr's AttrPath in Exprs::alloc 2025-10-03 23:26:41 +03:00
Sergei Zimmerman
75826824d0 Merge pull request #14124 from Radvendii/exprselect-alloc
libexpr: allocate ExprSelect's AttrPath in Expr::alloc
2025-10-03 23:25:02 +03:00
Taeer Bar-Yam
76a92985d7 libexpr: allocate ExprSelect's AttrName vector in Expr::alloc 2025-10-03 22:51:23 +03:00
Sergei Zimmerman
862c816498 Merge pull request #14150 from cole-h/fixup-fakessh-check
libstore: fixup fakeSSH check
2025-10-03 22:46:40 +03:00
Cole Helbling
7ec1427fc3 libstore: fixup fakeSSH check
This broke invocations like:

    NIX_SSHOPTS='-p2222 -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no' nix copy /nix/store/......-foo --to ssh-ng://root@localhost

In Nix 2.30.2, fakeSSH was enabled when the "thing I want to connect to"
was plain old "localhost". Previously, this check was written as:

         , fakeSSH(host == "localhost")

Given the above invocation, `host` would have been `root@localhost`, and
thus `fakeSSH` would be `false` because `root@localhost` != `localhost`.

However, since 49ba06175e, `authority.host`
returned _just_ the host (`localhost`, no user) and erroneously enabled
`fakeSSH` in this case, causing `NIX_SSHOPTS` to be ignored (since,
when `fakeSSH` is `true`, `SSHMaster::startCommand` doesn't call
`addCommonSSHOpts`).

`authority.to_string()` accurately returns the expected `root@localhost`
format (given the above invocation), fixing this.
2025-10-03 12:17:17 -07:00
Eelco Dolstra
73e4c40e64 Add test for external-builders 2025-10-03 16:32:32 +02:00
Eelco Dolstra
d5d7ca01b3 Merge pull request #14138 from lovesegfault/nix-fix-4313
fix(libfetchers): substitute fetchTarball and fetchurl
2025-10-03 15:13:06 +02:00
Eelco Dolstra
584ef0ffd3 Add external builders
These are helper programs that execute derivations for specified
system types (e.g. using QEMU to emulate another system type).

To use, set `external-builders`:

  external-builders = [{"systems": ["aarch64-linux"], "program": "/path/to/external-builder.py"}]

The external builder gets one command line argument, the path to a JSON file containing all necessary information about the derivation:

  {
    "args": [...],
    "builder": "/nix/store/kwcyvgdg98n98hqapaz8sw92pc2s78x6-bash-5.2p37/bin/bash",
    "env": {
      "HOME": "/homeless-shelter",
      ...
    },
    "realStoreDir": "/tmp/nix/nix/store",
    "storeDir": "/nix/store",
    "tmpDir": "/tmp/nix-shell.dzQ2hE/nix-build-patchelf-0.14.3.drv-46/build",
    "tmpDirInSandbox": "/build"
  }

Co-authored-by: Cole Helbling <cole.helbling@determinate.systems>
2025-10-03 14:34:13 +02:00
Jörg Thalheim
76ac3758d7 Merge pull request #14144 from lovesegfault/curl-based-s3-pieces
build(libstore): add NIX_WITH_CURL_S3 build option
2025-10-03 09:25:22 +02:00
Bernardo Meurer Costa
27f6417128 build(libstore): add NIX_WITH_CURL_S3 build option
Introduce a new build option 'curl-s3-store' for the curl-based S3
implementation, separate from the existing AWS SDK-based 's3-store'.
The two options are mutually exclusive to avoid conflicts.

Users can enable the new implementation with:
  -Dcurl-s3-store=enabled -Ds3-store=disabled
2025-10-03 03:34:57 +00:00
Sergei Zimmerman
8a8a0c2a4b Merge pull request #14135 from lovesegfault/curl-based-s3-pieces
feat(libstore): add AWS CRT-based credential infrastructure
2025-10-02 22:58:36 +00:00
Sergei Zimmerman
eb67b0df5a Merge pull request #14142 from NixOS/move-settings-http-store
libstore: Move {narinfo,ls,log}-compression settings from BinaryCache…
2025-10-02 21:04:22 +00:00
Sergei Zimmerman
ea14933915 Merge pull request #14139 from osbm/master
docs: Update documentation regarding the flake outputs
2025-10-02 20:17:42 +00:00
Sergei Zimmerman
d2017e0e1a libstore: Move {narinfo,ls,log}-compression settings from BinaryCacheStoreConfig to HttpBinaryCacheStoreConfig
These settings are only implemented for the http store and should not be
there for the file:// stores.
2025-10-02 23:11:16 +03:00
Bernardo Meurer Costa
1e92b61750 fix(libfetchers): substitute fetchTarball and fetchurl
Fixes #4313 by enabling builtins.fetchurl, builtins.fetchTarball to use
binary cache substituters before attempting to download from the
original URL.
2025-10-02 19:33:02 +00:00
osbm
7f3f0f2a0b docs: Update documentation regarding the flake outputs 2025-10-02 10:44:30 +03:00
Bernardo Meurer Costa
a4e792cba7 feat(libstore): add AWS CRT-based credential infrastructure
Add lightweight AWS credential resolution using AWS CRT (Common Runtime)
instead of the full AWS SDK. This provides credential management for the
upcoming curl-based S3 implementation.
2025-10-01 21:53:55 +00:00
John Ericson
dc8c1461da Merge pull request #14097 from obsidiansystems/light-realisation-improvements
Realisation improvements, dummy store support, unit testing
2025-10-01 17:28:26 -04:00
John Ericson
5592bb717b Implement realisation operations on dummy store 2025-10-01 17:05:06 -04:00
John Ericson
e06968ec25 Split out UnkeyedRealisation from Realisation
Realisations are conceptually key-value pairs, mapping `DrvOutputs` (the
key) to information about that derivation output.

This separate the value type, which will be useful in maps, etc., where
we don't want to denormalize by including the key twice.

This matches similar changes for existing types:

| keyed              | unkeyed                |
|--------------------|------------------------|
| `ValidPathInfo`    | `UnkeyedValidPathInfo` |
| `KeyedBuildResult` | `BuildResult`          |
| `Realisation`      | `UnkeyedRealisation`   |
2025-10-01 17:01:26 -04:00
Sergei Zimmerman
28adcfda32 Merge pull request #14119 from NixOS/hide-derivation-internal
libexpr: Move derivation-internal.nix from corepkgsFS to internalFS
2025-10-01 20:58:17 +00:00
Jörg Thalheim
d02dca099f Merge pull request #14022 from obsidiansystems/derivation-resolution-goal
Introduce `DerivationResolutionGoal`, fix substituting a single CA drv output
2025-10-01 22:53:58 +02:00
Jörg Thalheim
9bd09155ac Merge pull request #14136 from Mic92/jitsi
link to jitsi meeting in the PR docs
2025-10-01 22:39:13 +02:00
Sergei Zimmerman
2774e67c60 Merge pull request #14128 from obsidiansystems/expose-dummy-store-for-tests-somewhat
Expose some core implementation details and write a basic unit test for the dummy store
2025-10-01 20:27:37 +00:00
Jörg Thalheim
85d6c8af4d link to jitsi meeting in the PR docs 2025-10-01 22:23:31 +02:00
Sergei Zimmerman
2a0fddc7d5 libexpr: Move derivation-internal.nix from corepkgsFS to internalFS
Best I can tell this was never supposed to be exposed to the user
and has been this way since 2.19.

2.18 did not expose this file to the user:

nix run nix/2.18-maintenance -- eval --expr "import <nix/derivation-internal.nix>"

error: getting status of '/__corepkgs__/derivation-internal.nix': No such file or directory
2025-10-01 23:13:11 +03:00
Sergei Zimmerman
d0c017def5 Merge pull request #14134 from JamiKettunen/fix-libc++-build
libstore: Include missing header to fix compile with libc++ 20
2025-10-01 20:07:03 +00:00
Sergei Zimmerman
30a6cbe90b Merge pull request #14131 from lovesegfault/curl-based-s3-pieces
refactor(libstore): extract S3 URL parsing into separate files
2025-10-01 19:39:46 +00:00
Jami Kettunen
140b08ae3e libstore: Include missing header to fix compile with libc++ 20
https://en.cppreference.com/w/cpp/thread.html

src/libstore/gc.cc:121:39: error: no member named 'sleep_for' in namespace 'std::this_thread'
  121 |                     std::this_thread::sleep_for(std::chrono::milliseconds(100));
      |                     ~~~~~~~~~~~~~~~~~~^
2025-10-01 22:19:08 +03:00
Bernardo Meurer Costa
b72898b2aa refactor(libstore): extract S3 URL parsing into separate files
Move ParsedS3URL from s3.cc/.hh into dedicated s3-url.cc/.hh files.
This separates URL parsing utilities (which are protocol-agnostic) from
the AWS SDK-specific S3Helper implementation, making the code cleaner
and enabling reuse by future curl-based S3 implementation.
2025-10-01 16:11:38 +00:00
John Ericson
251479bdda Merge pull request #14127 from obsidiansystems/registerDrvOutput-no-blanket-unsupported
`Store::registerDrvOutput` make pure virtual
2025-10-01 08:51:18 -04:00
John Ericson
772a38069e Merge pull request #14129 from fzakaria/fzakaria/shellcheck-multiple-6
Remove all shellcheck exclusions
2025-09-30 23:54:53 -04:00
Farid Zakaria
015b639cea shellcheck fix: tests/functional/why-depends.sh 2025-09-30 20:27:51 -07:00
Farid Zakaria
c8ef6dfa5a shellcheck fix: tests/functional/user-envs.sh 2025-09-30 20:27:50 -07:00
Farid Zakaria
13eac5295d shellcheck fix: tests/functional/user-envs.builder.sh 2025-09-30 20:23:02 -07:00
Farid Zakaria
049c4c7546 shellcheck fix: tests/functional/user-envs-test-case.sh 2025-09-30 20:22:11 -07:00
Farid Zakaria
359e73a6db shellcheck fix: tests/functional/user-envs-migration.sh 2025-09-30 20:20:13 -07:00
Farid Zakaria
799cd62ec8 shellcheck fix: tests/functional/toString-path.sh 2025-09-30 20:19:47 -07:00
Farid Zakaria
b349783830 shellcheck fix: tests/functional/supplementary-groups.sh 2025-09-30 20:19:27 -07:00
Farid Zakaria
8c9bfb6e12 shellcheck fix: tests/functional/simple.builder.sh 2025-09-30 20:18:48 -07:00
Farid Zakaria
7266a51412 shellcheck fix: tests/functional/selfref-gc.sh 2025-09-30 20:17:55 -07:00
Farid Zakaria
b8f1a8a0c1 shellcheck fix: tests/functional/selfref-gc.sh 2025-09-30 20:17:55 -07:00
Farid Zakaria
1a5ccbeafc shellcheck fix: tests/functional/secure-drv-outputs.sh 2025-09-30 20:17:55 -07:00
Farid Zakaria
64d828b8c4 shellcheck fix: tests/functional/search.sh 2025-09-30 20:17:55 -07:00
Farid Zakaria
b42ed6a74d shellcheck fix: tests/functional/restricted.sh 2025-09-30 20:17:55 -07:00
Farid Zakaria
d35d86da89 shellcheck fix: tests/functional/repair.sh 2025-09-30 20:17:54 -07:00
Farid Zakaria
06f21e101f shellcheck fix: tests/functional/remote-store.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
7ed4011990 shellcheck fix: tests/functional/referrers.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
5d1333bf4b shellcheck fix: tests/functional/recursive.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
8a36cf4422 shellcheck fix: tests/functional/readfile-context.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
c8a7719614 shellcheck fix: tests/functional/read-only-store.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
1492c1bc5d shellcheck fix: tests/functional/push-to-store.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
a11195d6ce shellcheck fix: tests/functional/push-to-store-old.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
b951e6e1ed shellcheck fix: tests/functional/pure-eval.sh 2025-09-30 20:15:34 -07:00
Farid Zakaria
bcd8311ec6 shellcheck fix: tests/functional/post-hook.sh 2025-09-30 20:15:33 -07:00
Farid Zakaria
1aaa3dafee shellcheck fix: tests/functional/placeholders.sh 2025-09-30 19:54:29 -07:00
Farid Zakaria
c82aa04a3d shellcheck fix: tests/functional/path-info.sh 2025-09-30 19:53:54 -07:00
Farid Zakaria
112c9d8f54 shellcheck fix: tests/functional/path-from-hash-part.sh 2025-09-30 19:53:33 -07:00
Farid Zakaria
32cbf5f55a shellcheck fix: tests/functional/pass-as-file.sh 2025-09-30 19:52:44 -07:00
John Ericson
9ac306c4df Expose some core implementation details and write a basic unit test for the dummy store
This test currently doesn't use the new-exposed functionality, but with
future changes the tests will be expanded and they will be used.
2025-09-30 14:52:32 -04:00
John Ericson
88bd0c25f2 Store::registerDrvOutput make pure virtual
It should be the responsibility of implementations that don't implement
it to say so.

See also PR #9799, and issue #5729
2025-09-30 14:13:04 -04:00
John Ericson
c97b050a6c Fix ca/eval-store.sh test
The refactor in the last commit fixed the bug it was supposed to fix,
but introduced a new bug in that sometimes we tried to write a resolved
derivation to a store before all its `inputSrcs` were in that store.

The solution is to defer writing the derivation until inside
`DerivationBuildingGoal`, just before we do an actual build. At this
point, we are sure that all inputs in are the store.

This does have the side effect of meaning we don't write down the
resolved derivation in the substituting case, only the building case,
but I think that is actually fine. The store that actually does the
building should make a record of what it built by storing the resolved
derivation. Other stores that just substitute from that store don't
necessary want that derivation however. They can trust the substituter
to keep the record around, or baring that, they can attempt to re
resolve everything, if they need to be audited.
2025-09-30 11:29:21 -04:00
John Ericson
39f6fd9b46 Fix #13247
Resolve the derivation before creating a building goal, in a context
where we know what output(s) we want. That way we have a chance just to
download the outputs we want.

Fix #13247
2025-09-30 11:29:19 -04:00
John Ericson
8f4a739d0f Split out DerivationResolutionGoal
This prepares the way for fixing a few issues.
2025-09-30 11:25:52 -04:00
John Ericson
d76dc2406f Merge pull request #14060 from obsidiansystems/build-result-variant
Use `std::variant` to enforce `BuildResult` invariants
2025-09-30 11:02:13 -04:00
Jörg Thalheim
bc66e131f8 Merge pull request #14120 from lovesegfault/http-binary-cache-compression
feat(libstore/http-binary-cache-store): narinfo/ls/log compression
2025-09-30 12:50:10 +02:00
Jörg Thalheim
6e6f88ac45 add changelog for http binary cache compression 2025-09-30 11:05:20 +02:00
Jörg Thalheim
3fcd33079c add http binary cache test for compression options 2025-09-30 10:35:46 +02:00
Jörg Thalheim
a5facbd2d1 Merge pull request #14121 from obsidiansystems/file-transfer-quit
Some Curl file transfer cleanups
2025-09-30 09:12:08 +02:00
Jörg Thalheim
a5b35ec129 Merge pull request #14106 from Radvendii/exprpath-alloc
libexpr: allocate ExprPath strings in the allocator
2025-09-30 09:04:24 +02:00
John Ericson
e52e801421 Merge pull request #14123 from NixOS/path-tests-pure-eval
libexpr-tests: Add unit tests for broken readDir /. for pure eval
2025-09-30 00:33:51 -04:00
Sergei Zimmerman
a8670e8a7d libexpr-tests: Add unit tests for broken readDir /. for pure eval
A very unfortunate interaction of current filtering with pure eval is
that the following actually leads to `lib.a = {}`. This just adds a unit
test for this broken behavior. This is really good to be done as a unit test
via the in-memory store.

{
  outputs =
    { ... }:
    {
      lib.a = builtins.readDir /.;
    };
}
2025-09-30 03:16:35 +03:00
John Ericson
86fb5b24a9 curlFileTransfer::workerThreadEntry Only call quit if we need to. 2025-09-29 18:10:34 -04:00
John Ericson
1f65b08d94 curlFileTransfer::State:quit emptys the queue
Whoever first calls `quit` now empties the queue, instead of waiting for
the worker thread to do it.

(Note that in the unwinding case, the worker thread is still the first
to call `quit`, though.)
2025-09-29 18:10:34 -04:00
John Ericson
d5402b8527 Encapsulate curlFileTransfer::State:quit
It is allowed to read it, and to set it to `false`, but not to set it
to `true`.
2025-09-29 18:10:34 -04:00
Bernardo Meurer Costa
689fa81dc9 feat(libstore/http-binary-cache-store): narinfo/ls/log compression 2025-09-29 21:53:40 +00:00
Sergei Zimmerman
823c0d1140 Merge pull request #14118 from xokdvium/fix-make-empty-source-accessor
libutil: Create empty directory at the root for makeEmptySourceAccessor
2025-09-29 21:19:02 +00:00
Taeer Bar-Yam
f70b0b599c libexpr: allocate ExprPath strings in the allocator 2025-09-29 17:02:05 -04:00
Sergei Zimmerman
1830f5f967 libutil: Create empty directory at the root for makeEmptySourceAccessor
This is my SNAFU. Accidentally broken in 02c9ac445f.

There's very dubious behavior for 'builtins.readDir /.':

{
  outputs =
    { ... }:
    {
      lib.a = builtins.readDir /.;
    };
}

nix eval /tmp/test-flake#lib.a

Starting from 2.27 this now returns an empty set. This really isn't supposed
to happen, but this change in the semantics of makeEmptySourceAccessor accidentally
changed the behavior of this.
2025-09-29 23:16:28 +03:00
Jörg Thalheim
13a236ba29 Merge pull request #14114 from fzakaria/fzakaria/shellcheck-multiple-4
shellcheck fixes continued
2025-09-29 21:32:19 +02:00
Farid Zakaria
ef17baf50d shellcheck fix: tests/functional/parallel.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
4dc5dbaba2 shellcheck fix: tests/functional/parallel.builder.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
c09cf33a3a shellcheck fix: tests/functional/output-normalization.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
32818483a5 shellcheck fix: tests/functional/optimise-store.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
375529c7e5 shellcheck fix: tests/functional/nix_path.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
fe4e476d13 shellcheck fix: tests/functional/nix-shell.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
78833ca8d0 shellcheck fix: tests/functional/nix-profile.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
cf206ef61e shellcheck fix: tests/functional/nix-daemon-untrusting.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
8c2664ed15 shellcheck fix: tests/functional/nix-copy-ssh.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
ca7414cd18 shellcheck fix: tests/functional/nix-copy-ssh-ng.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
c9fd721be9 shellcheck fix: tests/functional/nix-copy-ssh-common.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
83e203fe45 shellcheck fix: tests/functional/nix-collect-garbage-d.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
2b1a0963f9 shellcheck fix: tests/functional/nix-channel.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
2bfc9019fa shellcheck fix: tests/functional/nix-build.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
794723142b shellcheck fix: tests/functional/nested-sandboxing/command.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
1a71c1ef9f shellcheck fix: tests/functional/nested-sandboxing.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
e26b0c66b0 shellcheck fix: tests/functional/multiple-outputs.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
f2eef5b0a4 shellcheck fix: tests/functional/misc.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
5a13f9fc91 shellcheck fix: tests/functional/logging.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
c4da98c8f4 shellcheck fix: tests/functional/linux-sandbox.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
5341d82428 shellcheck fix: tests/functional/legacy-ssh-store.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
f702101224 shellcheck fix: tests/functional/install-darwin.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
78d9a8d92b shellcheck fix: tests/functional/impure-eval.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
1cd96f22c0 shellcheck fix: tests/functional/impure-derivations.sh 2025-09-29 10:52:17 -07:00
Farid Zakaria
f3a2876c3a shellcheck fix: tests/functional/hash-convert.sh 2025-09-29 10:52:16 -07:00
Robert Hensing
8a968c599d Merge pull request #14116 from fzakaria/fzakaria/shellcheck-multiple-5
shellcheck fixes CA functional tests
2025-09-29 19:48:05 +02:00
Farid Zakaria
4232cb045a Remaining functional/ca tests for shellcheck 2025-09-29 10:25:49 -07:00
Farid Zakaria
5846d9d4dc shellcheck fix: tests/functional/ca/build-dry.sh 2025-09-29 10:12:04 -07:00
Farid Zakaria
745d1f9519 shellcheck fix: tests/functional/ca/build-delete.sh 2025-09-29 10:11:29 -07:00
Jörg Thalheim
fca6d8f1cc Merge pull request #14112 from EphraimSiegfried/make-content-addressed-doc-fix
docs: fix build command in make-content-addressed.md
2025-09-29 18:45:14 +02:00
Farid Zakaria
52b9fb38e0 shellcheck fix: tests/functional/gc-non-blocking.sh 2025-09-29 09:23:41 -07:00
Farid Zakaria
2e5952fb6a shellcheck fix: tests/functional/gc-concurrent2.builder.sh 2025-09-29 09:22:45 -07:00
Farid Zakaria
75df03204b shellcheck fix: tests/functional/gc-concurrent.sh 2025-09-29 09:21:47 -07:00
Farid Zakaria
613bd67574 shellcheck fix: tests/functional/gc-concurrent.builder.sh 2025-09-29 09:20:02 -07:00
Farid Zakaria
4192ca9131 shellcheck fix: tests/functional/gc-auto.sh 2025-09-29 09:18:50 -07:00
Farid Zakaria
08a82f4682 shellcheck fix: tests/functional/formatter.simple.sh 2025-09-29 09:17:24 -07:00
Farid Zakaria
f596c9b8c3 shellcheck fix: tests/functional/flakes/show.sh 2025-09-29 09:16:29 -07:00
Farid Zakaria
cb22518754 shellcheck fix: tests/functional/flakes/run.sh 2025-09-29 09:15:11 -07:00
Farid Zakaria
020f67a653 shellcheck fix: tests/functional/flakes/prefetch.sh 2025-09-29 09:14:41 -07:00
Ephraim Siegfried
121dda0f1f docs: fix build command in make-content-addressed.md 2025-09-29 14:07:26 +02:00
Jörg Thalheim
b6f4788a8f Merge pull request #14110 from Mic92/ptsname
Fix thread-safety issue with ptsname() usage
2025-09-29 13:49:58 +02:00
Jörg Thalheim
f816b9bcb8 Merge pull request #14111 from Mic92/symlinks
Prevent infinite symlink loop in followLinksToStore()
2025-09-29 13:49:19 +02:00
Jörg Thalheim
5ec9138179 Prevent infinite symlink loop in followLinksToStore()
The followLinksToStore() function could hang indefinitely when encountering
symlink cycles outside the Nix store, causing 100% CPU usage and blocking
any operations that use this function.

This affects multiple commands including nix-store --query, --delete,
--verify, nix-env, and nix-copy-closure when given paths with symlink cycles.

The fix adds a maximum limit of 1024 symlink follows (matching the limit
used by canonPath) and throws an error when exceeded, preventing the
infinite loop while preserving the original semantics of stopping at
the first path inside the store.
2025-09-29 12:22:43 +02:00
Jörg Thalheim
a9ffa42dda Fix thread-safety issue with ptsname() usage
Replace non-thread-safe ptsname() calls with a new getPtsName() helper
function that:
- Uses thread-safe ptsname_r() on Linux/BSD platforms
- Uses mutex-protected ptsname() on macOS (which lacks ptsname_r())
2025-09-29 12:01:49 +02:00
Eelco Dolstra
b0431a76f5 Merge pull request #14058 from DeterminateSystems/upstream-RossComputerGuy/feat/expose-logfmt
C API: add log format and verbosity functions
2025-09-29 11:21:43 +02:00
Jörg Thalheim
5e65fa7069 Merge pull request #14109 from Mic92/mingw
fix mingw build
2025-09-29 10:57:43 +02:00
Jörg Thalheim
69eae7770a fix mingw build 2025-09-29 10:29:37 +02:00
Jörg Thalheim
738d141dd9 Merge pull request #14108 from fzakaria/fzakaria/shellcheck-multiple-3
shellcheck fixes for tests/functional/local-overlay-store
2025-09-29 09:58:07 +02:00
Jörg Thalheim
7cbc0f97e7 Merge pull request #14090 from Radvendii/expr-slim
nixexpr: introduce arena to hold ExprString strings
2025-09-29 08:33:10 +02:00
Jörg Thalheim
c5b3567512 Merge pull request #14105 from xokdvium/cpp-bison
libexpr: Switch parser.y to %skeleton lalr1.cc
2025-09-29 08:23:03 +02:00
Farid Zakaria
f394390492 shellcheck fix: tests/functional/local-overlay-store/add-lower-inner.sh 2025-09-28 20:40:08 -07:00
Farid Zakaria
8f0d9412ba shellcheck fix: tests/functional/local-overlay-store/bad-uris.sh 2025-09-28 20:39:40 -07:00
Farid Zakaria
8f14301533 shellcheck fix: tests/functional/local-overlay-store/build-inner.sh 2025-09-28 20:38:46 -07:00
Farid Zakaria
6cae8da29d shellcheck fix: tests/functional/local-overlay-store/check-post-init.sh 2025-09-28 20:37:23 -07:00
Farid Zakaria
bb97f4b07a shellcheck fix: tests/functional/local-overlay-store/common.sh 2025-09-28 20:35:47 -07:00
Farid Zakaria
20665e1c3d shellcheck fix: tests/functional/local-overlay-store/delete-duplicate-inner.sh 2025-09-28 20:32:49 -07:00
Farid Zakaria
326d626ad7 shellcheck fix: tests/functional/local-overlay-store/delete-refs-inner.sh 2025-09-28 20:32:12 -07:00
Farid Zakaria
62b36eba11 shellcheck fix: tests/functional/local-overlay-store/gc-inner.sh 2025-09-28 20:31:09 -07:00
Farid Zakaria
675179a510 shellcheck fix: tests/functional/local-overlay-store/gc.sh 2025-09-28 20:30:02 -07:00
Farid Zakaria
283a9c4c5a shellcheck fix: tests/functional/local-overlay-store/optimise-inner.sh 2025-09-28 20:29:35 -07:00
Farid Zakaria
dbb53de9d3 shellcheck fix: tests/functional/local-overlay-store/redundant-add.sh 2025-09-28 20:28:18 -07:00
Farid Zakaria
0c50d5b25a shellcheck fix: tests/functional/local-overlay-store/redundant-add-inner.sh 2025-09-28 20:27:21 -07:00
Farid Zakaria
1bee4d0988 shellcheck fix: tests/functional/local-overlay-store/redundant-add.sh 2025-09-28 20:25:42 -07:00
Farid Zakaria
4ef4e96788 shellcheck fix: tests/functional/local-overlay-store/remount.sh 2025-09-28 20:25:09 -07:00
Farid Zakaria
c4c95f3d39 shellcheck fix: tests/functional/local-overlay-store/stale-file-handle-inner.sh 2025-09-28 20:24:38 -07:00
Farid Zakaria
e896bf1cb1 shellcheck fix: tests/functional/local-overlay-store/stale-file-handle.sh 2025-09-28 20:24:09 -07:00
Farid Zakaria
3a1ba8e41e shellcheck fix: tests/functional/local-overlay-store/verify-inner.sh 2025-09-28 20:23:19 -07:00
Farid Zakaria
76c9d3885c shellcheck fix: tests/functional/local-overlay-store/verify.sh 2025-09-28 20:22:55 -07:00
John Ericson
676e885f8d Merge pull request #14084 from obsidiansystems/issue-13247-test
Create test for Issue 13247
2025-09-28 19:12:44 -04:00
Sergei Zimmerman
c1f805b856 packaging: Build without symbolic interposition on GCC
This turns out to be a big problem for performance of Bison
generated code, that for whatever reason cannot be made internal
to the shared library. This causes GCC to make a bunch of function
calls go through PLT. Ideally these hot functions (like move/copy ctor) could become
inline in upstream Bison. That will make sure that GCC can do interprocedular
optimizations without -fno-semantic-interposition [^]. Considering that
LLVM already does inlining and whatnot is a good motivation for this change.
I don't know of any case where Nix relies on LD_PRELOAD tricks for the shared
libraries in production use-cases.

[^]: https://maskray.me/blog/2021-05-09-fno-semantic-interposition
2025-09-29 01:46:40 +03:00
Sergei Zimmerman
a8715a2d6e libexpr: Switch parser.y to %skeleton lalr1.cc
Since the parser is now LALR we can easily switch
over to the less ugly sketelon than the default C one.
This would allow us to switch from %union to %define api.value.type variant
in the future to avoid the need for triviall POD types.
2025-09-29 00:58:41 +03:00
John Ericson
241c7cd1f9 Merge pull request #14104 from xokdvium/dead-code-location
libexpr: Remove unused members from ParserLocation
2025-09-28 16:46:50 -04:00
Sergei Zimmerman
0f08feaa58 libexpr: Remove unused members from ParserLocation 2025-09-28 22:57:11 +03:00
Taeer Bar-Yam
eab467ecfb libexpr: introduce arena to hold ExprString strings
1. Saves 24-32 bytes per string (size of std::string)
2. Saves additional bytes by not over-allocating strings (in total we
save ~1% memory)
3. Sets us up to perform a similar transformation on the other Expr
subclasses
4. Makes ExprString trivially moveable (before the string data might
move, causing the Value's pointer to become invalid). This is important
so we can put ExprStrings in an std::vector and refer to them by index

We have introduced a string copy in ParserState::stripIndentation().
This could be removed by pre-allocating the right sized string in the
arena, but this adds complexity and doesn't seem to improve performance,
so for now we've left the copy in.
2025-09-28 14:23:13 -04:00
Sergei Zimmerman
c43ea09b9b Merge pull request #14100 from obsidiansystems/add-missing-pragma-once
Add `#pragma once` to `dummy-store.hh`
2025-09-28 16:41:28 +00:00
John Ericson
582d3ee611 Add #pragma once to dummy-store.hh
We should have a lint for this.

In later (yet to be merged at this time) commits, this started causing
problems that only the sanitzer caught.
2025-09-28 12:12:24 -04:00
John Ericson
f7d35dc1dc Merge pull request #14099 from xokdvium/fix-assert-failure
libstore: Call canonPath for constructing LocalFSStoreConfig::rootDir
2025-09-28 12:06:02 -04:00
Sergei Zimmerman
0866ba0b4a libstore: Deduplicate LocalFSStoreConfig::rootDir initializers
Co-authored-by: John Ericson <John.Ericson@Obsidian.Systems>
2025-09-28 18:38:57 +03:00
John Ericson
a01d52e57b Merge pull request #14063 from obsidiansystems/test-less-macro
Minimize the use of C Macros for characterization tests
2025-09-28 11:14:29 -04:00
John Ericson
87fc579bb7 Merge pull request #14098 from xokdvium/store-references-fixes
libstore: Make all StoreConfig::getReference implementations return s…
2025-09-28 11:11:49 -04:00
Sergei Zimmerman
3a64d3c0da libstore: Call canonPath for constructing LocalFSStoreConfig::rootDir
This mirrors what OptionalPathSetting does. Otherwise we run into
an assertion failure for relative paths specified as the authority + path:

nix build nixpkgs#hello --store "local://a/b"
nix: ../posix-source-accessor.cc:13: nix::PosixSourceAccessor::PosixSourceAccessor(std::filesystem::__cxx11::path&&): Assertion `root.empty() || root.is_absolute()' failed.

This is now diagnosed properly:

error: not an absolute path: 'a/b'

Just as you'd specify the root via a query parameter:

nix build nixpkgs#hello --store "local?root=a/b"
2025-09-28 17:42:19 +03:00
John Ericson
01b2037bc0 Minimize the use of C Macros for characterization tests
Fewer macros is better!

Introduce a new `JsonChacterizationTest` mixin class to help with this.

Also, avoid some needless copies with `GetParam`.

Part of my effort shoring up the JSON formats with #13570.
2025-09-28 09:54:46 -04:00
Sergei Zimmerman
426a72c9cf libstore: Make all StoreConfig::getReference implementations return store parameters
These stragglers have been accidentally left out when implementing the StoreConfig::getReference.
Also HttpBinaryCacheStore::getReference now returns the actual store parameters, not the cacheUri
parameters.
2025-09-28 16:29:12 +03:00
John Ericson
e35abb1102 Create test for issue 13247
This test ends up being skipped, since the bug has not yet been fixed. A
future commit will fix the bug.

Progress on #13247, naturally.
2025-09-27 21:53:14 -04:00
John Ericson
e731c43eae Use std::variant to enforce BuildResult invariants
There is now a clean separation between successful and failing build
results.
2025-09-27 15:56:06 -04:00
John Ericson
43550e8edb Lock down BuildResult::Status enum values
This allows refactoring without changing wire protocol by mistake.
2025-09-27 15:15:20 -04:00
John Ericson
3c610df550 Delete scratch data for CA derivation that produced already-extant output
In the case where the store object doesn't exist, we do correctly move
(rather than copy) the scratch data into place. In this case, the
destination store object already exists, but we still want to clean up
after ourselves.
2025-09-27 15:14:33 -04:00
John Ericson
3bf1268ac6 Merge pull request #14096 from Mic92/concurrency-bugs-2
document thread-unsafe mutation in PosixSourceAccessor
2025-09-27 11:18:56 -04:00
Sergei Zimmerman
b9571b6e52 Merge pull request #13508 from CertainLach/push-oyyysvytlnpr
fix: wait on incomplete assignment in REPL
2025-09-27 10:43:41 +00:00
Yaroslav Bolyukin
0a3eb22360 fix: wait on incomplete assignment in REPL
Fixes: https://github.com/NixOS/nix/issues/13507
2025-09-27 13:25:27 +03:00
Jörg Thalheim
866c9179a0 document thread-unsafe mutation in PosixSourceAccessor 2025-09-26 23:31:56 +02:00
Jörg Thalheim
7817239644 Merge pull request #14092 from rszyma/fix-devshell-attrpath-in-docs
doc: Fix invalid devshell attrpath
2025-09-26 21:01:02 +02:00
Jörg Thalheim
6721ef5feb Merge branch 'master' into fix-fetch-to-store-caching 2025-09-26 20:44:39 +02:00
Jörg Thalheim
be92b18add Merge pull request #14083 from fzakaria/fzakaria/shellcheck-multiple-2
shellcheck fixes
2025-09-26 20:42:43 +02:00
rszyma
7bd67cd8dc doc: Fix invalid devshell attrpath
`native-clangStdenvPackages` devshell attrpath was being mentioned in
development docs, but doesn't work anymore (since 69fde530).
2025-09-26 19:49:36 +02:00
Jörg Thalheim
b5f765b7eb Merge pull request #14047 from Radvendii/eval-memory
libexpr: move eval memory allocation to own struct
2025-09-26 19:24:30 +02:00
Farid Zakaria
2a6724299a shellcheck fix: tests/functional/flakes/follow-paths.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
6fc8f04ecb shellcheck fix: tests/functional/flakes/flakes.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
ac5615dd91 shellcheck fix: tests/functional/flakes/config.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
26a10453c3 shellcheck fix: tests/functional/flakes/check.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
9bf8e7b730 shellcheck fix: tests/functional/flakes/absolute-paths.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
8839bab84d shellcheck fix: completion files 2025-09-26 08:41:30 -07:00
Farid Zakaria
f8e351cd94 shellcheck fix: tests/functional/fixed 2025-09-26 08:41:30 -07:00
Farid Zakaria
4cec876319 shellcheck fix: tests/functional/fetchMercurial.sh 2025-09-26 08:41:30 -07:00
Farid Zakaria
c4c3524318 shellcheck fix: tests/functional/fetchGitVerification.sh 2025-09-26 08:41:29 -07:00
Tristan Ross
bb6a4dccdf libutil-c: add nix_set_verbosity function 2025-09-26 08:31:23 -07:00
Eelco Dolstra
8aa4669328 Merge pull request #14086 from getchoo-contrib/getchoo/help-pure-eval
nix-cli: use pure/restricted eval for help pages
2025-09-26 11:32:14 +02:00
Seth Flynn
ff82de86da nix-cli: use pure/restricted eval for help pages
This avoids any complications that can arise from the environment
affecting evaluation of the help pages (which don't need to be calling
out to anything external anyways)

A recent example of one of these problems is
https://github.com/NixOS/nix/issues/14085, which would break help pages
by causing them to make invalid calls to the dummy store they're
evaluated with

Fixes: https://github.com/NixOS/nix/issues/14062
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-09-26 02:05:58 -04:00
Taeer Bar-Yam
7b3c193bd3 libexpr: move eval memory allocation to own struct
Co-authored-by: eldritch horrors <pennae@lix.systems>
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>

See original commit on lix:
f5754dc90a
2025-09-26 00:40:43 +03:00
Farid Zakaria
53ad2433b4 shellcheck fix: tests/functional/fetchGitSubmodules.sh 2025-09-25 13:09:36 -07:00
Farid Zakaria
ea035ae165 shellcheck fix: tests/tests/functional/dump-db.sh 2025-09-25 13:07:41 -07:00
John Ericson
89141f1d67 Merge pull request #14082 from fzakaria/fzakaria/shellcheck-multiple
shellcheck: multiple file fixes
2025-09-25 15:59:43 -04:00
Farid Zakaria
1619409bf2 shellcheck fix: tests/functional/fetchGitRefs.sh 2025-09-25 12:45:43 -07:00
Farid Zakaria
32e1b5209b shellcheck fix: tests/functional/fetchGit.sh 2025-09-25 12:45:43 -07:00
Farid Zakaria
d07dd92db3 shellcheck fix: tests/functional/fetchClosure.sh 2025-09-25 12:45:43 -07:00
Farid Zakaria
230da1cbe7 shellcheck fix: tests/functional/export.sh 2025-09-25 12:45:40 -07:00
Tristan Ross
cf595b81d5 libmain-c: add nix_set_log_format function 2025-09-25 10:57:48 -07:00
Farid Zakaria
9e3c502521 shellcheck fix: tests/functional/extra-sandbox-profile.sh 2025-09-25 10:35:26 -07:00
Farid Zakaria
a209748ec0 shellcheck fix: tests/functional/export-graph.sh 2025-09-25 10:35:01 -07:00
Farid Zakaria
b8c24cdaef shellcheck fix: tests/functional/eval-store.sh 2025-09-25 10:33:40 -07:00
Jörg Thalheim
e3d62f35ea Merge pull request #14075 from fzakaria/fzakaria/shellcheck-functional-dump-db
shellcheck fix functional/dump-db.sh
2025-09-25 19:31:49 +02:00
Farid Zakaria
dc69e2e520 shellcheck fix: tests/functional/dyn-drv/recursive-mod-json.sh 2025-09-25 10:31:06 -07:00
Farid Zakaria
119489f253 shellcheck fix: tests/functional/dyn-drv/old-daemon-error-hack.sh 2025-09-25 10:30:03 -07:00
Farid Zakaria
412e51215f shellcheck fix: functional/dyn-drv/eval-outputOf.sh 2025-09-25 10:29:27 -07:00
Eelco Dolstra
4b9735b761 Test against uncacheable paths
This is to test the non-functional property that most paths should be
cacheable. We've had frequent cases where caching broken but we didn't
notice.
2025-09-25 11:30:11 -04:00
Eelco Dolstra
1d130492d7 Mount inputs on storeFS to restore fetchToStore() caching
fetchToStore() caching was broken because it uses the fingerprint of
the accessor, but now that the accessor (typically storeFS) is a
composite (like MountedSourceAccessor or AllowListSourceAccessor),
there was no fingerprint anymore. So fetchToStore now uses the new
getFingerprint() method to get the specific fingerprint for the
subpath.
2025-09-25 11:30:11 -04:00
Eelco Dolstra
ec6d5c7de3 Path fetcher: Simplify fingerprint computation 2025-09-25 11:21:14 -04:00
Eelco Dolstra
3450a72ba0 Git fetcher: Make dirty repos with no commits cacheable 2025-09-25 11:20:00 -04:00
Eelco Dolstra
28d11c5bcc Add SourceAccessor::getFingerprint()
This returns the fingerprint for a specific subpath. This is intended
for "composite" accessors like MountedSourceAccessor, where different
subdirectories can have different fingerprints.
2025-09-25 11:20:00 -04:00
Eelco Dolstra
55c7ef9d40 SourceAccessor: Make lstat() virtual
With FilteringSourceAccessor, lstat() needs to throw a different
exception if the path is inaccessible than if it doesn't exist.
2025-09-25 11:20:00 -04:00
John Ericson
46095284f1 Merge pull request #14080 from NixOS/storeFS-prep
Some `storeFS` and similar cleanup
2025-09-25 10:50:25 -04:00
Jörg Thalheim
099a74e9f4 Merge pull request #14041 from getchoo-contrib/getchoo/cache-substituted-inputs
libfetchers: avoid re-copying substituted inputs
2025-09-25 13:27:02 +02:00
Seth Flynn
74305d5260 libfetchers: avoid re-copying substituted inputs
Previously, Nix would not create a cache entry for substituted/cached
inputs

This led to severe slowdowns in some scenarios where a large input (like
Nixpkgs) had already been unpacked to the store but didn't exist in a
users cache, as described in https://github.com/NixOS/nix/issues/11228

Using the same method as https://github.com/NixOS/nix/pull/12911, we can
create a cache entry for the fingerprint of substituted/cached inputs
and avoid this problem entirely
2025-09-25 04:04:57 -04:00
Jörg Thalheim
534b29068a Merge pull request #14071 from fzakaria/fzakaria/shellcheck-functional-db-migration
shellcheck fix functional/db-migration.sh
2025-09-25 09:44:09 +02:00
Jörg Thalheim
697c704f28 Merge branch 'master' into fzakaria/shellcheck-functional-db-migration 2025-09-25 09:26:32 +02:00
Farid Zakaria
6e2c11e296 shellcheck fix functional/dump-db.sh
Add back the path variable
2025-09-25 09:24:39 +02:00
Jörg Thalheim
bdd3eb400a Merge pull request #14030 from roberth/c-api-item-access
C API: Various improvements to attribute/item access
2025-09-25 09:06:11 +02:00
John Ericson
ae896bebdf Merge pull request #14067 from fzakaria/fzakaria/shellcheck-systemd-multi-user
shellcheck fix scipts/install-systemd-multi-user.sh
2025-09-25 02:50:40 -04:00
Jörg Thalheim
eb04a6d3e3 Merge pull request #14079 from obsidiansystems/clean-up-why-depends
Clean up `nix why-depends` store accessor usage, and put back store dir in output
2025-09-25 08:49:12 +02:00
Jörg Thalheim
a08ae1d024 doc: Add release notes for C API lazy accessors 2025-09-25 08:45:32 +02:00
Jörg Thalheim
1877c477fc Merge branch 'master' into fzakaria/shellcheck-functional-db-migration 2025-09-25 08:35:45 +02:00
Jörg Thalheim
6dcfce0450 Merge branch 'master' into fzakaria/shellcheck-systemd-multi-user 2025-09-25 08:35:10 +02:00
Jörg Thalheim
ed3f847225 Merge pull request #14051 from NixOS/atomic-counters
Atomic statistics counters
2025-09-25 08:24:37 +02:00
John Ericson
2898dbe2d9 Merge pull request #14073 from fzakaria/fzakaria/shellcheck-functional-dependencies.builder0
shellcheck fix functional/dependencies.builder0.sh
2025-09-25 02:10:14 -04:00
Eelco Dolstra
e8f951289f EvalState: Don't maintain stats by default
These counters are extremely expensive in a multi-threaded
program. For instance, disabling them speeds up evaluation of the
NixOS/nix/2.21.2 from 32.6s to 17.8s.
2025-09-25 08:03:24 +02:00
Eelco Dolstra
8d257f5510 EvalState: Make the counters atomic 2025-09-25 08:03:24 +02:00
Jörg Thalheim
a6fcca3888 Merge branch 'master' into fzakaria/shellcheck-functional-db-migration 2025-09-25 07:54:43 +02:00
Farid Zakaria
e15c44d46b shellcheck fix functional/db-migration.sh 2025-09-25 07:53:29 +02:00
Jörg Thalheim
f3416913d4 Merge pull request #14069 from fzakaria/fzakaria/shellcheck-compute-levels
shellcheck fix for functional/compute-levels.sh
2025-09-25 07:52:56 +02:00
John Ericson
7f9867b548 Merge pull request #14076 from fzakaria/fzakaria/shellcheck-functional-dyn-drv-build-built-drv
shellcheck fix functional/dyn-drv/build-built-drv.sh
2025-09-25 01:51:21 -04:00
Jörg Thalheim
8ff5aeb367 Merge pull request #14065 from obsidiansystems/realisation-json-unit-test
Add JSON tests for `Realisation`
2025-09-25 07:42:15 +02:00
Jörg Thalheim
3076cc9e84 Merge branch 'master' into fzakaria/shellcheck-systemd-multi-user 2025-09-25 07:40:27 +02:00
Jörg Thalheim
31695f3690 Merge branch 'master' into fzakaria/shellcheck-compute-levels 2025-09-25 07:39:25 +02:00
Jörg Thalheim
a534a27571 Merge branch 'master' into fzakaria/shellcheck-functional-dependencies.builder0 2025-09-25 07:37:30 +02:00
Jörg Thalheim
5d6af1243a Merge branch 'master' into fzakaria/shellcheck-functional-dyn-drv-build-built-drv 2025-09-25 07:35:10 +02:00
John Ericson
9b2f282af5 Simplify the definition of rootFS
It was getting very hard to follow.
2025-09-25 00:14:14 -04:00
Eelco Dolstra
35189c0ae0 Expose the fact that storeFS is a MountedSourceAccessor
This will become useful.
2025-09-25 00:14:14 -04:00
John Ericson
8ef70ef522 Rename one overload to allowPathLegacy
Makes it easier to tell when it is isued.
2025-09-25 00:14:14 -04:00
Eelco Dolstra
339338e166 MountedSourceAccessor: Move into a separate header, add mount method 2025-09-25 00:14:14 -04:00
Farid Zakaria
bc13130497 shellcheck fix tests/functional/dyn-drv/dep-built-drv.sh (#14078) 2025-09-25 03:28:16 +00:00
John Ericson
d26dee20b2 Clean up nix why-depends store accessor usage, and put back store dir in output
With this change, the store-wide `getFSAccessor` has only one usage left
--- the evaluator. If we get rid of that (as is planned), we can then
remove that method altogether, simplifying `Store`. Hurray!

I removed the store dir by mistake from the pretty-printed (for humans)
output in eb643d034f. That change was not
supposed to change output.
2025-09-24 23:06:03 -04:00
John Ericson
d1958e1b2c Merge pull request #14066 from fzakaria/fzakaria/shellcheck-install-multi-user
shellcheck fix scripts/install-multi-user.sh
2025-09-24 23:00:16 -04:00
John Ericson
d0e2babee1 Merge pull request #14072 from fzakaria/fzakaria/shellcheck-functional-debugger
shellcheck fix: functional/debugger.sh
2025-09-24 22:58:32 -04:00
John Ericson
d2595130c6 Merge pull request #14074 from fzakaria/fzakaria/shellcheck-functional-dependencies
shellcheck fix functional/dependencies.sh
2025-09-24 22:57:09 -04:00
John Ericson
db25195bb2 Merge pull request #14077 from fzakaria/fzakaria/shellcheck-dyn-drv-common
shellcheck fix functional/dyn-drv/common.sh
2025-09-24 22:51:55 -04:00
John Ericson
5842aa2cac Merge pull request #14070 from fzakaria/fzakaria/shellcheck-functional-config.sh
shellcheck fix functional/config.sh
2025-09-24 22:47:21 -04:00
John Ericson
1e1c6d1042 Merge pull request #14068 from fzakaria/fzakaria/shellcheck-functional-completions.sh
shellcheck fix tests/functional/completions.sh
2025-09-24 22:44:32 -04:00
Farid Zakaria
614ef6cfb1 shellcheck fix functional/dyn-drv/common.sh 2025-09-24 19:18:30 -07:00
Farid Zakaria
59791082fa shellcheck fix functional/dyn-drv/build-built-drv.sh 2025-09-24 19:17:12 -07:00
Farid Zakaria
98f716f78c Revert change for SC2059 for nix_user_for_core 2025-09-24 19:13:46 -07:00
Farid Zakaria
c7c74fec67 shellcheck fix functional/dependencies.sh 2025-09-24 19:11:00 -07:00
Farid Zakaria
121a8ab3ec shellcheck fix functional/dependencies.builder0.sh 2025-09-24 19:09:21 -07:00
Farid Zakaria
67d43f3b12 shellcheck fix: functional/debugger.sh 2025-09-24 19:06:23 -07:00
Farid Zakaria
832100f543 shellcheck fix functional/config.sh 2025-09-24 18:59:41 -07:00
Farid Zakaria
2732812524 Enable shellcheck for functional/compute-levels.sh 2025-09-24 18:57:30 -07:00
Farid Zakaria
92f8f87dd1 shellcheck fix tests/functional/completions.sh 2025-09-24 18:56:00 -07:00
Farid Zakaria
76b9565414 shellcheck fix scipts/install-systemd-multi-user.sh 2025-09-24 18:52:46 -07:00
Farid Zakaria
c77b15a178 shellcheck fix scripts/install-multi-user.sh 2025-09-24 18:49:53 -07:00
John Ericson
30691c38c2 Add JSON tests for Realisation 2025-09-24 18:09:24 -04:00
John Ericson
9f26c20ebd Merge pull request #14057 from obsidiansystems/derived-path-json
Modernize and test derived path JSON
2025-09-24 18:08:06 -04:00
John Ericson
f2cd6235a7 Merge pull request #14056 from obsidiansystems/better-output-spec-json-tests
Convert `{Extended,}OutputsSpec` JSON tests to characterization tests
2025-09-24 17:41:25 -04:00
Sergei Zimmerman
05279f2ba0 Merge pull request #14061 from xokdvium/k-way-update
libexpr: Preparation for more k-way updates of attribute sets (NFC)
2025-09-25 00:29:54 +03:00
John Ericson
19fa132a8c Merge pull request #14049 from NixOS/per-object-fs-accessor
Create a second `Store::getFSAccessor` for a single store object
2025-09-24 17:29:10 -04:00
John Ericson
a97d6d89d8 Create a second Store::getFSAccessor for a single store object
This is sometimes easier / more performant to implement, and
independently it is also a more convenient interface for many callers.

The existing store-wide `getFSAccessor` is only used for

 - `nix why-depends`
 - the evaluator

I hope we can get rid of it for those, too, and then we have the option
of getting rid of the store-wide method.

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-09-24 15:49:14 -04:00
Sergei Zimmerman
97ce7759d0 libexpr: Use same naive iterative merging but with evalForUpdate 2025-09-24 21:47:59 +03:00
Jörg Thalheim
0175f7e836 Merge pull request #14059 from xokdvium/formatting-ci
ci: Split formatting check into a separate job, gate other jobs
2025-09-24 13:29:22 +02:00
Jörg Thalheim
00775ad83c Apply suggestion from @getchoo
Co-authored-by: Seth Flynn <getchoo@tuta.io>
2025-09-24 13:14:00 +02:00
Sergei Zimmerman
9789019a50 libexpr: Move *StackReservation constants to gc-small-vector.hh
There are other places where it's useful to use these constants
(notably in eval.hh).
2025-09-24 01:05:18 +03:00
Sergei Zimmerman
b7c6cf900f libexpr: Explicitly define ExprOpUpdate 2025-09-24 01:04:26 +03:00
Sergei Zimmerman
e282175f48 libexpr: Split out MakeBinOpMembers from MakeBinOp 2025-09-24 01:04:23 +03:00
Sergei Zimmerman
35d8ffe01d ci: Split formatting check into a separate job, gate other jobs
This makes the CI fail fast and more explicitly in case the formatting
is incorrect and provides a better error messages. This also ensures
that we don't burn CI on useless checks for code that wouldn't pass lints
anyway.
2025-09-24 00:34:35 +03:00
John Ericson
d23e59bb6b Modernize and test derived path JSON
Old code is now just used for `nix build` --- there is no CLI breaking
change.

Test the new format, too.

The new format is not currently used, but will be used going forward,
for example in the C API.

Progress on #13570
2025-09-23 15:05:56 -04:00
Eelco Dolstra
73d3ab05b6 Merge pull request #14054 from obsidiansystems/to-json-no-copy
Fix `JSON_IMPL` macro to avoid extraneous copies
2025-09-23 20:58:12 +02:00
John Ericson
f24e00710e Convert {Extended,}OutputsSpec JSON tests to characterization tests
This brings them in line with the other tests, and furthers my goals of
separating unit test data from code.

Doing this cleanup as part of my #13570 effort, but strictly-speaking,
this is separate as these data types' JSON never contained and store
paths or store dirs, just simple output name strings.
2025-09-23 14:47:00 -04:00
Eelco Dolstra
03440946cd Merge pull request #14055 from obsidiansystems/rm-pointless-std-visit
Remove some pointless `std::visit`
2025-09-23 20:14:33 +02:00
John Ericson
1c71cb4005 Remove some pointless std::visit
These are not needed, because the `toJSON` methods are already
implemented for the variant wrapper too.
2025-09-23 13:59:27 -04:00
John Ericson
af71a9dbd9 Fix JSON_IMPL macro to avoid extraneous copies
Should take the thing we're serializing by reference.
2025-09-23 13:05:12 -04:00
John Ericson
d9de675357 Merge pull request #14027 from obsidiansystems/more-ca-tests
More floating content-addressing derivation tests
2025-09-22 17:09:39 -04:00
John Ericson
7ea31c6e56 Run multiple outputs and build-delete test for CA drvs also 2025-09-22 16:54:30 -04:00
Jörg Thalheim
af82c847a7 Merge pull request #14048 from roberth/shellcheck
Shellcheck
2025-09-22 21:57:42 +02:00
Robert Hensing
8a9d9bb0e9 pre-commit: Remove exclusion for removed file 2025-09-22 21:06:26 +02:00
Robert Hensing
4183308ee2 tests/func*/characterisation-test-infra: Fix shellcheck 2025-09-22 21:06:26 +02:00
Robert Hensing
993ea14f52 pre-commit: Remove exclude that passes 2025-09-22 21:06:26 +02:00
Robert Hensing
926287d813 tests/func*/ca/common: Fix shellcheck 2025-09-22 21:06:26 +02:00
Robert Hensing
8c31e07cce tests/func*/ca/build-with-garbage-path: Fix shellcheck 2025-09-22 21:06:26 +02:00
John Ericson
5292b0e49e Merge pull request #14038 from NixOS/thread-safe-dummy
libstore: Make writable dummy store thread-safe
2025-09-22 14:26:35 -04:00
Robert Hensing
01357d0808 Merge pull request #14012 from obsidiansystems/drv-realisation-issue-13570
Convert Realisation JSON logic to standard style
2025-09-22 20:25:06 +02:00
Robert Hensing
8b97d14c08 pre-commit: Give reason for ca test wrappers exclusion 2025-09-22 19:57:28 +02:00
Robert Hensing
5af644492b nix develop: Apply shellcheck 2025-09-22 19:31:22 +02:00
Sergei Zimmerman
5915fe3190 Revert "Use shared pointers in the memory source accessor"
This is no longer necessary.

This reverts commit 4df60e639b.
2025-09-22 20:22:17 +03:00
Sergei Zimmerman
c4c92c4c61 libstore: Make writable dummy store thread-safe
Tested by building with b_sanitize=thread and running:

nix flake prefetch-inputs --store "dummy://?read-only=false"

It might make sense to move this utility class out of dummy-store.cc,
but it seems fine for now.
2025-09-22 20:22:16 +03:00
Robert Hensing
43ec36cddf pre-commit: Remove exclude that passes 2025-09-22 19:21:06 +02:00
Robert Hensing
033f13fb1a pre-commit: Remove exclude that passes 2025-09-22 19:19:39 +02:00
Robert Hensing
34e9caaf9b pre-commit: Move zsh exclude 2025-09-22 19:18:52 +02:00
Robert Hensing
6195dfff3a pre-commit: Move fish exclude 2025-09-22 19:17:58 +02:00
Sergei Zimmerman
c71f80b6eb libstore: Implement boost::hash for StorePath 2025-09-22 20:16:11 +03:00
Robert Hensing
1878e788ce misc/bash/completion.sh: Fix shellcheck 2025-09-22 19:15:44 +02:00
Robert Hensing
c12187b15a pre-commit: Drop exclude config/install-sh
This file was part of the make-based build, which has been removed.
2025-09-22 19:12:33 +02:00
Robert Hensing
df23f2b3c1 packaging/dev-shell: Add shellcheck
It was already in the closure for the pre-commit hook installation
script.
2025-09-22 19:09:35 +02:00
John Ericson
91593a237f Convert Realisation JSON logic to standard style
No behavior is changed, just:

- Declare a canonical `nlohmnan::json::adl_serializer`

- Use `json-utils.hh` to shorten code without getting worse error
  messages.

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2025-09-22 12:59:37 -04:00
John Ericson
6389f65d63 Rework derivation format release note slightly 2025-09-22 12:59:37 -04:00
Robert Hensing
169a368459 Merge pull request #14040 from NixOS/import-thunk
Ensure that files are parsed/evaluated only once (2nd attempt)
2025-09-22 18:33:00 +02:00
Eelco Dolstra
a0103fc302 Merge pull request #13852 from lovesegfault/warn-no-kvm
feat(libstore): warn when kvm is enabled but /dev/kvm isn't available
2025-09-22 18:31:57 +02:00
Jörg Thalheim
dcaf001d52 Merge pull request #14021 from jfroche/fix/installer-shell-path
installer: prepend nix paths to shell config files instead of appending
2025-09-22 18:27:03 +02:00
John Ericson
74b31d10db Merge pull request #14042 from corngood/cygwin-cross
fix cross build for cygwin
2025-09-22 11:55:40 -04:00
David McFarland
32d4ea8140 fix cross-build for cygwin 2025-09-22 12:27:04 -03:00
Eelco Dolstra
d32d77f4d4 Allocate ExprParseFile on the heap for now
https://github.com/NixOS/nix/pull/14013#issuecomment-3308085755
2025-09-22 12:06:51 +02:00
Robert Hensing
28c0089268 Merge pull request #14039 from NixOS/document-expr-methods
libexpr: Document {eval,maybeThunk} methods
2025-09-22 11:59:55 +02:00
Eelco Dolstra
5f60602875 Reapply "Merge pull request #13938 from NixOS/import-thunk"
This reverts commit fd034814dc.
2025-09-22 11:48:58 +02:00
Robert Hensing
71b27774f0 libexpr: Document {eval,maybeThunk} methods 2025-09-22 01:41:02 +03:00
Robert Hensing
c121c65640 C API: Clarify valid use of bindings ordering 2025-09-21 21:16:46 +02:00
Robert Hensing
ab7feb3898 Merge pull request #14023 from NixOS/dummy-store-path-info
Make dummy store also store path info
2025-09-21 16:58:18 +02:00
Sergei Zimmerman
a453a49043 tests: Tests for writeable dummy in-memory store 2025-09-21 13:36:31 +03:00
Sergei Zimmerman
b66c357b58 libstore: Implement DummyStore::narFromPath 2025-09-21 13:19:50 +03:00
Sergei Zimmerman
3a4c618483 libstore: Fix typo in description of dummy store 2025-09-21 13:19:49 +03:00
Sergei Zimmerman
ed9b377928 libstore: Disable path info cache for dummy store 2025-09-21 13:19:48 +03:00
Sergei Zimmerman
341878ce0f libstore: Make dummy store also store path info 2025-09-21 13:19:47 +03:00
Sergei Zimmerman
02c9ac445f libutil: Improve handling of non-directory root in MemorySourceAccessor 2025-09-21 13:19:45 +03:00
John Ericson
4df60e639b Use shared pointers in the memory source accessor
This allows aliasing, like hard links.
2025-09-21 13:19:44 +03:00
John Ericson
f66b56ad3f Merge pull request #14035 from NixOS/github-fetcher-accessor
libfetchers/github: Use getFSAccessor for downloadFile result
2025-09-20 21:42:54 -04:00
Sergei Zimmerman
e04381edbd libfetchers/github: Use getFSAccessor for downloadFile result
We should use proper abstractions for reading files from the store.
E.g. this caused errors when trying to download github flakes into
an in-memory store in #14023.
2025-09-21 01:12:42 +03:00
Robert Hensing
d8d1fb0e34 Merge pull request #14029 from roberth/enable-libexpr-tests
libexpr-tests: Enable when test setup for building succeeds
2025-09-20 00:57:15 +02:00
Robert Hensing
d0b1caf53a C API: Document and verify NIX_ERR_KEY behavior 2025-09-20 00:13:50 +02:00
Robert Hensing
2d1b412e5b libexpr-tests: Enable when test setup for building succeeds
Accidentally disabled by 9bc218ca3f
2025-09-19 23:39:00 +02:00
Robert Hensing
3d777eb37f C API: Add lazy attribute value and list item accessors 2025-09-19 23:39:00 +02:00
Robert Hensing
7c553a30a9 C API: Improve nix_get_attr_name_byidx() doc 2025-09-19 23:39:00 +02:00
Robert Hensing
0e74b25f62 C API: Fix bounds checking in _byidx functions
The docs weren't 100% clear about bounds checking, but suggested that
errors would be caught.
The bounds checks are cheap compared to the function calls they're in,
so we have no reason to omit them.
2025-09-19 23:39:00 +02:00
John Ericson
773dd61d1c Merge pull request #14026 from lovesegfault/s3-url-tests
test(libstore): additional ParsedS3Url tests
2025-09-19 17:08:36 -04:00
Bernardo Meurer Costa
b63d9fbc87 test(libstore): additional ParsedS3Url tests
Extracted from the work in #13752
2025-09-19 20:52:44 +00:00
Jean-François Roche
a408bc3e30 installer: prepend nix paths to shell config files instead of appending
Some distribution will stop evaluating the shell config file if
they are not running in an interactive shell. As we append the nix
paths to the end of the file, they will not be evaluated.

We better prepend the nix paths to the shell config files to be sure
that once nix is installed, nix path will be available in any shell.

Note that this is already the case for the detsys installer script for
a while: https://github.com/DeterminateSystems/nix-installer/pull/148

Possibly related errors:

https://github.com/NixOS/nix/issues/8061
https://github.com/NixOS/nix/pull/6628
https://github.com/NixOS/nix/issues/2587
2025-09-19 14:06:06 +02:00
Jörg Thalheim
07b96c1d14 Merge pull request #14018 from NixOS/fix-soname-for-real
meson: Fix SONAME for unstable versions
2025-09-19 13:01:04 +02:00
John Ericson
936334638d Merge pull request #14020 from xokdvium/dummy-store-fixes
libstore: Set display prefix for dummy store
2025-09-19 00:00:00 -04:00
John Ericson
8719c2e6b7 Merge pull request #14016 from xokdvium/asan
treewide: Support builds with ASAN, enable in CI
2025-09-18 23:48:23 -04:00
Sergei Zimmerman
72e2b0efea libstore: Set display prefix for dummy store
Otherwise the prefix is «unknown».
2025-09-19 02:28:59 +03:00
Sergei Zimmerman
d5e84383d1 doc: Document building with sanitizers 2025-09-19 01:37:15 +03:00
Sergei Zimmerman
94d37e62fc treewide: Support builds with ASAN, enable in CI
Enables builds with ASAN to catch memory corruption
bugs faster and in CI. This is an incredibly valuable
instrument that must be used as much as possible.

Somewhat based on jade's work from Lix, though there's a lot that
we have to do differently:

19ae87e5ce

Co-authored-by: Jade Lovelace <lix@jade.fyi>
2025-09-19 01:33:57 +03:00
Sergei Zimmerman
7dbfe9f576 meson: Fix SONAME for unstable versions
Replacing the string is not enough [^] for e.g. nixpkgs precise versions:

`2.31pre20250712_b1245123`

[^]: https://github.com/NixOS/nixpkgs/pull/444089
2025-09-18 23:34:27 +03:00
Jörg Thalheim
3a687eeb4f Merge pull request #14015 from eclairevoyant/doc-global-builtins
doc: document global builtins
2025-09-18 08:11:18 +02:00
Jörg Thalheim
4808b0e24f Merge pull request #14014 from xokdvium/fish delete
libexpr-c: Fix mismatched new/delete
2025-09-18 08:08:39 +02:00
éclairevoyant
40b47b9395 doc: document global builtins 2025-09-18 00:04:31 -04:00
Sergei Zimmerman
309d55807c libexpr-c: Fix mismatched new/delete
This leads to ASAN errors:

==1137785==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x523000001d00 in thread T0:
  object passed to delete has wrong type:
  size of the allocated type:   5968 bytes;
  size of the deallocated type: 5968 bytes.
  alignment of the allocated type:   8 bytes;
  alignment of the deallocated type: default-aligned.
2025-09-18 02:58:32 +03:00
Jörg Thalheim
9d8c6a6646 Merge pull request #14013 from xokdvium/revert-13938
Revert "Merge pull request #13938 from NixOS/import-thunk"
2025-09-18 01:23:14 +02:00
Sergei Zimmerman
fd034814dc Revert "Merge pull request #13938 from NixOS/import-thunk"
This has multiple dangling pointer issues that lead to segfaults in e.g.:

nix eval --expr '(builtins.getFlake "github:nixos/nixpkgs/25.05")' --impure

This reverts commit ad175727e4, reversing
changes made to d314750174.
2025-09-18 01:52:46 +03:00
Robert Hensing
b4fcb64276 Merge pull request #13980 from obsidiansystems/drv-json-issue-13570
Make the JSON format for derivation use basename store paths
2025-09-17 23:31:41 +02:00
Robert Hensing
82315c3807 Merge pull request #13987 from xokdvium/bindings-bananza
libexpr: Structural sharing of attrsets
2025-09-17 23:15:05 +02:00
Sergei Zimmerman
0ccb00bb81 libexpr: Add release note for c-api-byidx change 2025-09-17 23:54:46 +03:00
Sergei Zimmerman
6138bc3de3 libexpr: Structural sharing of attrsets
This changes the implementation of Bindings to allow
for a more space-efficient implementation of attribute
set merges. This is accomplished by "layering" over the "base" Bindings.
The top "layer" is naturally the right-hand-side of the update operator //.

Such an implementation leads to significantly better memory usage on
something like nixpkgs:

nix-env --query --available --out-path --file ../nixpkgs --eval-system x86_64-linux > /dev/null

Comparison against 2b0fd88324 for x86_64-linux on nixpkgs f06c7c3b6f5074dbffcf02542fb86af3a5526afa:

| metric                 | mean_before     | mean_after      | mean_diff       | mean_%_change | p_value | t_stat  |
| -                      | -               | -               | -               | -             | -       | -       |
| cpuTime                | 21.1520         | 21.3414         | 0.1894          | 0.7784        | 0.3190  | 1.0219  |
| envs.bytes             | 461451951.6190  | 461451951.6190  | -               | -             | -       | -       |
| envs.elements          | 34344544.8571   | 34344544.8571   | -               | -             | -       | -       |
| envs.number            | 23336949.0952   | 23336949.0952   | -               | -             | -       | -       |
| gc.cycles              | 7.5238          | 7.2857          | -0.2381         | -4.6825       | 0.0565  | -2.0244 |
| gc.heapSize            | 1777848124.9524 | 1252162023.6190 | -525686101.3333 | -29.9472      | 0.0000  | -8.7041 |
| gc.totalBytes          | 3102787383.6190 | 2498431578.6667 | -604355804.9524 | -19.7704      | 0.0000  | -9.3502 |
| list.bytes             | 59928225.9048   | 59928225.9048   | -               | -             | -       | -       |
| list.concats           | 1240028.2857    | 1240028.2857    | -               | -             | -       | -       |
| list.elements          | 7491028.2381    | 7491028.2381    | -               | -             | -       | -       |
| nrAvoided              | 28165342.2381   | 28165342.2381   | -               | -             | -       | -       |
| nrExprs                | 1577412.9524    | 1577412.9524    | -               | -             | -       | -       |
| nrFunctionCalls        | 20970743.4286   | 20970743.4286   | -               | -             | -       | -       |
| nrLookups              | 10867306.0952   | 10867306.0952   | -               | -             | -       | -       |
| nrOpUpdateValuesCopied | 61206062.0000   | 25748169.5238   | -35457892.4762  | -58.8145      | 0.0000  | -8.9189 |
| nrOpUpdates            | 2167097.4286    | 2167097.4286    | -               | -             | -       | -       |
| nrPrimOpCalls          | 12337423.4286   | 12337423.4286   | -               | -             | -       | -       |
| nrThunks               | 29361806.7619   | 29361806.7619   | -               | -             | -       | -       |
| sets.bytes             | 1393822818.6667 | 897587655.2381  | -496235163.4286 | -36.7168      | 0.0000  | -9.1115 |
| sets.elements          | 84504465.3333   | 48270845.9524   | -36233619.3810  | -43.8698      | 0.0000  | -8.9181 |
| sets.number            | 5218921.6667    | 5218921.6667    | -               | -             | -       | -       |
| sizes.Attr             | 16.0000         | 16.0000         | -               | -             | -       | -       |
| sizes.Bindings         | 8.0000          | 24.0000         | 16.0000         | 200.0000      | -       | inf     |
| sizes.Env              | 8.0000          | 8.0000          | -               | -             | -       | -       |
| sizes.Value            | 16.0000         | 16.0000         | -               | -             | -       | -       |
| symbols.bytes          | 1368494.0952    | 1368494.0952    | -               | -             | -       | -       |
| symbols.number         | 109147.1905     | 109147.1905     | -               | -             | -       | -       |
| time.cpu               | 21.1520         | 21.3414         | 0.1894          | 0.7784        | 0.3190  | 1.0219  |
| time.gc                | 1.6011          | 0.8508          | -0.7503         | -37.1507      | 0.0017  | -3.6328 |
| time.gcFraction        | 0.0849          | 0.0399          | -0.0450         | -37.4504      | 0.0035  | -3.3116 |
| values.bytes           | 615968144.7619  | 615968144.7619  | -               | -             | -       | -       |
| values.number          | 38498009.0476   | 38498009.0476   | -               | -             | -       | -       |

Overall this does slow down the evaluator slightly (no more than ~10% in most cases),
but this seems like a very decent tradeoff for shaving off 33% of memory usage.
2025-09-17 23:54:45 +03:00
John Ericson
9d7229a2a4 Make the JSON format for derivation use basename store paths
See #13570 for details --- the idea is that included the store dir in
store paths makes systematic JSON parting with e.g. Serde, Aeson,
nlohmann, or similiar harder.

After talking to Eelco, we are changing the `Derivation` format right
away because not only is `nix derivation` technically experimental, we think it is
also less widely used in practice than, say, `nix path-info`.

Progress on #13570
2025-09-17 16:38:17 -04:00
Robert Hensing
3eb223f4bb Merge pull request #10915 from NixOS/dummy-memory
Use `MemorySourceAccessor` in `DummyStore` so writes work
2025-09-17 22:33:17 +02:00
John Ericson
d5ce8c3caa Use MemorySourceAccessor in DummyStore
Add `read-only` setting to `dummy://` store for back compat.

Test by changing an existing test to use this instead, fixing a TODO.

Co-Authored-By: HaeNoe <git@haenoe.party>
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
2025-09-17 16:09:53 -04:00
Eelco Dolstra
7ff61576f2 Merge pull request #14009 from xokdvium/fix-authorization
Revert "tests/nixos: Fix daemon store reference in authorization test"
2025-09-17 21:58:44 +02:00
John Ericson
168c24b605 Declare DummyStoreConfig in a header
This will useful for unit tests.
2025-09-17 15:54:30 -04:00
John Ericson
613de9d9cc Add missing #pragma once 2025-09-17 15:21:21 -04:00
Sergei Zimmerman
86ad8d49f9 Revert "tests/nixos: Fix daemon store reference in authorization test"
This reverts commit 695f3bc7e3.
2025-09-17 22:05:26 +03:00
Jörg Thalheim
187520ce88 Merge pull request #14008 from juhp/update-COPYING
COPYING: update to latest lgpl-2.1.txt
2025-09-17 20:15:01 +02:00
Jens Petersen
a66ba324d7 COPYING: update to latest lgpl-2.1.txt (fixes #13758)
$ curl -I https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
:
Last-Modified: Wed, 18 Sep 2024 14:34:04 GMT
ETag: "6733-62265b29fd1ee"
:
2025-09-18 00:45:01 +08:00
Jörg Thalheim
7822bd5692 Merge pull request #14005 from juhp/nix_soversion
nix-meson-build-support/common nix_soversion: fixup removal of 'pre'
2025-09-17 12:19:57 +02:00
Robert Hensing
0b19468368 Merge pull request #13907 from obsidiansystems/store-building-unit-test
C API for building
2025-09-16 19:45:51 +02:00
John Ericson
9bc218ca3f Add new C API for working with derivations
Also test the APIs we just added.
2025-09-16 13:25:36 -04:00
Jens Petersen
ca23c819e0 nix-meson-build-support/common nix_soversion: fixup removal of 'pre'
.strip() removes individual chars whereas .replace() affects whole substring

Thanks @keszybz
2025-09-16 18:31:40 +08:00
Jörg Thalheim
1a69fc6ab5 Merge pull request #14001 from juhp/common-soversion
meson: refactor nix_soversion into nix-meson-build-support/common
2025-09-16 08:50:05 +02:00
Jens Petersen
86bb7c958a meson: refactor nix_soversion into nix-meson-build-support/common
This is a follow-on to #13995 which added soversion to the libraries
2025-09-16 12:54:30 +08:00
Jörg Thalheim
5e17a3f81c Merge pull request #13998 from Mic92/fast-flake-check
nix flake check: Skip substitutable derivations
2025-09-15 21:44:11 +02:00
Seth Flynn
ecdda5798c nix flake check: Skip substitutable derivations
Since `nix flake check` doesn't produce a `result` symlink, it doesn't
actually need to build/substitute derivations that are already known
to have succeeded, i.e. that are substitutable.

This can speed up CI jobs in cases where the derivations have already
been built by other jobs. For instance, a command like

  nix flake check github:NixOS/hydra/aa62c7f7db31753f0cde690f8654dd1907fc0ce2

should no longer build anything because the outputs are already in
cache.nixos.org.

Based-on: https://github.com/DeterminateSystems/nix-src/pull/134
Based-on: https://gerrit.lix.systems/c/lix/+/3841
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
2025-09-15 21:31:03 +02:00
Jörg Thalheim
0b401e2199 Merge pull request #13995 from juhp/soversion
meson: add soversion with nix version to give SONAME to libs
2025-09-15 20:36:31 +02:00
Eelco Dolstra
ad175727e4 Merge pull request #13938 from NixOS/import-thunk
Ensure that files are parsed/evaluated only once
2025-09-15 19:03:18 +02:00
John Ericson
d314750174 Merge pull request #13999 from obsidiansystems/more-get-improvements
More `get` / `getOr` improvements
2025-09-15 12:55:40 -04:00
John Ericson
f3e3f75838 More get / getOr improvements
- Use `const K`, not `K`, otherwise we don't get auto referencing of
  rvalues.

- Generalized the deleted overloads, because we don't care what the key
  type is --- we want to get rid of anything that has an rvalue map
  type.
2025-09-15 12:25:37 -04:00
Jens Petersen
dd1a554aba meson: add soversion with nix version to give SONAME to libs (#13960, #13979)
remove 'pre' version suffix for non-releases (chokes Darwin ld)
2025-09-15 22:08:26 +08:00
Sergei Zimmerman
2b0fd88324 Merge pull request #13991 from xokdvium/bindings-remove-find
libexpr: Remove Bindings::find
2025-09-14 21:32:31 +00:00
John Ericson
ffc14ac91b Merge pull request #13983 from xokdvium/bindings-fixes
libexpr: Make Bindings::iterator a proper strong type instead of pointer
2025-09-14 17:31:48 -04:00
Sergei Zimmerman
d830840433 libexpr: Remove Bindings::find
A follow-up optimization will make it impossible to make a find function
that returns an iterator in an efficient manner. All consumer code can
easily use the `get` variant.
2025-09-14 23:29:44 +03:00
Sergei Zimmerman
ddabd94f82 libexpr: Make Bindings::iterator a proper strong type instead of pointer
As evident from the number of tests that were holding this API completely
wrong (the end() iterator returned from find() is NEVER nullptr) we should
not have this footgun. A proper strong type guarantees that this confusion
will not happen again.

Also this will be helpful down the road when Bindings becomes something
smarter than an array of Attr.
2025-09-14 22:52:37 +03:00
Sergei Zimmerman
b974b7dc1e Merge pull request #13985 from dramforever/master 2025-09-14 11:19:10 +00:00
dramforever
7295034362 libstore: Raise default connect-timeout to 15 secs
This allows the weird network or DNS server fallback mechanism inside
glibc to work, and prevents a "Resolving timed out after 5000
milliseconds" error. Read on for details.

The DNS request stuff (dns-hosts) in glibc uses this fallback procedure
to minimize network RTT in the ideal case while dealing with
ill-behaving networks and DNS servers gracefully (see resolv.conf(5)):

- Use sendmmsg() to send UDP DNS requests for IPv4 and IPv6 in parallel
- If that times out (meaning that none or only one of the responses have
  been received), send the requests one by one, waiting for the response
  before sending the next request ("single-request")
- If that still times out, try to use a different socket (hence
  different address) for each request ("single-request-reopen")

The default timeout inside glibc is 5 seconds. Therefore, setting
connect-timeout, and therefore CURLOPT_CONNECTTIMEOUT to 5 seconds
prevents the single-request fallback, and setting it to even 10 seconds
prevents the single-request-reopen fallback as well.

The fallback decision is saved by glibc, but only thread-locally, and
libcurl starts a new thread for getaddrinfo() for each connection.
Therefore for every connection the fallback starts from sendmmsg() all
over again. And since these are considered to have timed out by libcurl,
even though getaddrinfo() might return a successful result, it is not
cached in libcurl.

While a user could tweak these with resolv.conf(5) options (e.g. using
networking.resolvconf.extraOptions in NixOS), and indeed that is
probably needed to avoid annoying delays, it still means that the
default connect-timeout of 5 is too low. Raise it to give fallback a
chance.
2025-09-14 08:48:29 +08:00
John Ericson
5bc96798b1 Merge pull request #13982 from obsidiansystems/path-info-static-function
`ValidPathInfo`, `NarInfo`, turn funky constructor into static method
2025-09-13 20:10:45 -04:00
Sergei Zimmerman
e75501da3e libexpr: Remove non-const iterators of Bindings 2025-09-13 23:21:24 +03:00
John Ericson
74be28820c ValidPathInfo, NarInfo, turn funky constructor into static method
This is more flexible, and needed for me to be able to reshuffle the
inheritance bureaucracy to make the JSON instances more precise.
2025-09-13 13:17:14 -04:00
Jörg Thalheim
465d627f7f Merge pull request #13978 from xokdvium/fix-warn
libutil: Fix missing return warning
2025-09-13 10:30:32 +02:00
Sergei Zimmerman
298ea97c12 libutil: Fix missing return warning
../hash.cc: In function 'nix::{anonymous}::DecodeNamePair nix::baseExplicit(HashFormat)':
../hash.cc:114:1: warning: control reaches end of non-void function [-Wreturn-type]
  114 | }
      | ^
2025-09-13 09:19:07 +03:00
John Ericson
1907a3300f Merge pull request #13811 from hgl/patch-2
doc: Rephrase store-object.md
2025-09-12 23:34:52 -04:00
John Ericson
1710fd09f3 Merge pull request #13975 from obsidiansystems/prep-json-0
Misc prep changes for #13942
2025-09-12 23:32:20 -04:00
Glen Huang
a0b633dd2b doc: Rephrase store-object.md 2025-09-13 10:17:12 +08:00
John Ericson
f78062d2fb Merge pull request #13976 from xokdvium/darwin-packaging
packaging: Drop legacy apple sdk pattern
2025-09-12 18:37:36 -04:00
Sergei Zimmerman
20b532eab0 packaging: Drop legacy apple sdk pattern
This has been dropped on unstable an nix no longer
compiled with overridden nixpkgs input. On 25.05 these
overrides already do nothing.

Tested with:

nix build .#packages.x86_64-darwin.nix-cli -L --override-input nixpkgs https://releases.nixos.org/nixos/unstable/nixos-25.11pre859555.ab0f3607a6c7/nixexprs.tar.xz

Default deployment target on 25.05 is 11.3, so 10.13
sdk override doesn't have to be updated at all as evident
from the fact that we didn't observe any issues with it.
2025-09-13 01:07:42 +03:00
John Ericson
095ac66d4c Introduce Hash::parseExplicitFormatUnprefixed 2025-09-12 18:04:29 -04:00
John Ericson
c6d06ce486 Fix hash error message
Wrong number of arguments was causing a format assertion.
2025-09-12 18:04:29 -04:00
John Ericson
c242706319 Move json_avoids_null to its own header
This is because we need it in declarations where we should not be
including the full `nlohmann/json.hpp`.

Already can clean up by moving the experimental feature "instance".

Also, make the `std::map` instance better by allowing for other
comparison functions.
2025-09-12 18:04:29 -04:00
Philip Wilk
aef431fbd1 bugfix/3514: do not throw on substituter errors if other substituters are still enabled (#13301)
## Motivation

Nix currently hard fails if a substituter is inaccessible, even when they are other substituters available, unless `fallback = true`. 
This breaks nix build, run, shell et al entirely. 
This would modify the default behaviour so that nix would actually use the other available substituters and not hard error.

Here is an example before vs after when using dotenv where I have manually stopped my own cache to trigger this issue, before and after the patch. The initial error is really frustrating because there is other caches available.
![image](https://github.com/user-attachments/assets/b4aec474-52d1-497d-b4e8-6f5737d6acc7)
![image](https://github.com/user-attachments/assets/ee91fcd4-4a1a-4c33-bf88-3aee67ad3cc9)

## Context

https://github.com/NixOS/nix/issues/3514#issuecomment-2905056198 is the earliest issue I could find, but there are many duplicates.

There is an initial PR at https://github.com/NixOS/nix/pull/7188, but this appears to have been abandoned - over 2 years with no activity, then a no comment review in jan. There was a subsequent PR at https://github.com/NixOS/nix/pull/8983 but this was closed without merge - over a year without activity.
<!-- Non-trivial change: Briefly outline the implementation strategy. -->
I have visualised the current and proposed flows. I believe my logic flows line up with what is suggested in https://github.com/NixOS/nix/pull/7188#issuecomment-1375652870 but correct me if I am wrong.
Current behaviour:
![current](https://github.com/user-attachments/assets/d9501b34-274c-4eb3-88c3-9021a482e364)
Proposed behaviour:
![proposed](https://github.com/user-attachments/assets/8236e4f4-21ef-45d7-87e1-6c8d416e8c1c)

[Charts in lucid](https://lucid.app/lucidchart/1b51b08d-6c4f-40e0-bf54-480df322cccf/view)
<!-- Invasive change: Discuss alternative designs or approaches you considered. -->

Possible issues to think about:
- I could not figure out where the curl error is created... I can't figure out how to swallow it and turn it into a warn or better yet, a debug log.
- Unfortunately, in contrast with the previous point, I'm not sure how verbose we want to warns/traces to be - personally I think that the warn that a substituter has been disabled (when it happens) is sufficient, and that the next one is being used, but this is personal preference.
2025-09-12 17:29:34 -04:00
Sergei Zimmerman
92df96543c Merge pull request #13972 from xokdvium/no-string-values-in-evalstate 2025-09-12 21:19:09 +00:00
Jörg Thalheim
5772c207d8 Merge pull request #13970 from xokdvium/no-soname
Revert "meson: add soversion to libraries (#13960)"
2025-09-12 23:17:17 +02:00
Sergei Zimmerman
f4c38278ca libexpr: Remove vString* Values from EvalState
EvalState is too big and cluttered. These strings
can be private constant statics.
2025-09-12 23:44:52 +03:00
Sergei Zimmerman
0db2b8c8fe Revert "meson: add soversion to libraries (#13960)"
This reverts commit bdbc739d6e.

Such a change needs more thought put into it. By versioning
shared libraries we'd make a false impression that libraries
themselves are actually versioned and have some sort of stable
ABI, which is not the case.

This will be useful when C bindings become stable, but as long
as they are experimental it does not make sense to set SONAME.

Also this change should not have been backported, since it's
severely breaking.
2025-09-12 20:43:34 +03:00
Eelco Dolstra
8d8f49cb5a Use concurrent_flat_map_fwd.hpp 2025-09-12 17:49:15 +02:00
Eelco Dolstra
4b63ff63a4 Remove some unnecessary hash template arguments 2025-09-12 17:26:29 +02:00
Eelco Dolstra
ad6eb22368 Ensure that files are parsed/evaluated only once
When doing multithreaded evaluation, we want to ensure that any Nix
file is parsed and evaluated only once. The easiest way to do this is
to rely on thunks, since those ensure locking in the multithreaded
evaluator. `fileEvalCache` is now a mapping from `SourcePath` to a
`Value *`. The value is initially a thunk (pointing to a
`ExprParseFile` helper object) that can be forced to parse and
evaluate the file. So a subsequent thread requesting the same file
will see a thunk that is possibly locked and wait for it.

The parser cache is gone since it's no longer needed. However, there
is a new `importResolutionCache` that maps `SourcePath`s to
`SourcePath`s (e.g. `/foo` to `/foo/default.nix`). Previously we put
multiple entries in `fileEvalCache`, which was ugly and could result
in work duplication.
2025-09-12 17:05:21 +02:00
Eelco Dolstra
47c16fc4bd SourcePath: Implement boost::hash 2025-09-12 17:05:21 +02:00
Eelco Dolstra
8fbf4b9427 CanonPath: Implement boost::hash 2025-09-12 17:05:21 +02:00
Eelco Dolstra
7f9b5226af Add getConcurrent helper function 2025-09-12 16:49:25 +02:00
Jörg Thalheim
377b60ee9b Merge pull request #13926 from NaN-git/opt_boost-unordered
replace all occurences of std::unordered_* by equivalents from boost
2025-09-12 11:46:42 +02:00
Jörg Thalheim
429812cdb8 Merge pull request #13966 from juhp/patch-1
meson: add soversion to libraries (#13960)
2025-09-12 08:25:12 +02:00
Jörg Thalheim
f6802a8ccf Merge pull request #13963 from xokdvium/fix-no-gc
libexpr: Fix build without Boehm
2025-09-12 08:23:19 +02:00
Jens Petersen
bdbc739d6e meson: add soversion to libraries (#13960) 2025-09-12 14:06:39 +08:00
Sergei Zimmerman
c0b35c71cd libexpr: Fix build without Boehm
This should have been placed under the ifdef.
2025-09-12 04:02:07 +03:00
Sergei Zimmerman
ef5fedbc0d Merge pull request #13936 from xokdvium/empty-list-bindings
libexpr: Make constant Values global constants, move out of EvalState
2025-09-10 23:12:20 +00:00
Sergei Zimmerman
5db4b0699c libexpr: Make constant Values global constants, move out of EvalState
These constant Values have no business being in the EvalState in the
first place. The ultimate goal is to get rid of the ugly `getBuiltins`
and its relience (in `createBaseEnv`) on these global constants is getting in the way.

Same idea as in f017f9ddd3.

Co-authored-by: eldritch horrors <pennae@lix.systems>
2025-09-11 01:53:41 +03:00
Sergei Zimmerman
462b9ac49c libexpr: Make Value::isa and Value::getStorage private methods
This was always intended to be the case, but accidentally left
in the public interface.
2025-09-11 01:52:17 +03:00
Sergei Zimmerman
4df1a3ca76 libexpr: Make emptyBindings a global constant
This object is always constant and will never get modified.
Having it as a global (constant) static is much easier and
unclutters the EvalState.

Same idea as in f017f9ddd3.

Co-authored-by: eldritch horrors <pennae@lix.systems>
2025-09-11 01:51:48 +03:00
Philipp Otterbein
9dbc2cae4f hashmaps with string keys: add transparent lookups 2025-09-10 23:04:44 +02:00
Philipp Otterbein
9f2b6a1b94 replace more std::unordered_* types by faster boost hash maps 2025-09-10 23:04:44 +02:00
Philipp Otterbein
4f8c50fb77 libexpr: replace std::unordered_* types by faster boost hash maps 2025-09-10 23:04:44 +02:00
John Ericson
c0fd9146d6 Move exportPaths() / importPaths() out of the Store class (#13959) 2025-09-10 15:39:20 -04:00
Eelco Dolstra
3898a7343a Merge pull request #13961 from NyCodeGHG/push-prlsssvmxwvl
meson: link to libatomic on powerpc-linux
2025-09-10 19:22:54 +02:00
Marie Ramlow
37eec84bc1 meson: link to libatomic on powerpc-linux
Like 32-bit Arm, 32-bit PowerPC also needs linking against libatomic
because it doesn't support some atomic instructions in hardware.
2025-09-10 18:50:35 +02:00
Eelco Dolstra
fe5b669534 Move exportPaths() / importPaths() out of the Store class 2025-09-10 14:22:46 +02:00
Jörg Thalheim
5e46df973f Merge pull request #13957 from NixOS/drop-old-serve-protocol
Remove support for serve protocol version < 5
2025-09-10 13:50:12 +02:00
Eelco Dolstra
9df99e0658 Remove ServeProto::Command::ExportPaths
This seems to have been unused since the build-remote.pl removal in February 2017 (27dc76c1a5).
2025-09-10 10:57:15 +02:00
Eelco Dolstra
fa048e4383 Remove support for serve protocol < 5
This was introduced in August 2018 (2825e05d21).
2025-09-10 10:57:15 +02:00
Jörg Thalheim
8c789db05b Merge pull request #13956 from NixOS/drop-unused-addMultipleToStoreLegacy
Drop unused LegacySSHStore::addMultipleToStoreLegacy()
2025-09-10 10:52:05 +02:00
Eelco Dolstra
f8b15bfc7f Merge pull request #13951 from NixOS/drop-old-daemon-protocol
Remove support for worker protocol version < 18
2025-09-10 10:43:48 +02:00
Eelco Dolstra
5013b38df4 Drop unused LegacySSHStore::addMultipleToStoreLegacy() 2025-09-10 10:27:07 +02:00
Eelco Dolstra
247d16a530 Merge pull request #13954 from xokdvium/empty-list-elems-fix
libexpr: Fix Value::mkList for empty lists
2025-09-10 10:23:49 +02:00
Eelco Dolstra
d1d3ed6241 Add release note 2025-09-10 10:20:37 +02:00
Jörg Thalheim
7d26bf8cc7 Merge pull request #13906 from obsidiansystems/derivation-builder-simpler
More `DerivationBuilder` simplifications
2025-09-10 09:58:07 +02:00
Jörg Thalheim
9c186c35fa Merge pull request #13932 from NixOS/move-pathInfoCache
Reduce false sharing between pathInfoCache and Store
2025-09-10 09:56:46 +02:00
Sergei Zimmerman
2ed2c79721 libexpr: Fix Value::mkList for empty lists
This code used to save the pointer to a small
list allocated on the stack to the Value, which
is unintended.
2025-09-10 01:37:39 +03:00
Sergei Zimmerman
3c331b7ef3 Merge pull request #13953 from xokdvium/value-alignment
libexpr: Overalign Value to 16 bytes
2025-09-09 20:44:43 +00:00
Sergei Zimmerman
4524235af4 libexpr: Overalign Value to 16 bytes
This is necessary to make use of 128 bit atomics on x86_64 [1],
since MOVAPD, MOVAPS, and MOVDQA need memory operands to be 16-byte
aligned. We are not losing anything here, because Value is already 16-byte
wide and Boehm allocates memory in granules that are 16 bytes by default
on 64 bit systems [2].

[1]: https://patchwork.sourceware.org/project/gcc/patch/YhxkfzGEEQ9KHbBC@tucnak/
[2]: 54ac18ccbc/include/gc/gc_tiny_fl.h (L31-L33)
2025-09-09 22:18:52 +03:00
Eelco Dolstra
86d19956f2 Remove WorkerProto::Op::ImportPaths
This was obsoleted in May 2016 (538a64e8c3).
2025-09-09 15:41:17 +02:00
Eelco Dolstra
4fb61bc5af Remove WorkerProto::Op::ExportPath
This was obsoleted in May 2016 (538a64e8c3).
2025-09-09 15:41:12 +02:00
Eelco Dolstra
137a55122c Remove support for daemon protocol version < 18
Version 18 was introduced in November 2016 (4b8f1b0ec0).
2025-09-09 15:41:01 +02:00
Eelco Dolstra
7658f00bb1 Merge pull request #13941 from NixOS/dependabot/github_actions/actions/labeler-6
build(deps): bump actions/labeler from 5 to 6
2025-09-09 09:37:08 +02:00
Eelco Dolstra
a97c5df47c Merge pull request #13939 from DeterminateSystems/fix-inputs-from-ignoring-dir-param-upstreaming
Pass `dir` in extraAttrs when overriding the registry
2025-09-09 09:36:33 +02:00
Sergei Zimmerman
371623bf0c Merge pull request #13940 from xokdvium/unbracketed-ipv6
libstore: Reallow unbracketed IPv6 addresses in store references
2025-09-08 23:21:34 +00:00
dependabot[bot]
7128abd217 build(deps): bump actions/labeler from 5 to 6
Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 22:00:58 +00:00
Sergei Zimmerman
7cc654afa9 libstore: Reallow unbracketed IPv6 addresses in store references
This implements a special back-compat shim to specifically allow
unbracketed IPv6 addresses in store references. This is something
that is relied upon in the wild and the old parsing logic accepted
both ways (brackets were optional). This patch restores this behavior.
As always, we didn't have any tests for this.

Addresses #13937.
2025-09-09 00:41:03 +03:00
Cole Helbling
38663fb434 Pass dir in extraAttrs when overriding the registry
This is handled similarly in the handler for `--override-flake` in
`MixEvalArgs`.
2025-09-08 09:00:59 +02:00
Cole Helbling
ed6ef7cdf4 Test that using --inputs-from with a flakeref that has a dir works
Will not pass until the next commit.
2025-09-08 09:00:59 +02:00
Eelco Dolstra
12db0726e9 Merge pull request #13934 from DeterminateSystems/fix-flake-registry-ignoring-dir-param-upstreaming
Fix flake registry ignoring `dir` parameter
2025-09-08 07:50:54 +02:00
Eelco Dolstra
525245181a Merge pull request #13933 from NixOS/local-store-state
LocalStore::State: Put behind a ref to reduce false sharing
2025-09-08 06:22:04 +02:00
Eelco Dolstra
9302ec5e0e Add comment 2025-09-08 05:57:02 +02:00
Cole Helbling
9c832a08b0 fixup: cached case
I couldn't come up with a test that failed before this, but my existing
test still passes so 🤷
2025-09-07 19:40:24 +02:00
Cole Helbling
bccdb95a86 Fix flake registry ignoring dir parameter
This broke in e3042f10af.
2025-09-07 19:40:24 +02:00
Cole Helbling
258d41bfb6 Test that dir is propagated from registry entry 2025-09-07 19:40:23 +02:00
Tom Westerhout
dbc235cc62 Generalize recognized git url schemas (#13925)
Use `parseUrlScheme` instead of manually parsing `url.scheme`.
2025-09-07 15:22:20 +02:00
Eelco Dolstra
df9b3bfba8 Merge pull request #13845 from NixOS/nix-flake-check-build-test
Add a test for `nix flake check` building checks
2025-09-07 14:53:19 +02:00
Eelco Dolstra
14c001d613 Add a test for nix flake check building checks 2025-09-07 14:41:40 +02:00
Eelco Dolstra
e791ede495 LocalStore::State: Put behind a ref to reduce false sharing 2025-09-07 14:32:24 +02:00
Eelco Dolstra
a73cf447ac Reduce false sharing between pathInfoCache and Store
`perf c2c` shows a lot of cacheline conflicts between purely read-only
Store methods (like `parseStorePath()`) and the Sync classes. So
allocate pathInfoCache separately to avoid that.
2025-09-07 14:27:38 +02:00
Eelco Dolstra
9ff427d7ba Merge pull request #13911 from xokdvium/store-uri-daemon-local
libstore: Do not normalize daemon -> unix://, local -> local://
2025-09-07 14:10:45 +02:00
Eelco Dolstra
4dd27a292c Merge pull request #13929 from NixOS/remove-unused
Remove unused function setChildSignalMask()
2025-09-07 13:30:09 +02:00
Jörg Thalheim
5ae1b5f88b Merge pull request #13916 from sinanmohd/fix/develop-interactive-shell
nix/develop: pass down the interactive shell to subshells
2025-09-07 10:14:25 +02:00
Eelco Dolstra
a7c6a42344 Merge pull request #13923 from NixOS/fix-multithreaded-chroot-hang
Fix hang in enterChroot() draining userNamespaceSync
2025-09-07 09:13:54 +02:00
Eelco Dolstra
f363d958a7 Fix hang in enterChroot() draining userNamespaceSync
Calling `drainFD()` will hang if another process has the write side
open, since then the child won't get an EOF. This can happen if we
have multiple threads doing a build, since in that case another thread
may fork a child process that inherits the write side of the first
thread.

We could set O_CLOEXEC on the write side (using pipe2()) but it won't
help here since we don't always do an exec() in the child, e.g. in the
case of builtin builders. (We need a "close-on-fork", not a
"close-on-exec".)
2025-09-07 01:12:44 +02:00
Eelco Dolstra
a44dcbff13 Remove unused function setChildSignalMask() 2025-09-06 23:02:57 +02:00
John Ericson
12b6d8d208 Merge pull request #13924 from xokdvium/dead-code
libexpr: Remove decl for undefined overload of Value::mkPath
2025-09-06 10:47:26 -04:00
Sergei Zimmerman
bbdabe4973 libexpr: Remove decl for undefined overload of Value::mkPath 2025-09-06 16:36:16 +03:00
Jörg Thalheim
1d62ccdb3d Merge pull request #13767 from ethanavatar/master
libutil, libexpr: #10542 abstract over getrusage for getting cpuTime stat and implement windows version
2025-09-06 09:26:13 +02:00
Jörg Thalheim
533c6d38aa Merge pull request #13901 from Mic92/fix-macos-hup-detection
Fix macOS HUP detection using kqueue instead of poll
2025-09-06 09:19:51 +02:00
Jörg Thalheim
dbc8d0ab64 Merge pull request #13919 from xokdvium/smaller-bindings
libexpr: Slim down Bindings to 8 bytes (on 64 bit systems)
2025-09-06 09:11:48 +02:00
Sergei Zimmerman
738924b705 libexpr: Slim down Bindings to 8 bytes (on 64 bit systems)
Since the only construction and push_back() calls
to Bindings happen through the `BindingsBuilder` [1] we don't
need to keep `capacity` around on the heap anymore. This saves 8 bytes
(because of the member alignment padding)
per one Bindings allocation. This isn't that much, but it does
save significant memory.

This also shows that the Bindings don't necessarily have to
be mutable, which opens up opportunities for doing small bindings
optimization and storing a 1-element Bindings directly in Value.

For the following scenario:

nix-env --query --available --out-path --file ../nixpkgs --eval-system x86_64-linux

(nixpkgs revision: ddcddd7b09a417ca9a88899f4bd43a8edb72308d)

This patch results in reduction of `sets.bytes` 13115104016 -> 12653087640,
which amounts to 462 MB less bytes allocated for Bindings.

[1]: Not actually, `getBuiltins` does mutate bindings, but this is pretty
     inconsequential and doesn't lead to problems.
2025-09-06 00:23:54 +03:00
sinanmohd
211cbe4abf nix/develop: pass down the interactive shell to subshells 2025-09-05 20:18:25 +05:30
Sergei Zimmerman
3513ab13dc libstore: Do not normalize daemon -> unix://, local -> local://
This is relied upon (specifically the `local` store) by existing
tooling [1] and we broke this in 3e7879e6df (which
was first released in 2.31).

To lessen the scope of the breakage we should not normalize "auto" references
and explicitly specified references like "local" or "daemon". It also makes
sense to canonicalize local://,daemon:// to be more compatible with prior
behavior.

[1]: 05e1b3cba2/lib/NOM/Builds.hs (L60-L64)
2025-09-05 04:14:36 +03:00
John Ericson
49e9c14e2f Merge pull request #13900 from NixOS/fix-mingw-windows-build
Fix downstream MinGW build by not looking for Boost Regex
2025-09-04 21:05:12 -04:00
John Ericson
25d3c197b8 Merge pull request #13902 from NixOS/ssh-master-deadlock
Fix deadlock in SSHMaster::addCommonSSHOpts()
2025-09-03 21:44:06 -04:00
John Ericson
2acb9559d5 Combine DerivationBuilder::{prepareBuild,startBuilder}
After many other cleanups, it turns out there is no reason for these to
be separate methods. We can combine them to simplify things.
2025-09-03 17:58:50 -04:00
John Ericson
14c206f05a DerivationBuilder no more callback soup for logging
`startBuilder` just returns the descriptor for the pipe now.
2025-09-03 17:34:45 -04:00
John Ericson
7f3314a68c DerivationBuilder::initialOutputs make const
At one point I remember it did mutatate `initialOutputs`, but not
anymore!
2025-09-03 17:34:45 -04:00
John Ericson
b69576e2b3 Merge pull request #13905 from obsidiansystems/derivation-building-goal-simplify-0
Derivation building goal simplify -- no `goto`
2025-09-03 17:34:27 -04:00
John Ericson
7b22cd5105 Merge pull request #13839 from Mic92/infra
don't include derivation name in temporary build directories
2025-09-03 17:15:03 -04:00
Jörg Thalheim
1732b4a61b Merge pull request #13885 from netadr/fix-ssh-key-ids
libfetchers: Fix SSH key types for sk type keys
2025-09-03 23:13:48 +02:00
John Ericson
819bf13607 Merge pull request #13880 from Mic92/static-alloc-symbol-ids
libexpr: Convert Symbol comparisons to switch statements
2025-09-03 17:13:12 -04:00
Jörg Thalheim
81e068ab8a Merge pull request #13904 from NixOS/c-ffi-improvements
C ffi improvements
2025-09-03 23:10:27 +02:00
John Ericson
a30bf96349 DerivationBuildingGoal::initialOutputs make local variable
Also inline `assertPathValidity` in the process.
2025-09-03 17:04:13 -04:00
John Ericson
c0c2a89f05 DerivationBuildingGoal::initialOutputs move initialization down to tryToBuild
Will help us make this a local variable.
2025-09-03 17:04:08 -04:00
John Ericson
450633aa8c Move machineName from DerivationBuildingGoal to HookInstance
Exactly why is is correct is a little subtle, because sometimes the
worker is owned by the worker. But the commit message in
e437b08250 explained the situation well
enough: I made that commit message part of the ABI docs, and now it
should be understandable to the next person.
2025-09-03 17:03:56 -04:00
netadr
671c21db9f libfetchers: Fix SSH key identifiers for sk type keys
libfetchers: Mark ssh-ecdsa-sk key type mapping as a TODO for now
2025-09-03 22:56:33 +02:00
John Ericson
8089102164 Separate internal from non-internal unit tests of the C API
This helps us make sure that the external C API is sufficient for the
tasks that we think it is sufficient for.
2025-09-03 22:50:42 +02:00
John Ericson
f6bc47bc50 nix_store_realise: Improve typing of store path
Use `StorePath *` not `const char *`.
2025-09-03 22:50:42 +02:00
John Ericson
fa76b6e215 nix store benchmarks: Only get unit test dir from env var 2025-09-03 22:50:42 +02:00
John Ericson
44d096f68d nix_store_is_valid_path param path should be const 2025-09-03 22:50:42 +02:00
John Ericson
7e4608a3f8 More extern "C" for FFI
This allows us to catch the header and file getting out of sync, because
we are not doing overloading by mistake.
2025-09-03 22:50:42 +02:00
John Ericson
eb56b181ae DerivationBuildingGoal: Make almost everything private 2025-09-03 16:25:12 -04:00
John Ericson
c6ba120000 DerivationBuildingGoal::started make local (lambda) variable 2025-09-03 16:19:35 -04:00
John Ericson
3b9c510ab1 DerivationBuildingGoal::outputLocks make local variable 2025-09-03 16:19:35 -04:00
John Ericson
a63ac8d98b Inline DerivationBuildingGoal::hookDone 2025-09-03 16:19:35 -04:00
John Ericson
51dadaded4 Move up assert(!hook);
We don't need to keep doing this every loop iteration, hook stuff it is only set
above.
2025-09-03 16:19:35 -04:00
John Ericson
7c1e5b3345 In DerivationBuildingGoal Demote actLock to local variable
It doesn't need to be a field any more, because we just use it with two
loops.
2025-09-03 16:19:35 -04:00
John Ericson
4c44a213a3 Get rid of a tryToBuild tail recursive call with loop
This will make it easier to convert somethings to RAII.
2025-09-03 16:19:35 -04:00
John Ericson
95c5779880 DerivationBuildingGoal::tryToBuild pull hook waiting out of switch
Do this with a new `useHook` boolean we carefully make sure is set in
all cases. This change isn't really worthwhile by itself, but it allows
us to make further refactors (see later commits) which are
well-motivated.
2025-09-03 16:19:35 -04:00
Eelco Dolstra
c7603c61c8 Mark tmpDir as const 2025-09-03 20:17:42 +02:00
Eelco Dolstra
2fe629c5d4 Fix deadlock in SSHMaster::addCommonSSHOpts()
When useMaster is true, startMaster() acquires the state lock, then
calls isMasterRunning(), which calls addCommonSSHOpts(), which tries
to acquire the state lock again, causing a deadlock.

The solution is to move tmpDir out of the state. It doesn't need to be
there in the first place because it never changes.
2025-09-03 17:49:24 +02:00
Jörg Thalheim
1286d5db78 Fix macOS HUP detection using kqueue instead of poll
On macOS, poll() is fundamentally broken for HUP detection. It loses event
subscriptions when EVFILT_READ fires without matching the requested events
in the pollfd. This causes daemon processes to linger after client disconnect.

This commit replaces poll() with kqueue on macOS, which is what poll()
uses internally but without the bugs. The kqueue implementation uses
EVFILT_READ which works for both sockets and pipes, avoiding EVFILT_SOCK
which only works for sockets.

On Linux and other platforms, we continue using poll() with the standard
POSIX behavior where POLLHUP is always reported regardless of requested events.

Based on work from the Lix project (https://git.lix.systems/lix-project/lix)
commit 69ba3c92db3ecca468bcd5ff7849fa8e8e0fc6c0

Fixes: https://github.com/NixOS/nix/issues/13847
Related: https://git.lix.systems/lix-project/lix/issues/729
Apple bugs: rdar://37537852 (poll), FB17447257 (poll)

Co-authored-by: Jade Lovelace <jadel@mercury.com>
2025-09-03 11:33:23 +02:00
Jörg Thalheim
cbcb434cb3 libexpr: Convert Symbol comparisons to switch statements
Now that Symbols are statically allocated at compile time with known IDs,
we can use switch statements instead of if-else chains for Symbol comparisons.
This provides better performance through compiler optimizations like jump tables.

Changes:
- Add public getId() method to Symbol class to access the internal ID
- Convert if-else chains comparing Symbol values to switch statements
  in primops.cc's derivationStrictInternal function
- Simplify control flow by removing the 'handled' flag and moving the
  default attribute handling into the switch's default case

The static and runtime Symbol IDs are guaranteed to match by the
copyIntoSymbolTable implementation which asserts this invariant.

Co-authored-by: John Ericson <git@JohnEricson.me>
2025-09-03 10:13:12 +02:00
Sergei Zimmerman
1935c19705 Merge pull request #13890 from xokdvium/mkstring-no-copy
Re-introduce mkStringNoCopy (revised)
2025-09-02 17:13:17 +00:00
John Ericson
6bdb5e8e09 Fix downstream MinGW build by not looking for Boost Regex 2025-09-02 10:41:39 -04:00
John Ericson
b806440808 Merge pull request #13894 from NixOS/more-url-testing
More URL testing
2025-09-02 00:10:13 -04:00
John Ericson
7f91e91876 More URL testing
More parameterized tests, we can have more coverage.
2025-09-01 18:26:21 -04:00
John Ericson
ab095c029c Merge pull request #13891 from NixOS/another-url-test
Add another `fixGitURL` test
2025-09-01 17:36:18 -04:00
John Ericson
7195250fc4 Add another fixGitURL test
Also improve a similar `parseURL` test.
2025-09-01 17:19:26 -04:00
Sergei Zimmerman
34181afc6a libexpr: Use mkStringNoCopy in prim_typeOf
This would lead to an unnecessary allocation. Not
a significant issue by any means, but it doesn't
have to allocate for most cases.
2025-09-02 00:16:11 +03:00
Eelco Dolstra
d62cfc1c97 Re-introduce mkStringNoCopy (revised)
In b70d22b `mkStringNoCopy()` was renamed to
`mkString()`, but this is a bit risky since in code like

    vStringRegular.mkString("regular");

we want to be sure that the right overload is picked. (This is
especially problematic since the overload that takes an
`std::string_view` *does* allocate.)  So let's be explicit.

(Rebased from https://github.com/NixOS/nix/pull/11551)
2025-09-02 00:16:06 +03:00
John Ericson
3a19ea96d9 Merge pull request #13888 from NixOS/old-busted-git-url-with-tests
Old busted git url with tests
2025-09-01 16:46:01 -04:00
Farid Zakaria
2b310aee13 A few more URL tests
Adapted from commit 04ad66af5f
2025-09-01 16:31:45 -04:00
John Ericson
d2f1860ee5 Revert "Improve Git URI handling"
I (@Ericson2314) messed up. We were supposed to test the status quo
before landing any new chnages, and also there is one change that is not
quite right (relative paths).

I am reverting for now, and then backporting the test suite to the old
situation.

This reverts commit 04ad66af5f.
2025-09-01 16:13:32 -04:00
Jörg Thalheim
a0ce514769 Merge pull request #13866 from obsidiansystems/more-derivation-builder-cleanup
Even more `DerivationBuilder` cleanup
2025-09-01 20:35:16 +02:00
Jörg Thalheim
0d300112fa Merge pull request #13862 from obsidiansystems/build-failure-content-vs-presentation
Properly separater builder failure content and presentation
2025-09-01 20:25:50 +02:00
Jörg Thalheim
de7f137f31 Merge pull request #13860 from obsidiansystems/derivation-building-resources-code-cleanup
Derivation building resources code cleanup
2025-09-01 20:22:30 +02:00
John Ericson
7fde4f7d6f Merge pull request #13821 from fzakaria/fzakaria/improve-fixgiturl
Improve Git URI handling
2025-09-01 14:15:17 -04:00
Jörg Thalheim
dc29cdf66d Merge pull request #13858 from obsidiansystems/no-more-defered-exception
Get rid of `delayedException` in `DerivationBuilder`
2025-09-01 20:11:51 +02:00
Jörg Thalheim
3e0fb3f8d2 Merge pull request #13881 from xokdvium/pass-url-verbatim
lib{store,fetchers}: Pass URLs specified directly verbatim to FileTra…
2025-09-01 20:06:50 +02:00
Farid Zakaria
04ad66af5f Improve Git URI handling
Git URI can also support scp style links similar to git itself.

This change augments the function fixGitURL to better handle the scp
style urls through a minimal parser rather than regex which has been
found to be brittle.

* Support for IPV6 added
* New test cases added for fixGitURL
* Clearer documentation on purpose and goal of function
* More `std::string_view` for performance
* A few more URL tests

Fixes #5958
2025-09-01 14:04:04 -04:00
Jörg Thalheim
fea4a29c0a Merge pull request #13883 from xokdvium/toml-timestamps-reapply
Reapply "Merge pull request #13741 from xokdvium/toml-timestamps"
2025-09-01 09:12:33 +02:00
Sergei Zimmerman
e548700010 lib{store,fetchers}: Pass URLs specified directly verbatim to FileTransferRequest
The URL should not be normalized before handing it off to cURL, because
builtin fetchers like fetchTarball/fetchurl are expected to work with
arbitrary URLs, that might not be RFC3986 compliant. For those cases
Nix should not normalize URLs, though validation is fine. ParseURL and
cURL are supposed to match the set of acceptable URLs, since they implement
the same RFC.
2025-09-01 02:22:23 +03:00
Emily
acd627fa46 tests/functional/lang: Add tests for builtins.fromTOML overflow
This adds regression tests for fromTOML overflow/underflow behavior.
Previous versions of toml11 used to saturate, but this was never an
intended behavior (and Snix/Nix 2.3/toml11 >= 4.0 validate this).

(cherry picked from Lix [1,2])

[1]: 7ee442079d
[2]: 4de09b6b54
2025-09-01 01:49:15 +03:00
Sergei Zimmerman
8251305aff Reapply "Merge pull request #13741 from xokdvium/toml-timestamps"
This reverts commit 75740fbd75.
2025-09-01 01:26:14 +03:00
Jörg Thalheim
73cdfe7066 Merge pull request #13878 from urbas/hacking-instructions
hacking.md: set installation outputs as well
2025-08-31 13:58:36 +02:00
Jörg Thalheim
1f7d43e5bd Merge pull request #13879 from xokdvium/static-alloc-symbol-ids
libexpr: Statically allocate commonly used symbols
2025-08-31 13:40:55 +02:00
Sergei Zimmerman
363620dd24 libexpr: Statically allocate commonly used symbols
The motivation for this change is two-fold:

1. Commonly used Symbol values can be referred to
   quite often and they can be assigned at compile-time
   rather than runtime.

2. This also unclutters EvalState constructor, which was
   getting very long and unreadable.

Spiritually similar to https://gerrit.lix.systems/c/lix/+/2218,
though that patch doesn't allocate the Symbol at compile time.

Co-authored-by: eldritch horrors <pennae@lix.systems>
2025-08-31 13:24:06 +02:00
Matej Urbas
112f311c50 hacking.md: set installation outputs as well 2025-08-31 09:53:14 +01:00
John Ericson
2746985d90 Merge pull request #13877 from xokdvium/opt-print-string
libstore: Get rid of allocations in printString, allocate 2K bytes on the stack
2025-08-31 00:42:18 -04:00
Sergei Zimmerman
e1c9bc0ef6 libstore: Get rid of allocations in printString, allocate 2K bytes on the stack
Looking at perf:

   0.21 │       push   %rbp
   0.99 │       mov    %rsp,%rbp
        │       push   %r15
   0.25 │       push   %r14
        │       push   %r13
   0.49 │       push   %r12
   0.66 │       push   %rbx
   1.23 │       lea    -0x10000(%rsp),%r11
   0.23 │ 15:   sub    $0x1000,%rsp
   1.01 │       orq    $0x0,(%rsp)
  59.12 │       cmp    %r11,%rsp
   0.27 │     ↑ jne    15

Seems like 64K is too much to have on the stack for each invocation, considering
that only a minuscule number of allocations are actually larger than 4K.

There's actually no good reason this function should use so much stack space. Or
use small_string at all. Everything can be done in small chunks that don't require
any memory allocations and use up 2K bytes on the stack.

This patch also adds a microbenchmark for tracking the unparsing performance. Here
are the results for this change:

(Before)

BM_UnparseRealDerivationFile/hello         7275 ns         7247 ns        96093 bytes_per_second=232.136Mi/s
BM_UnparseRealDerivationFile/firefox      40538 ns        40376 ns        17327 bytes_per_second=378.534Mi/s

(After)

BM_UnparseRealDerivationFile/hello         3228 ns         3218 ns       215671 bytes_per_second=522.775Mi/s
BM_UnparseRealDerivationFile/firefox      39724 ns        39584 ns        17617 bytes_per_second=386.101Mi/s

This translates into nice evaluation performance improvements (compared to 18c3d2348f):

Benchmark 1: GC_INITIAL_HEAP_SIZE=8G old-nix/bin/nix-instantiate ../nixpkgs -A nixosTests.gnome --readonly-mode
  Time (mean ± σ):      3.111 s ±  0.021 s    [User: 2.513 s, System: 0.580 s]
  Range (min … max):    3.083 s …  3.143 s    10 runs

Benchmark 2: GC_INITIAL_HEAP_SIZE=8G result/bin/nix-instantiate ../nixpkgs -A nixosTests.gnome --readonly-mode
  Time (mean ± σ):      3.037 s ±  0.038 s    [User: 2.461 s, System: 0.558 s]
  Range (min … max):    2.960 s …  3.086 s    10 runs
2025-08-31 00:48:37 +03:00
John Ericson
18c3d2348f Merge pull request #13875 from xokdvium/restore-weird-flakeref-path
libfetchers: Restore path separator ignoring behavior for indirect an…
2025-08-30 11:17:42 -04:00
Sergei Zimmerman
a38ebdd511 libfetchers: Restore path separator ignoring behavior for indirect and git-archive flakerefs
Old versions of nix happily accepted a lot of weird flake references,
which we didn't have tests for, so this was accidentally broken in
c436b7a32a.

This patch restores previous behavior and adds a plethora of tests
to ensure we don't break this in the future.

These test cases are aligned with how 2.18/2.28 parsed flake references.
2025-08-30 14:40:56 +03:00
John Ericson
401e7fe3ad Merge pull request #13873 from xokdvium/fix-mingw
libfetchers: Fix mingw build
2025-08-29 19:56:20 -04:00
Sergei Zimmerman
b88a22504f libfetchers: Fix mingw build 2025-08-30 02:36:16 +03:00
John Ericson
511d885d60 Merge pull request #13872 from xokdvium/fix-indirect-flake-refs
libflake: Fix flake id flake refs with revisions
2025-08-29 18:51:25 -04:00
Sergei Zimmerman
3ef3f525c3 libflake: Fix flake id flake refs with revisions
Starting from c436b7a32a
this used to lead to assertion failures like:

> std::string nix::ParsedURL::renderAuthorityAndPath() const: Assertion `path.empty() || path.front().empty()' failed.

This has the bugfix for the issue and regressions tests
so that this gets properly tested in the future.
2025-08-30 01:26:51 +03:00
John Ericson
53a7d87b93 Merge pull request #13871 from obsidiansystems/fix-refactor-bug
`DerivationBuildingGoal::done*` restore `outputLocks.unlock()`
2025-08-29 18:25:43 -04:00
John Ericson
a8c4cfae26 DerivationBuildingGoal::done* restore outputLocks.unlock()
This was accidentally removed in
169033001d.
2025-08-29 17:49:11 -04:00
John Ericson
d50d4b01c7 Merge pull request #13867 from xokdvium/fix-13482
nix/develop: Fix misleading ignored error when run with --arg/--argstr
2025-08-29 17:17:25 -04:00
Sergei Zimmerman
b6f98b52a4 nix/develop: Fix misleading ignored error when run with --arg/--argstr
This would print erroneous and misleading diagnostics like:

> error (ignored): error: '--arg' and '--argstr' are incompatible with flakes

When run with --expr/--file. Since this installable is used to get the
bash package it doesn't make sense to check this.
2025-08-30 00:03:54 +03:00
John Ericson
d7ed86ceb1 Move deleting redirected outputs in to cleanupBuild
It is only done in the `force = true` case, and the only
`cleanupBuild(true)` call is right after where it used to be, so this
has the exact same behavior as before.
2025-08-29 16:10:25 -04:00
John Ericson
76125f8eb1 Get rid of Finally in DerivationBuilderImpl::unprepareBuild
Calling `reset` on this `std::optional` field of `DerivationBuilderImpl`
is also what the (automatically created) destructor of
`DerivationBuilderImpl` will do. We should be making sure that the
derivation builder is cleaned up by the goal anyways, and if we do that,
then this `Finally` is no longer needed.
2025-08-29 13:22:36 -04:00
Jörg Thalheim
0d006aedd6 Merge pull request #13854 from obsidiansystems/register-outputs-slight-simplify
Simplify handling of statuses for build errors
2025-08-29 07:20:55 +02:00
Jörg Thalheim
04d2122de2 Merge pull request #13861 from xokdvium/terminate-for-unreachable
libutil: Try to call std::terminate for panic, use C++20 std::source_location
2025-08-29 07:15:49 +02:00
John Ericson
8825bfa7fe Properly separater builer failure content and presentation
Before, had a very ugly `appendLogTailErrorMsg` callback. Now, we
instead have a `fixupBuilderFailureErrorMessage` that is just used by
`DerivationBuildingGoal`, and `DerivationBuilder` just returns the raw
data needed by this.
2025-08-28 22:17:15 -04:00
Sergei Zimmerman
d59b959c87 libutil: Use std::source_location for unreachable
Make unreachable a function instead of a macro, since
C++20 provides a convenience class as a replacement for
older __FILE__, __LINE__ macros.
2025-08-29 00:21:07 +03:00
John Ericson
47cae1f72b Merge pull request #13850 from obsidiansystems/factor-out-drv-env-desugar
Factor out a new `DesugaredEnv` from `DerivationBuildingGoal`
2025-08-28 17:10:48 -04:00
Sergei Zimmerman
1f607b5def libutil: Try to call std::terminate for panic
We now have a terminate handler that prints a
stack trace, which is useful to have when encountering
an unreachable.
2025-08-29 00:02:13 +03:00
John Ericson
53c31c8b29 Factor out a new DesugaredEnv from DerivationBuildingGoal
Now we have better separation of the core logic --- an integral part of
the store layer spec even --- from the goal mechanism and other
minutiae.

Co-authored-by: Jeremy Kolb <kjeremy@gmail.com>
2025-08-28 16:45:45 -04:00
Sergei Zimmerman
731349639f Merge pull request #13524 from gmarti/fix_cacertificate
Add /etc/ssl/certs/ca-certificates.crt in docker.nix
2025-08-28 23:28:53 +03:00
John Ericson
f019f1b75a Merge pull request #13838 from NixOS/parse-url-path
Fix `ParsedURL` handling of `%2F` in URL paths
2025-08-28 16:07:25 -04:00
Jörg Thalheim
c436b7a32a Fix ParsedURL handling of %2F in URL paths
See the new extensive doxygen in `url.hh`.
This fixes fetching gitlab: flakes.

Paths are now stored as a std::vector of individual path
segments, which can themselves contain path separators '/' (%2F).
This is necessary to make the Gitlab's /projects/ API work.

Co-authored-by: John Ericson <John.Ericson@Obsidian.Systems>
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-08-28 22:20:04 +03:00
Sergei Zimmerman
6839f3de55 libutil-tests: Add more URL tests 2025-08-28 14:58:17 -04:00
John Ericson
3e0b1705c1 Move markContentsGood to after DerivationBuilder finishes
I think this should be fine for repairing. If anything, it is better,
because it would be weird to "mark and output good" only for it to then
fail output checks.
2025-08-28 14:54:11 -04:00
Bernardo Meurer Costa
f193bca595 feat(libstore): warn when kvm is enabled but /dev/kvm isn't available 2025-08-28 18:44:28 +00:00
Sergei Zimmerman
c2782d7b84 Merge pull request #13853 from obsidiansystems/no-old-debugging-aid
Revert "Add a crude tracing mechansim for the build results"
2025-08-28 21:18:10 +03:00
John Ericson
bde745cb3f Move killChild call from ~DerivationBuildingGoal to ~DerivationBuilder
Sadly we cannot unexpose `DerivationBuilder::killChild` yet, because
`DerivationBuildingGoal` calls it elsewhere, but we can at least haave a
better division of labor between the two destructors.
2025-08-28 14:01:24 -04:00
John Ericson
c632c823ce Take DerivationBuilder::pid private 2025-08-28 14:01:20 -04:00
John Ericson
4388e3dcb5 Create DerivationBuilder::killChild
Then the derivation building goal doesn't need to snoop around as much.
2025-08-28 14:01:17 -04:00
John Ericson
49da508f46 Write a destructor for DerivationBuilderImpl
This allows `DerivationBuildingGoal` to know less.
2025-08-28 14:01:14 -04:00
John Ericson
557bbe969e Combine cleanupBuild and deleteTmpDir
It's hard to tell if I changed any behavior, but if I did, I think I
made it better, because now we explicitly move stuff out of the chroot
(if we were going to) before trying to delete the chroot.
2025-08-28 14:01:11 -04:00
John Ericson
4db6bf96b7 Give DerivationBuilderImpl::cleanupBuild bool arg
Do this to match `DerivationBuilder::deleteTmpDir`, which we'll want to
combine it with next.

Also chenge one caller from `deleteTmpDir(true)` to `cleanupBuild(true)`
now that this is done, because it will not make a difference.

This should be a pure refactor with no behavioral change.
2025-08-28 14:01:08 -04:00
John Ericson
8dd289099c Simplify DerivationGoal::unprepareBuild::diskFull
We only need it defined in the narrower scope
2025-08-28 14:01:05 -04:00
John Ericson
374f8e79a1 DerivationBuilderImpl::unprepareBuild Just throw error
Aftet the previous simplifications, there is no reason to catch the
error and immediately return it with a `std::variant` --- just let the
caller catch it instead.
2025-08-28 14:00:35 -04:00
John Ericson
0b85b023d8 Get rid of delayedException in DerivationBuilder
Instead of that funny business, the fixed output checks are not put in
`checkOutputs`, with the other (newer) output checks, where they also
better belong. The control flow is reworked (with comments!) so that
`checkOutputs` also runs in the `bmCheck` case.

Not only does this preserve existing behavior of `bmCheck`
double-checking fixed output hashes with less tricky code, it also makes
`bmCheck` better by also double-checking the other output checks, rather
than just assuming they pass if the derivation is deterministic.
2025-08-28 11:44:18 -04:00
John Ericson
ff961fd9e2 Get rid of DerivationBuilder::note*Mismatch
It's fine to set these worker flags a little later in the control flow,
since we'll be sure to reach those points in the error cases. And doing
that is much nicer than having these tangled callbacks.

I originally made the callbacks to meticulously recreate the exact
behavior which I didn't quite understand. Now, thanks to cleaning up the
error handling, I do understand what is going on, so I can be confident
that this change is safe to make.
2025-08-28 11:44:18 -04:00
Sergei Zimmerman
2eacb3c36f Merge pull request #13851 from lovesegfault/http-binary-cache-store-once
refactor(libstore/http-binary-cache-store): pragma once
2025-08-28 03:44:17 +03:00
John Ericson
169033001d Simplify handling of statuses for build errors
Instead of passing them around separately, or doing finicky logic in a
try-catch block to recover them, just make `BuildError` always contain a
status, and make it the thrower's responsibility to set it. This is much
more simple and explicit.

Once that change is done, split the `done` functions of `DerivationGoal`
and `DerivationBuildingGoal` into separate success and failure
functions, which ends up being easier to understand and hardly any
duplication.

Also, change the handling of failures in resolved cases to use
`BuildResult::DependencyFailed` and a new message. This is because the
underlying derivation will also get its message printed --- which is
good, because in general the resolved derivation is not unique. One dyn
drv test had to be updated, but CA (and dyn drv) is experimental, so I
do not mind.

Finally, delete `SubstError` because it is unused.
2025-08-27 20:05:06 -04:00
John Ericson
0590b13156 Revert "Add a crude tracing mechansim for the build results"
The commit says it was added for CA testing --- manual I assume, since
there is no use of this in the test suite. I don't think we need it any
more, and I am not sure whether it was ever supposed to have made it to
`master` either.

This reverts commit 2eec2f765a.
2025-08-27 19:36:02 -04:00
Bernardo Meurer Costa
241abcca86 refactor(libstore/http-binary-cache-store): pragma once 2025-08-27 21:13:59 +00:00
John Ericson
35978ca47b Merge pull request #13848 from obsidiansystems/factor-out-drv-check
Factor out `checkOutputs`
2025-08-27 16:50:38 -04:00
John Ericson
d1bdaef04e Factor out checkOutputs
We currently just use this during the build of a derivation, but there is no
reason we wouldn't want to use it elsewhere, e.g. to check the outputs
of someone else's build after the fact.

Moreover, I like pulling things out of `DerivationBuilder` that are
simple and don't need access to all that state. While
`DerivationBuilder` is unix-only, this refactor also make the code more
portable "for free".

The header is private, at Eelco's request.
2025-08-27 16:25:46 -04:00
John Ericson
6c8f5ef9f7 Merge pull request #13802 from obsidiansystems/post-build-hook-later
Move `runPostBuildHook` out of `DerivationBuilder`
2025-08-27 15:48:05 -04:00
John Ericson
193ad73ce2 Merge pull request #13808 from obsidiansystems/derivation-builder-kvm
Create `StringSet DerivationBuilderParams::systemFeatures`
2025-08-27 15:19:06 -04:00
John Ericson
f4a0161cb1 Create StringSet DerivationBuilderParams::systemFeatures
Do this to avoid checking "system features" from the store config
directly, because we rather not have `DerivationBuilder` depend on
`Store`.
2025-08-27 12:38:15 -04:00
John Ericson
79211b6110 Merge pull request #13846 from obsidiansystems/derivation-builder-params-aggregate-initialize
No more `DerivationBuilderParams:` constructor!
2025-08-27 12:30:49 -04:00
John Ericson
f5f9e32f54 No more DerivationBuilderParams: constructor!
I am not sure how/why this started working. C++23?
2025-08-27 11:40:02 -04:00
Jörg Thalheim
725a2f379f don't include derivation name in temporary build directories
With the migration to /nix/var/nix/builds we now have failing builds
when the derivation name is too long.
This change removes the derivation name from the temporary build to have
a predictable prefix length:

Also see: https://github.com/NixOS/infra/pull/764
for context.
2025-08-27 09:48:31 +02:00
Jörg Thalheim
564593bcb9 Merge pull request #13837 from xokdvium/bump-nixpkgs
flake: Update nixpkgs
2025-08-27 09:33:04 +02:00
Sergei Zimmerman
8ee74792fe Merge pull request #13819 from obsidiansystems/relative-url
Implement `parseURLRelative`, use in `HttpBinaryCacheStore`
2025-08-27 03:34:57 +03:00
John Ericson
e82210b3b2 Implement parseURLRelative, use in HttpBinaryCacheStore
This allows us to replace some very hacky and not correct string
concatentation in `HttpBinaryCacheStore`. It will especially be useful
with #13752, when today's hacks started to cause problems in practice,
not just theory.

Also make `fixGitURL` returned a `ParsedURL`.
2025-08-26 19:45:10 -04:00
Sergei Zimmerman
625477a7df flake: Update nixpkgs
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/cd32a774ac52caaa03bcfc9e7591ac8c18617ced?narHash=sha256-VtMQg02B3kt1oejwwrGn50U9Xbjgzfbb5TV5Wtx8dKI%3D' (2025-08-17)
  → 'github:NixOS/nixpkgs/d98ce345cdab58477ca61855540999c86577d19d?narHash=sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8%3D' (2025-08-26)

This update contains d1266642a8722f2a05e311fa151c1413d2b9653c, which
is necessary for the TOML timestamps to get tested via nixpkgsLibTests job.
2025-08-27 02:23:05 +03:00
Sergei Zimmerman
231f3af535 Merge pull request #13835 from obsidiansystems/better-string-split
Better `stringSplit`
2025-08-27 01:20:46 +03:00
John Ericson
cc4aa70e6e Better stringSplit
I need this for some `ParseURL` improvements, but I figure this is
better to send as its own PR.

I changed the tests willy-nilly to sometimes use
`std::list<std::string_view>` instead of `Strings` (which is
`std::list<std::string>`).

Co-Authored-By: Sergei Zimmerman <sergei@zimmerman.foo>
2025-08-26 18:03:23 -04:00
John Ericson
0bd9d6a28e Merge pull request #13832 from kip93/fix/empty-ports
Handle empty ports with new URL parsing
2025-08-26 13:55:59 -04:00
Leandro Reina
7989e3192d Handle empty ports 2025-08-26 17:41:27 +02:00
Robert Hensing
1e16a54ee5 Merge pull request #13828 from NixOS/readme-meeting-times
Update work meeting time in README
2025-08-26 01:37:07 +02:00
Robert Hensing
afade27123 Update work meeting time in README 2025-08-26 00:50:12 +02:00
John Ericson
0250d50df3 Move runPostBuildHook out of DerivationBuilder
It is suppposed to be "post build" not "during the build" after all. Its
location now matches that for the hook case (see elsewhere in
`DerivationdBuildingGoal`).

It was in a try-catch before, and now it isn't, but I believe that it is
impossible for it to throw `BuildError`, which is sufficient for this
code motion to be correct.
2025-08-25 18:29:24 -04:00
Robert Hensing
c1e2396d58 Merge pull request #13826 from xokdvium/sqlite-zfs-hack
SQLite: fsync db.sqlite-shm before opening the database
2025-08-26 00:05:40 +02:00
John Ericson
ca94905593 Merge pull request #13825 from obsidiansystems/slight-optimize-s3ToHttpsURL
`ParsedS3URL::toHttpsUrl` Slight optimize
2025-08-25 17:51:09 -04:00
Eelco Dolstra
e492c64c8e SQLite: fsync db.sqlite-shm before opening the database
This is a workaround for https://github.com/NixOS/nix/issues/13515
(opening the SQLite DB randomly taking a couple of seconds on ZFS).

(cherry picked from commit a7fceb5eec)
2025-08-26 00:42:18 +03:00
John Ericson
e4e8a615fa ParsedS3URL::toHttpsUrl Slight optimize
I didn't want to block that PR on further code review while I figured
out these new (to us) C++23 goodies.
2025-08-25 16:53:39 -04:00
John Ericson
fac34ad20f Merge pull request #13824 from xokdvium/fix-formatting
libexpr: Fix weird formatting after treewide reformat
2025-08-25 15:26:17 -04:00
John Ericson
024d3954af Merge pull request #13823 from lovesegfault/extract-s3ToHttpsURL
feat(libstore/s3): add toHttpsUrl
2025-08-25 15:11:38 -04:00
Sergei Zimmerman
f0e4af4365 libexpr: Fix weird formatting after treewide reformat 2025-08-25 22:09:18 +03:00
Bernardo Meurer Costa
5985d67906 feat(libstore/s3): add toHttpsUrl
This is extracted from the work in #13752
2025-08-25 18:48:19 +00:00
Eelco Dolstra
9bee0fa6ac Merge pull request #13822 from NixOS/bump-2.32.0
Bump version to 2.32
2025-08-25 17:22:57 +02:00
Eelco Dolstra
adec28bf85 Update release-process.md 2025-08-25 10:30:21 +02:00
Eelco Dolstra
f5e09d9b58 Update mergify.yml 2025-08-25 10:28:47 +02:00
Eelco Dolstra
f67daa4a87 Bump version 2025-08-25 10:27:46 +02:00
Ethan Evans
7b8ceb5d2d libutil, libexpr: #10542 abstract over getrusage for getting cpuTime stat and implement windows version
Update src/libutil/windows/current-process.cc

Prefer `nullptr` over `NULL`

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>

Update src/libutil/unix/current-process.cc

Prefer C++ type casts

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>

Update src/libutil/windows/current-process.cc

Prefer C++ type casts

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>

Update src/libutil/unix/current-process.cc

Don't allocate exception

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-08-24 18:45:33 -07:00
John Ericson
c9211b0b2d Merge pull request #13803 from obsidiansystems/more-parsed-urls
Make more URLs parsed, most notably `FileTransferRequest::url`
2025-08-23 10:54:39 -04:00
John Ericson
2fa2c0b09f Merge pull request #13812 from obsidiansystems/url-parse-leniency
Limit to lenient parsing of non-standard URLs only where needed
2025-08-23 10:53:59 -04:00
Jörg Thalheim
ebf1cf5227 Merge pull request #13807 from roberth/release-notes-todo
maintainers: Add script for release notes todo list
2025-08-23 08:52:22 +02:00
John Ericson
3e86d75c9d Make more URLs parsed, most notably FileTransferRequest::url
Trying to gradually replace the use of strings with better types in ways
that makes sense.
2025-08-22 12:42:48 -04:00
John Ericson
72a548ed6a Limit to lenient parsing of non-standard URLs only where needed
This allows us to put `parseURL` in more spots without furthering
technical debt.
2025-08-22 12:37:37 -04:00
John Ericson
4083eff0c0 decodeQuery Take std::string_view not string ref 2025-08-22 12:26:48 -04:00
Robert Hensing
a1b3934a78 maintainers: Add script for release notes todo list 2025-08-21 14:19:22 +02:00
Grégory marti
f0c7fbcdab Add /etc/ssl/certs/ca-certificates.crt in docker.nix 2025-07-22 17:39:29 +02:00
614 changed files with 14178 additions and 6253 deletions

View File

@@ -15,6 +15,10 @@ so you understand the process and the expectations.
- volunteering contributions effectively
- how to get help and our review process.
PR stuck in review? We have two Nix team meetings per week online that are open for everyone in a jitsi conference:
- https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com
-->
## Motivation

View File

@@ -4,15 +4,29 @@ inputs:
dogfood:
description: "Whether to use Nix installed from the latest artifact from master branch"
required: true # Be explicit about the fact that we are using unreleased artifacts
experimental-installer:
description: "Whether to use the experimental installer to install Nix"
default: false
experimental-installer-version:
description: "Version of the experimental installer to use. If `latest`, the newest artifact from the default branch is used."
# TODO: This should probably be pinned to a release after https://github.com/NixOS/experimental-nix-installer/pull/49 lands in one
default: "latest"
extra_nix_config:
description: "Gets appended to `/etc/nix/nix.conf` if passed."
install_url:
description: "URL of the Nix installer"
required: false
default: "https://releases.nixos.org/nix/nix-2.30.2/install"
tarball_url:
description: "URL of the Nix tarball to use with the experimental installer"
required: false
github_token:
description: "Github token"
required: true
use_cache:
description: "Whether to setup github actions cache (not implemented currently)"
default: false
required: false
runs:
using: "composite"
steps:
@@ -37,14 +51,74 @@ runs:
gh run download "$RUN_ID" --repo "$DOGFOOD_REPO" -n "$INSTALLER_ARTIFACT" -D "$INSTALLER_DOWNLOAD_DIR"
echo "installer-path=file://$INSTALLER_DOWNLOAD_DIR" >> "$GITHUB_OUTPUT"
TARBALL_PATH="$(find "$INSTALLER_DOWNLOAD_DIR" -name 'nix*.tar.xz' -print | head -n 1)"
echo "tarball-path=file://$TARBALL_PATH" >> "$GITHUB_OUTPUT"
echo "::notice ::Dogfooding Nix installer from master (https://github.com/$DOGFOOD_REPO/actions/runs/$RUN_ID)"
env:
GH_TOKEN: ${{ inputs.github_token }}
DOGFOOD_REPO: "NixOS/nix"
- name: "Gather system info for experimental installer"
shell: bash
if: ${{ inputs.experimental-installer == 'true' }}
run: |
echo "::notice Using experimental installer from $EXPERIMENTAL_INSTALLER_REPO (https://github.com/$EXPERIMENTAL_INSTALLER_REPO)"
if [ "$RUNNER_OS" == "Linux" ]; then
EXPERIMENTAL_INSTALLER_SYSTEM="linux"
echo "EXPERIMENTAL_INSTALLER_SYSTEM=$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
elif [ "$RUNNER_OS" == "macOS" ]; then
EXPERIMENTAL_INSTALLER_SYSTEM="darwin"
echo "EXPERIMENTAL_INSTALLER_SYSTEM=$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
else
echo "::error ::Unsupported RUNNER_OS: $RUNNER_OS"
exit 1
fi
if [ "$RUNNER_ARCH" == "X64" ]; then
EXPERIMENTAL_INSTALLER_ARCH=x86_64
echo "EXPERIMENTAL_INSTALLER_ARCH=$EXPERIMENTAL_INSTALLER_ARCH" >> "$GITHUB_ENV"
elif [ "$RUNNER_ARCH" == "ARM64" ]; then
EXPERIMENTAL_INSTALLER_ARCH=aarch64
echo "EXPERIMENTAL_INSTALLER_ARCH=$EXPERIMENTAL_INSTALLER_ARCH" >> "$GITHUB_ENV"
else
echo "::error ::Unsupported RUNNER_ARCH: $RUNNER_ARCH"
exit 1
fi
echo "EXPERIMENTAL_INSTALLER_ARTIFACT=nix-installer-$EXPERIMENTAL_INSTALLER_ARCH-$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
env:
EXPERIMENTAL_INSTALLER_REPO: "NixOS/experimental-nix-installer"
- name: "Download latest experimental installer"
shell: bash
id: download-latest-experimental-installer
if: ${{ inputs.experimental-installer == 'true' && inputs.experimental-installer-version == 'latest' }}
run: |
RUN_ID=$(gh run list --repo "$EXPERIMENTAL_INSTALLER_REPO" --workflow ci.yml --branch main --status success --json databaseId --jq ".[0].databaseId")
EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR="$GITHUB_WORKSPACE/$EXPERIMENTAL_INSTALLER_ARTIFACT"
mkdir -p "$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR"
gh run download "$RUN_ID" --repo "$EXPERIMENTAL_INSTALLER_REPO" -n "$EXPERIMENTAL_INSTALLER_ARTIFACT" -D "$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR"
# Executable permissions are lost in artifacts
find $EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR -type f -exec chmod +x {} +
echo "installer-path=$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ inputs.github_token }}
EXPERIMENTAL_INSTALLER_REPO: "NixOS/experimental-nix-installer"
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
if: ${{ inputs.experimental-installer != 'true' }}
with:
# Ternary operator in GHA: https://www.github.com/actions/runner/issues/409#issuecomment-752775072
install_url: ${{ inputs.dogfood == 'true' && format('{0}/install', steps.download-nix-installer.outputs.installer-path) || inputs.install_url }}
install_options: ${{ inputs.dogfood == 'true' && format('--tarball-url-prefix {0}', steps.download-nix-installer.outputs.installer-path) || '' }}
extra_nix_config: ${{ inputs.extra_nix_config }}
- uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # v20
if: ${{ inputs.experimental-installer == 'true' }}
with:
diagnostic-endpoint: ""
# TODO: It'd be nice to use `artifacts.nixos.org` for both of these, maybe through an `/experimental-installer/latest` endpoint? or `/commit/<hash>`?
local-root: ${{ inputs.experimental-installer-version == 'latest' && steps.download-latest-experimental-installer.outputs.installer-path || '' }}
source-url: ${{ inputs.experimental-installer-version != 'latest' && 'https://artifacts.nixos.org/experimental-installer/tag/${{ inputs.experimental-installer-version }}/${{ env.EXPERIMENTAL_INSTALLER_ARTIFACT }}' || '' }}
nix-package-url: ${{ inputs.dogfood == 'true' && steps.download-nix-installer.outputs.tarball-path || (inputs.tarball_url || '') }}
extra-conf: ${{ inputs.extra_nix_config }}

View File

@@ -27,9 +27,34 @@ jobs:
extra_nix_config:
experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
use_cache: false
- run: nix flake show --all-systems --json
pre-commit-checks:
name: pre-commit checks
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/install-nix-action
with:
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
extra_nix_config: experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
- run: ./ci/gha/tests/pre-commit-checks
basic-checks:
name: aggregate basic checks
if: ${{ always() }}
runs-on: ubuntu-24.04
needs: [pre-commit-checks, eval]
steps:
- name: Exit with any errors
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: |
exit 1
tests:
needs: basic-checks
strategy:
fail-fast: false
matrix:
@@ -65,7 +90,6 @@ jobs:
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
# The sandbox would otherwise be disabled by default on Darwin
extra_nix_config: "sandbox = true"
- uses: DeterminateSystems/magic-nix-cache-action@main
# Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
# https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
- run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
@@ -140,80 +164,23 @@ jobs:
- run: exec bash -c "nix-channel --add https://releases.nixos.org/nixos/unstable/nixos-23.05pre466020.60c1d71f2ba nixpkgs"
- run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"
# Steps to test CI automation in your own fork.
# 1. Sign-up for https://hub.docker.com/
# 2. Store your dockerhub username as DOCKERHUB_USERNAME in "Repository secrets" of your fork repository settings (https://github.com/$githubuser/nix/settings/secrets/actions)
# 3. Create an access token in https://hub.docker.com/settings/security and store it as DOCKERHUB_TOKEN in "Repository secrets" of your fork
check_secrets:
permissions:
contents: none
name: Check presence of secrets
runs-on: ubuntu-24.04
outputs:
docker: ${{ steps.secret.outputs.docker }}
steps:
- name: Check for DockerHub secrets
id: secret
env:
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
run: |
echo "docker=${{ env._DOCKER_SECRETS != '' }}" >> $GITHUB_OUTPUT
docker_push_image:
needs: [tests, vm_tests, check_secrets]
name: Push docker image to DockerHub and GHCR
needs: [tests, vm_tests]
if: github.event_name == 'push' && github.ref_name == 'master'
uses: ./.github/workflows/docker-push.yml
with:
ref: ${{ github.sha }}
is_master: true
permissions:
contents: read
packages: write
if: >-
needs.check_secrets.outputs.docker == 'true' &&
github.event_name == 'push' &&
github.ref_name == 'master'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: cachix/install-nix-action@v31
with:
install_url: https://releases.nixos.org/nix/nix-2.20.3/install
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
- run: nix --experimental-features 'nix-command flakes' build .#dockerImage -L
- run: docker load -i ./result/image.tar.gz
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
# We'll deploy the newly built image to both Docker Hub and Github Container Registry.
#
# Push to Docker Hub first
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
# Push to GitHub Container Registry as well
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/nix
# Change all uppercase to lowercase
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
docker tag nix:$NIX_VERSION $IMAGE_ID:$NIX_VERSION
docker tag nix:$NIX_VERSION $IMAGE_ID:latest
docker push $IMAGE_ID:$NIX_VERSION
docker push $IMAGE_ID:latest
# deprecated 2024-02-24
docker tag nix:$NIX_VERSION $IMAGE_ID:master
docker push $IMAGE_ID:master
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
vm_tests:
needs: basic-checks
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
@@ -254,7 +221,6 @@ jobs:
extra_nix_config:
experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh
profile_build:
@@ -275,7 +241,6 @@ jobs:
extra_nix_config: |
experimental-features = flakes nix-command ca-derivations impure-derivations
max-jobs = 1
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: |
nix build -L --file ./ci/gha/profile-build buildTimeReport --out-link build-time-report.md
cat build-time-report.md >> $GITHUB_STEP_SUMMARY

101
.github/workflows/docker-push.yml vendored Normal file
View File

@@ -0,0 +1,101 @@
name: "Push Docker Image"
on:
workflow_call:
inputs:
ref:
description: "Git ref to build the docker image from"
required: true
type: string
is_master:
description: "Whether run from master branch"
required: true
type: boolean
secrets:
DOCKERHUB_USERNAME:
required: true
DOCKERHUB_TOKEN:
required: true
permissions: {}
jobs:
# Steps to test CI automation in your own fork.
# 1. Sign-up for https://hub.docker.com/
# 2. Store your dockerhub username as DOCKERHUB_USERNAME in "Repository secrets" of your fork repository settings (https://github.com/$githubuser/nix/settings/secrets/actions)
# 3. Create an access token in https://hub.docker.com/settings/security and store it as DOCKERHUB_TOKEN in "Repository secrets" of your fork
check_secrets:
permissions:
contents: none
name: Check presence of secrets
runs-on: ubuntu-24.04
outputs:
docker: ${{ steps.secret.outputs.docker }}
steps:
- name: Check for DockerHub secrets
id: secret
env:
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
run: |
echo "docker=${{ env._DOCKER_SECRETS != '' }}" >> $GITHUB_OUTPUT
push:
name: Push docker image to DockerHub and GHCR
needs: [check_secrets]
permissions:
contents: read
packages: write
if: needs.check_secrets.outputs.docker == 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
ref: ${{ inputs.ref }}
- uses: ./.github/actions/install-nix-action
with:
dogfood: false
extra_nix_config: |
experimental-features = flakes nix-command
- run: echo NIX_VERSION="$(nix eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
- run: nix build .#dockerImage -L
- run: docker load -i ./result/image.tar.gz
# We'll deploy the newly built image to both Docker Hub and Github Container Registry.
#
# Push to Docker Hub first
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push to Docker Hub
env:
IS_MASTER: ${{ inputs.is_master }}
DOCKERHUB_REPO: ${{ secrets.DOCKERHUB_USERNAME }}/nix
run: |
docker tag nix:$NIX_VERSION $DOCKERHUB_REPO:$NIX_VERSION
docker push $DOCKERHUB_REPO:$NIX_VERSION
if [ "$IS_MASTER" = "true" ]; then
docker tag nix:$NIX_VERSION $DOCKERHUB_REPO:master
docker push $DOCKERHUB_REPO:master
fi
# Push to GitHub Container Registry as well
- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push to GHCR
env:
IS_MASTER: ${{ inputs.is_master }}
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/nix
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
docker tag nix:$NIX_VERSION $IMAGE_ID:$NIX_VERSION
docker push $IMAGE_ID:$NIX_VERSION
if [ "$IS_MASTER" = "true" ]; then
docker tag nix:$NIX_VERSION $IMAGE_ID:master
docker push $IMAGE_ID:master
fi

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-24.04
if: github.repository_owner == 'NixOS'
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v6
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
sync-labels: false

80
.github/workflows/upload-release.yml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: Upload Release
on:
workflow_dispatch:
inputs:
eval_id:
description: "Hydra evaluation ID"
required: true
type: number
is_latest:
description: "Mark as latest release"
required: false
type: boolean
default: false
permissions:
contents: read
id-token: write
packages: write
jobs:
release:
runs-on: ubuntu-24.04
environment: releases
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/install-nix-action
with:
dogfood: false # Use stable version
use_cache: false # Don't want any cache injection shenanigans
extra_nix_config: |
experimental-features = nix-command flakes
- name: Set NIX_PATH from flake input
run: |
NIXPKGS_PATH=$(nix build --inputs-from .# nixpkgs#path --print-out-paths --no-link)
# Shebangs with perl have issues. Pin nixpkgs this way. nix shell should maybe
# get the same uberhack that nix-shell has to support it.
echo "NIX_PATH=nixpkgs=$NIXPKGS_PATH" >> "$GITHUB_ENV"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
role-to-assume: "arn:aws:iam::080433136561:role/nix-release"
role-session-name: nix-release-oidc-${{ github.run_id }}
aws-region: eu-west-1
- name: Disable containerd image store
run: |
# Docker 28+ defaults to the containerd image store, which
# pushes layers uncompressed instead of gzip. OCI clients
# that only support gzip (e.g. go-containerregistry) fail
# with "gzip: invalid header". Disabling the containerd
# snapshotter restores the classic storage driver, which
# preserves gzip-compressed layers through the
# `docker load` / `docker push` pipeline.
echo '{"features":{"containerd-snapshotter":false}}' | sudo tee /etc/docker/daemon.json > /dev/null
sudo systemctl restart docker
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Upload release
run: |
./maintainers/upload-release.pl \
${{ inputs.eval_id }} \
--skip-git
env:
IS_LATEST: ${{ inputs.is_latest && '1' || '' }}
- name: Push to GHCR
run: |
DOCKER_OWNER="ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[A-Z]' '[a-z]')/nix"
./maintainers/upload-release.pl \
${{ inputs.eval_id }} \
--skip-git \
--skip-s3 \
--docker-owner "$DOCKER_OWNER"
env:
IS_LATEST: ${{ inputs.is_latest && '1' || '' }}

View File

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

View File

@@ -1 +1 @@
2.31.0
2.32.7

25
COPYING
View File

@@ -1,8 +1,8 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -10,7 +10,7 @@
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
@@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
@@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
@@ -484,8 +484,7 @@ convey the exclusion of warranty; and each file should have at least the
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
License along with this library; if not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@@ -496,9 +495,7 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
<signature of Moe Ghoul>, 1 April 1990
Moe Ghoul, President of Vice
That's all there is to it!

View File

@@ -24,16 +24,7 @@ let
enableSanitizersLayer = finalAttrs: prevAttrs: {
mesonFlags =
(prevAttrs.mesonFlags or [ ])
++ [
# Run all tests with UBSAN enabled. Running both with ubsan and
# without doesn't seem to have much immediate benefit for doubling
# the GHA CI workaround.
#
# TODO: Work toward enabling "address,undefined" if it seems feasible.
# This would maybe require dropping Boost coroutines and ignoring intentional
# memory leaks with detect_leaks=0.
(lib.mesonOption "b_sanitize" "undefined")
]
++ [ (lib.mesonOption "b_sanitize" "address,undefined") ]
++ (lib.optionals stdenv.cc.isClang [
# https://www.github.com/mesonbuild/meson/issues/764
(lib.mesonBool "b_lundef" false)
@@ -71,8 +62,12 @@ rec {
nixComponentsInstrumented = nixComponents.overrideScope (
final: prev: {
nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; };
# Boehm is incompatible with ASAN.
nix-expr = prev.nix-expr.override { enableGC = !withSanitizers; };
mesonComponentOverrides = lib.composeManyExtensions componentOverrides;
# Unclear how to make Perl bindings work with a dynamically linked ASAN.
nix-perl-bindings = if withSanitizers then null else prev.nix-perl-bindings;
}
);

24
ci/gha/tests/pre-commit-checks Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail
system=$(nix eval --raw --impure --expr builtins.currentSystem)
echo "::group::Running pre-commit checks"
if nix build ".#checks.$system.pre-commit" -L; then
echo "::endgroup::"
exit 0
fi
echo "::error ::Changes do not pass pre-commit checks"
cat <<EOF
The code isn't formatted or doesn't pass lints. You can run pre-commit locally with:
nix develop -c ./maintainers/format.sh
EOF
echo "::endgroup::"
exit 1

View File

@@ -24,8 +24,15 @@ def map_contents_recursively(transformer):
def process_command:
.[0] as $context |
.[1] as $body |
$body + {
sections: $body.sections | map(map_contents_recursively(if $context.renderer == "html" then transform_anchors_html else transform_anchors_strip end)),
};
# mdbook 0.5.x uses 'items' instead of 'sections'
if $body.items then
$body + {
items: $body.items | map(map_contents_recursively(if $context.renderer == "html" then transform_anchors_html else transform_anchors_strip end)),
}
else
$body + {
sections: $body.sections | map(map_contents_recursively(if $context.renderer == "html" then transform_anchors_html else transform_anchors_strip end)),
}
end;
process_command

View File

@@ -23,12 +23,3 @@ renderers = ["html"]
command = "jq --from-file ./anchors.jq"
[output.markdown]
[output.linkcheck]
# no Internet during the build (in the sandbox)
follow-web-links = false
# mdbook-linkcheck does not understand [foo]{#bar} style links, resulting in
# excessive "Potential incomplete link" warnings. No other kind of warning was
# produced at the time of writing.
warning-policy = "ignore"

View File

@@ -24,9 +24,9 @@ let
in
concatStringsSep "\n" (map showEntry storesList);
"index.md" =
replaceStrings [ "@store-types@" ] [ index ]
(readFile ./source/store/types/index.md.in);
"index.md" = replaceStrings [ "@store-types@" ] [ index ] (
readFile ./source/store/types/index.md.in
);
tableOfContents =
let

View File

@@ -15,6 +15,7 @@ pymod = import('python')
python = pymod.find_installation('python3')
nix_env_for_docs = {
'ASAN_OPTIONS' : 'abort_on_error=1:print_summary=1:detect_leaks=0',
'HOME' : '/dummy',
'NIX_CONF_DIR' : '/dummy',
'NIX_SSL_CERT_FILE' : '/dummy/no-ca-bundle.crt',

View File

@@ -6,7 +6,6 @@
ninja,
lowdown-unsandboxed,
mdbook,
mdbook-linkcheck,
jq,
python3,
rsync,
@@ -51,7 +50,6 @@ mkMesonDerivation (finalAttrs: {
ninja
(lib.getBin lowdown-unsandboxed)
mdbook
mdbook-linkcheck
jq
python3
rsync

View File

@@ -138,6 +138,7 @@
- [Contributing](development/contributing.md)
- [Releases](release-notes/index.md)
{{#include ./SUMMARY-rl-next.md}}
- [Release 2.32 (2025-10-06)](release-notes/rl-2.32.md)
- [Release 2.31 (2025-08-21)](release-notes/rl-2.31.md)
- [Release 2.30 (2025-07-07)](release-notes/rl-2.30.md)
- [Release 2.29 (2025-05-14)](release-notes/rl-2.29.md)

View File

@@ -2,6 +2,7 @@ xp_features_json = custom_target(
command : [ nix, '__dump-xp-features' ],
capture : true,
output : 'xp-features.json',
env : nix_env_for_docs,
)
experimental_features_shortlist_md = custom_target(

View File

@@ -23,7 +23,7 @@ $ nix-shell
To get a shell with one of the other [supported compilation environments](#compilation-environments):
```console
$ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages
$ nix-shell --attr devShells.x86_64-linux.native-clangStdenv
```
> **Note**
@@ -34,7 +34,7 @@ $ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages
To build Nix itself in this shell:
```console
[nix-shell]$ mesonFlags+=" --prefix=$(pwd)/outputs/out"
[nix-shell]$ out="$(pwd)/outputs/out" dev=$out debug=$out mesonFlags+=" --prefix=${out}"
[nix-shell]$ dontAddPrefix=1 configurePhase
[nix-shell]$ buildPhase
```

View File

@@ -24,6 +24,19 @@ It is also possible to build without debugging for faster build:
(The first line is needed because `fortify` hardening requires at least some optimization.)
## Building Nix with sanitizers
Nix can be built with [Address](https://clang.llvm.org/docs/AddressSanitizer.html) and
[UB](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) sanitizers using LLVM
or GCC. This is useful when debugging memory corruption issues.
```console
[nix-shell]$ export mesonBuildType=debugoptimized
[nix-shell]$ appendToVar mesonFlags "-Dlibexpr:gc=disabled" # Disable Boehm
[nix-shell]$ appendToVar mesonFlags "-Dbindings=false" # Disable nix-perl
[nix-shell]$ appendToVar mesonFlags "-Db_sanitize=address,undefined"
```
## Debugging the Nix Binary
Obtain your preferred debugger within the development shell:

View File

@@ -7,5 +7,6 @@ experimental_feature_descriptions_md = custom_target(
xp_features_json,
],
capture : true,
env : nix_env_for_docs,
output : 'experimental-feature-descriptions.md',
)

View File

@@ -5,12 +5,28 @@ All built-ins are available through the global [`builtins`](#builtins-builtins)
Some built-ins are also exposed directly in the global scope:
<!-- TODO(@rhendric, #10970): this list is incomplete -->
- [`derivation`](#builtins-derivation)
- [`import`](#builtins-import)
- `derivationStrict`
- [`abort`](#builtins-abort)
- [`baseNameOf`](#builtins-baseNameOf)
- [`break`](#builtins-break)
- [`dirOf`](#builtins-dirOf)
- [`false`](#builtins-false)
- [`fetchGit`](#builtins-fetchGit)
- `fetchMercurial`
- [`fetchTarball`](#builtins-fetchTarball)
- [`fetchTree`](#builtins-fetchTree)
- [`fromTOML`](#builtins-fromTOML)
- [`import`](#builtins-import)
- [`isNull`](#builtins-isNull)
- [`map`](#builtins-map)
- [`null`](#builtins-null)
- [`placeholder`](#builtins-placeholder)
- [`removeAttrs`](#builtins-removeAttrs)
- `scopedImport`
- [`throw`](#builtins-throw)
- [`toString`](#builtins-toString)
- [`true`](#builtins-true)
<dl>
<dt id="builtins-derivation"><a href="#builtins-derivation"><code>derivation <var>attrs</var></code></a></dt>

View File

@@ -14,6 +14,21 @@ is a JSON object with the following fields:
The name of the derivation.
This is used when calculating the store paths of the derivation's outputs.
* `version`:
Must be `3`.
This is a guard that allows us to continue evolving this format.
The choice of `3` is fairly arbitrary, but corresponds to this informal version:
- Version 0: A-Term format
- Version 1: Original JSON format, with ugly `"r:sha256"` inherited from A-Term format.
- Version 2: Separate `method` and `hashAlgo` fields in output specs
- Verison 3: Drop store dir from store paths, just include base name.
Note that while this format is experimental, the maintenance of versions is best-effort, and not promised to identify every change.
* `outputs`:
Information about the output paths of the derivation.
This is a JSON object with one member per output, where the key is the output name and the value is a JSON object with these fields:
@@ -52,7 +67,6 @@ is a JSON object with the following fields:
> ```json
> "outputs": {
> "out": {
> "path": "/nix/store/2543j7c6jn75blc3drf4g5vhb1rhdq29-source",
> "method": "nar",
> "hashAlgo": "sha256",
> "hash": "6fc80dcc62179dbc12fc0b5881275898f93444833d21b89dfe5f7fbcbb1d0d62"
@@ -63,6 +77,15 @@ is a JSON object with the following fields:
* `inputSrcs`:
A list of store paths on which this derivation depends.
> **Example**
>
> ```json
> "inputSrcs": [
> "47y241wqdhac3jm5l7nv0x4975mb1975-separate-debug-info.sh",
> "56d0w71pjj9bdr363ym3wj1zkwyqq97j-fix-pop-var-context-error.patch"
> ]
> ```
* `inputDrvs`:
A JSON object specifying the derivations on which this derivation depends, and what outputs of those derivations.
@@ -70,8 +93,8 @@ is a JSON object with the following fields:
>
> ```json
> "inputDrvs": {
> "/nix/store/6lkh5yi7nlb7l6dr8fljlli5zfd9hq58-curl-7.73.0.drv": ["dev"],
> "/nix/store/fn3kgnfzl5dzym26j8g907gq3kbm8bfh-unzip-6.0.drv": ["out"]
> "6lkh5yi7nlb7l6dr8fljlli5zfd9hq58-curl-7.73.0.drv": ["dev"],
> "fn3kgnfzl5dzym26j8g907gq3kbm8bfh-unzip-6.0.drv": ["out"]
> }
> ```

View File

@@ -0,0 +1,165 @@
# Release 2.32.0 (2025-10-06)
## Incompatible changes
- Removed support for daemons and clients older than Nix 2.0 [#13951](https://github.com/NixOS/nix/pull/13951)
We have dropped support in the daemon worker protocol for daemons and clients that don't speak at least version 18 of the protocol. This first Nix release that supports this version is Nix 2.0, released in February 2018.
- Derivation JSON format now uses store path basenames only [#13570](https://github.com/NixOS/nix/issues/13570) [#13980](https://github.com/NixOS/nix/pull/13980)
Experience with many JSON frameworks (e.g. nlohmann/json in C++, Serde in Rust, and Aeson in Haskell) has shown that the use of the store directory in JSON formats is an impediment to systematic JSON formats, because it requires the serializer/deserializer to take an extra parameter (the store directory).
We ultimately want to rectify this issue with all JSON formats to the extent allowed by our stability promises. To start with, we are changing the JSON format for derivations because the `nix derivation` commands are — in addition to being formally unstable — less widely used than other unstable commands.
See the documentation on the [JSON format for derivations](@docroot@/protocols/json/derivation.md) for further details.
- C API: `nix_get_attr_name_byidx`, `nix_get_attr_byidx` take a `nix_value *` instead of `const nix_value *` [#13987](https://github.com/NixOS/nix/pull/13987)
In order to accommodate a more optimized internal representation of attribute set merges these functions require
a mutable `nix_value *` that might be modified on access. This does *not* break the ABI of these functions.
## New features
- C API: Add lazy attribute and list item accessors [#14030](https://github.com/NixOS/nix/pull/14030)
The C API now includes lazy accessor functions for retrieving values from lists and attribute sets without forcing evaluation:
- `nix_get_list_byidx_lazy()` - Get a list element without forcing its evaluation
- `nix_get_attr_byname_lazy()` - Get an attribute value by name without forcing evaluation
- `nix_get_attr_byidx_lazy()` - Get an attribute by index without forcing evaluation
These functions are useful when forwarding unevaluated sub-values to other lists, attribute sets, or function calls. They allow more efficient handling of Nix values by deferring evaluation until actually needed.
Additionally, bounds checking has been improved for all `_byidx` functions to properly validate indices before access, preventing potential out-of-bounds errors.
The documentation for `NIX_ERR_KEY` error handling has also been clarified to specify when this error code is returned.
- HTTP binary caches now support transparent compression for metadata
HTTP binary cache stores can now compress `.narinfo`, `.ls`, and build log files before uploading them,
reducing bandwidth usage and storage requirements. The compression is applied transparently using the
`Content-Encoding` header, allowing compatible clients to automatically decompress the files.
Three new configuration options control this behavior:
- `narinfo-compression`: Compression method for `.narinfo` files
- `ls-compression`: Compression method for `.ls` files
- `log-compression`: Compression method for build logs in `log/` directory
Example usage:
```
nix copy --to 'http://cache.example.com?narinfo-compression=gzip&ls-compression=gzip' /nix/store/...
nix store copy-log --to 'http://cache.example.com?log-compression=br' /nix/store/...
```
- Temporary build directories no longer include derivation names [#13839](https://github.com/NixOS/nix/pull/13839)
Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`.
- External derivation builders [#14145](https://github.com/NixOS/nix/pull/14145)
These are helper programs that Nix calls to perform derivations for specified system types, e.g. by using QEMU to emulate a different type of platform. For more information, see the [`external-builders` setting](../command-ref/conf-file.md#conf-external-builders).
This is currently an experimental feature.
## Performance improvements
- Optimize memory usage of attribute set merges [#13987](https://github.com/NixOS/nix/pull/13987)
[Attribute set update operations](@docroot@/language/operators.md#update) have been optimized to
reduce reallocations in cases when the second operand is small.
For typical evaluations of nixpkgs this optimization leads to ~20% less memory allocated in total
without significantly affecting evaluation performance.
See [eval-attrset-update-layer-rhs-threshold](@docroot@/command-ref/conf-file.md#conf-eval-attrset-update-layer-rhs-threshold)
- Substituted flake inputs are no longer re-copied to the store [#14041](https://github.com/NixOS/nix/pull/14041)
Since 2.25, Nix would fail to store a cache entry for substituted flake inputs, which in turn would cause them to be re-copied to the store on initial evaluation. Caching these inputs results in a near doubling of performance in some cases — especially on I/O-bound machines and when using commands that fetch many inputs, like `nix flake [archive|prefetch-inputs]`.
- `nix flake check` now skips derivations that can be substituted [#13574](https://github.com/NixOS/nix/pull/13574)
Previously, `nix flake check` would evaluate and build/substitute all
derivations. Now, it will skip downloading derivations that can be substituted.
This can drastically decrease the time invocations take in environments where
checks may already be cached (like in CI).
- `fetchTarball` and `fetchurl` now correctly substitute (#14138)
At some point we stopped substituting calls to `fetchTarball` and `fetchurl` with a set `narHash` to avoid incorrectly substituting things in `fetchTree`, even though it would be safe to substitute when calling the legacy `fetch{Tarball,url}`. This fixes that regression where it is safe.
- Started moving AST allocations into a bump allocator [#14088](https://github.com/NixOS/nix/issues/14088)
This leaves smaller, immutable structures in the AST. So far this saves about 2% memory on a NixOS config evaluation.
## Contributors
This release was made possible by the following 32 contributors:
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)
- dram [**(@dramforever)**](https://github.com/dramforever)
- Ephraim Siegfried [**(@EphraimSiegfried)**](https://github.com/EphraimSiegfried)
- Robert Hensing [**(@roberth)**](https://github.com/roberth)
- Taeer Bar-Yam [**(@Radvendii)**](https://github.com/Radvendii)
- Emily [**(@emilazy)**](https://github.com/emilazy)
- Jens Petersen [**(@juhp)**](https://github.com/juhp)
- Bernardo Meurer [**(@lovesegfault)**](https://github.com/lovesegfault)
- Jörg Thalheim [**(@Mic92)**](https://github.com/Mic92)
- Leandro Emmanuel Reina Kiperman [**(@kip93)**](https://github.com/kip93)
- Marie [**(@NyCodeGHG)**](https://github.com/NyCodeGHG)
- Ethan Evans [**(@ethanavatar)**](https://github.com/ethanavatar)
- Yaroslav Bolyukin [**(@CertainLach)**](https://github.com/CertainLach)
- Matej Urbas [**(@urbas)**](https://github.com/urbas)
- Jami Kettunen [**(@JamiKettunen)**](https://github.com/JamiKettunen)
- Clayton [**(@netadr)**](https://github.com/netadr)
- Grégory Marti [**(@gmarti)**](https://github.com/gmarti)
- Eelco Dolstra [**(@edolstra)**](https://github.com/edolstra)
- rszyma [**(@rszyma)**](https://github.com/rszyma)
- Philip Wilk [**(@philipwilk)**](https://github.com/philipwilk)
- John Ericson [**(@Ericson2314)**](https://github.com/Ericson2314)
- Tom Westerhout [**(@twesterhout)**](https://github.com/twesterhout)
- Tristan Ross [**(@RossComputerGuy)**](https://github.com/RossComputerGuy)
- Sergei Zimmerman [**(@xokdvium)**](https://github.com/xokdvium)
- Jean-François Roche [**(@jfroche)**](https://github.com/jfroche)
- Seth Flynn [**(@getchoo)**](https://github.com/getchoo)
- éclairevoyant [**(@eclairevoyant)**](https://github.com/eclairevoyant)
- Glen Huang [**(@hgl)**](https://github.com/hgl)
- osman - オスマン [**(@osbm)**](https://github.com/osbm)
- David McFarland [**(@corngood)**](https://github.com/corngood)
- Cole Helbling [**(@cole-h)**](https://github.com/cole-h)
- Sinan Mohd [**(@sinanmohd)**](https://github.com/sinanmohd)
- Philipp Otterbein
# Release 2.32.5 (2026-01-02)
## Bug fixes
- Fix `builtins.fetchGit` with `ref = "HEAD"` [#13948](https://github.com/NixOS/nix/issues/13948) [#14673](https://github.com/NixOS/nix/pull/14673)
- Fix dynamic attributes that are simple string expressions [#14642](https://github.com/NixOS/nix/issues/14642) [#14646](https://github.com/NixOS/nix/pull/14646)
Dynamic attributes are typically not allowed in [`let` expressions](https://nix.dev/manual/nix/2.32/language/syntax.html#let-expressions), but simple [string literals](https://nix.dev/manual/nix/2.32/language/string-literals.html) are allowed. This special-case was broken in prior releases of 2.32.
- Fix null pointer dereference on reading non-existent derivations [#14571](https://github.com/NixOS/nix/issues/14571) [#14891](https://github.com/NixOS/nix/issues/14891) [#14572](https://github.com/NixOS/nix/pull/14572)
- Fix use-after-free in derivation build scheduler [#14782](https://github.com/NixOS/nix/pull/14782)
- Avoid querying remaining substituters after first success [#14836](https://github.com/NixOS/nix/issues/14836) [#14839](https://github.com/NixOS/nix/pull/14839)
- Improve temporary path creation in hard link store optimisation [#7273](https://github.com/NixOS/nix/issues/7273) [#14680](https://github.com/NixOS/nix/pull/14680)
`auto-optimise-store` has been known to be flaky on Darwin due the usage of `rand()` when constructing the path of a temporary hardlink.
- Move singletons out of headers [#14558](https://github.com/NixOS/nix/issues/14558)
Such variables have ["vague linkage"](https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Vague-Linkage.html) and require special support from the dynamic linker to deduplicate across different shared libraries. Platforms such as Cygwin do not support this and duplicate the symbols instead.
- Fix `curl` with `c-ares` failing to resolve DNS inside sandbox on macOS [#14859](https://github.com/NixOS/nix/pull/14859)
- Fix `recursive-nix` [#14730](https://github.com/NixOS/nix/pull/14730)
## Improvements
- Support building manual with mdbook 0.5 [#14628](https://github.com/NixOS/nix/issues/14628) [#14693](https://github.com/NixOS/nix/pull/14693)
- Improve `parent directory is world-writable or a symlink` error message to include the offending path component [#13701](https://github.com/NixOS/nix/issues/13701) [#14849](https://github.com/NixOS/nix/pull/14849)
- Correct `build-dir` documentation in manual [#14748](https://github.com/NixOS/nix/pull/14748)

View File

@@ -12,10 +12,11 @@
The [`builder`](./derivation/index.md#builder) is executed as follows:
- A temporary directory is created under the directory specified by
`TMPDIR` (default `/tmp`) where the build will take place. The
- A temporary directory is created where the build will take place. The
current directory is changed to this directory.
See the per-store [`build-dir`](@docroot@/store/types/local-store.md#store-local-store-build-dir) setting for more information.
- The environment is cleared and set to the derivation attributes, as
specified above.

View File

@@ -20,7 +20,8 @@ The graph of references excluding self-references thus forms a [directed acyclic
[directed acyclic graph]: @docroot@/glossary.md#gloss-directed-acyclic-graph
We can take the [transitive closure] of the references graph, which any pair of store objects have an edge not if there is a single reference from the first to the second, but a path of one or more references from the first to the second.
We can take the [transitive closure] of the references graph, in which any pair of store objects have an edge if a *path* of one or more references exists from the first to the second object.
(A single reference always forms a path which is one reference long, but longer paths may connect objects which have no direct reference between them.)
The *requisites* of a store object are all store objects reachable by paths of references which start with given store object's references.
[transitive closure]: https://en.wikipedia.org/wiki/Transitive_closure

View File

@@ -41,6 +41,10 @@ def recursive_replace(data: dict[str, t.Any], book_root: Path, search_path: Path
return data | dict(
sections = [recursive_replace(section, book_root, search_path) for section in sections],
)
case {'items': items}:
return data | dict(
items = [recursive_replace(item, book_root, search_path) for item in items],
)
case {'Chapter': chapter}:
path_to_chapter = Path(chapter['path'])
chapter_content = chapter['content']

View File

@@ -281,7 +281,10 @@ let
# may get replaced by pkgs.dockerTools.caCertificates
mkdir -p $out/etc/ssl/certs
# Old NixOS compatibility.
ln -s /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt $out/etc/ssl/certs
# NixOS canonical location
ln -s /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt $out/etc/ssl/certs/ca-certificates.crt
cat $passwdContentsPath > $out/etc/passwd
echo "" >> $out/etc/passwd

8
flake.lock generated
View File

@@ -63,16 +63,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1755442223,
"narHash": "sha256-VtMQg02B3kt1oejwwrGn50U9Xbjgzfbb5TV5Wtx8dKI=",
"lastModified": 1761597516,
"narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "cd32a774ac52caaa03bcfc9e7591ac8c18617ced",
"rev": "daf6dc47aa4b44791372d6139ab7b25269184d55",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05-small",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}

View File

@@ -1,7 +1,7 @@
{
description = "The purely functional package manager";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
@@ -32,7 +32,7 @@
let
inherit (nixpkgs) lib;
officialRelease = false;
officialRelease = true;
linux32BitSystems = [ "i686-linux" ];
linux64BitSystems = [

View File

@@ -46,7 +46,7 @@ The team meets twice a week (times are denoted in the [Europe/Amsterdam](https:/
- mark it as draft if it is blocked on the contributor
- escalate it back to the team by moving it to To discuss, and leaving a comment as to why the issue needs to be discussed again.
- Work meeting: Mondays 14:00-16:00 Europe/Amsterdam see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
- Work meeting: Mondays 18:00-20:00 Europe/Amsterdam; see [calendar](https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com).
1. Code review on pull requests from [In review](#in-review).
2. Other chores and tasks.

View File

@@ -203,5 +203,26 @@
"ConnorBaker01@Gmail.com": "ConnorBaker",
"jsoo1@asu.edu": "jsoo1",
"hsngrmpf+github@gmail.com": "DavHau",
"matthew@floxdev.com": "mkenigs"
"matthew@floxdev.com": "mkenigs",
"taeer@bar-yam.me": "Radvendii",
"beme@anthropic.com": "lovesegfault",
"osbm@osbm.dev": "osbm",
"jami.kettunen@protonmail.com": "JamiKettunen",
"ephraim.siegfried@hotmail.com": "EphraimSiegfried",
"rszyma.dev@gmail.com": "rszyma",
"tristan.ross@determinate.systems": "RossComputerGuy",
"corngood@gmail.com": "corngood",
"jfroche@pyxel.be": "jfroche",
"848000+eclairevoyant@users.noreply.github.com": "eclairevoyant",
"petersen@redhat.com": "juhp",
"dramforever@live.com": "dramforever",
"me@glenhuang.com": "hgl",
"philip.wilk@fivium.co.uk": "philipwilk",
"me@nycode.dev": "NyCodeGHG",
"14264576+twesterhout@users.noreply.github.com": "twesterhout",
"sinan@sinanmohd.com": "sinanmohd",
"42688647+netadr@users.noreply.github.com": "netadr",
"matej.urbas@gmail.com": "urbas",
"ethanalexevans@gmail.com": "ethanavatar",
"greg.marti@gmail.com": "gmarti"
}

View File

@@ -177,5 +177,24 @@
"avnik": "Alexander V. Nikolaev",
"DavHau": null,
"aln730": "AGawas",
"vog": "Volker Diels-Grabsch"
"vog": "Volker Diels-Grabsch",
"corngood": "David McFarland",
"twesterhout": "Tom Westerhout",
"JamiKettunen": "Jami Kettunen",
"dramforever": "dram",
"philipwilk": "Philip Wilk",
"netadr": "Clayton",
"NyCodeGHG": "Marie",
"jfroche": "Jean-Fran\u00e7ois Roche",
"urbas": "Matej Urbas",
"osbm": "osman - \u30aa\u30b9\u30de\u30f3",
"rszyma": null,
"eclairevoyant": "\u00e9clairevoyant",
"Radvendii": "Taeer Bar-Yam",
"sinanmohd": "Sinan Mohd",
"ethanavatar": "Ethan Evans",
"gmarti": "Gr\u00e9gory Marti",
"lovesegfault": "Bernardo Meurer",
"EphraimSiegfried": "Ephraim Siegfried",
"hgl": "Glen Huang"
}

View File

@@ -79,6 +79,8 @@
# Not supported by nixfmt
''^tests/functional/lang/eval-okay-deprecate-cursed-or\.nix$''
''^tests/functional/lang/eval-okay-attrs5\.nix$''
''^tests/functional/lang/eval-fail-dynamic-attrs-inherit\.nix$''
''^tests/functional/lang/eval-fail-dynamic-attrs-inherit-2\.nix$''
# More syntax tests
# These tests, or parts of them, should have been parse-* test cases.
@@ -104,151 +106,6 @@
};
shellcheck = {
enable = true;
excludes = [
# We haven't linted these files yet
''^config/install-sh$''
''^misc/bash/completion\.sh$''
''^misc/fish/completion\.fish$''
''^misc/zsh/completion\.zsh$''
''^scripts/create-darwin-volume\.sh$''
''^scripts/install-darwin-multi-user\.sh$''
''^scripts/install-multi-user\.sh$''
''^scripts/install-systemd-multi-user\.sh$''
''^src/nix/get-env\.sh$''
''^tests/functional/ca/build-dry\.sh$''
''^tests/functional/ca/build-with-garbage-path\.sh$''
''^tests/functional/ca/common\.sh$''
''^tests/functional/ca/concurrent-builds\.sh$''
''^tests/functional/ca/eval-store\.sh$''
''^tests/functional/ca/gc\.sh$''
''^tests/functional/ca/import-from-derivation\.sh$''
''^tests/functional/ca/new-build-cmd\.sh$''
''^tests/functional/ca/nix-shell\.sh$''
''^tests/functional/ca/post-hook\.sh$''
''^tests/functional/ca/recursive\.sh$''
''^tests/functional/ca/repl\.sh$''
''^tests/functional/ca/selfref-gc\.sh$''
''^tests/functional/ca/why-depends\.sh$''
''^tests/functional/characterisation-test-infra\.sh$''
''^tests/functional/common/vars-and-functions\.sh$''
''^tests/functional/completions\.sh$''
''^tests/functional/compute-levels\.sh$''
''^tests/functional/config\.sh$''
''^tests/functional/db-migration\.sh$''
''^tests/functional/debugger\.sh$''
''^tests/functional/dependencies\.builder0\.sh$''
''^tests/functional/dependencies\.sh$''
''^tests/functional/dump-db\.sh$''
''^tests/functional/dyn-drv/build-built-drv\.sh$''
''^tests/functional/dyn-drv/common\.sh$''
''^tests/functional/dyn-drv/dep-built-drv\.sh$''
''^tests/functional/dyn-drv/eval-outputOf\.sh$''
''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$''
''^tests/functional/dyn-drv/recursive-mod-json\.sh$''
''^tests/functional/eval-store\.sh$''
''^tests/functional/export-graph\.sh$''
''^tests/functional/export\.sh$''
''^tests/functional/extra-sandbox-profile\.sh$''
''^tests/functional/fetchClosure\.sh$''
''^tests/functional/fetchGit\.sh$''
''^tests/functional/fetchGitRefs\.sh$''
''^tests/functional/fetchGitSubmodules\.sh$''
''^tests/functional/fetchGitVerification\.sh$''
''^tests/functional/fetchMercurial\.sh$''
''^tests/functional/fixed\.builder1\.sh$''
''^tests/functional/fixed\.builder2\.sh$''
''^tests/functional/fixed\.sh$''
''^tests/functional/flakes/absolute-paths\.sh$''
''^tests/functional/flakes/check\.sh$''
''^tests/functional/flakes/config\.sh$''
''^tests/functional/flakes/flakes\.sh$''
''^tests/functional/flakes/follow-paths\.sh$''
''^tests/functional/flakes/prefetch\.sh$''
''^tests/functional/flakes/run\.sh$''
''^tests/functional/flakes/show\.sh$''
''^tests/functional/formatter\.sh$''
''^tests/functional/formatter\.simple\.sh$''
''^tests/functional/gc-auto\.sh$''
''^tests/functional/gc-concurrent\.builder\.sh$''
''^tests/functional/gc-concurrent\.sh$''
''^tests/functional/gc-concurrent2\.builder\.sh$''
''^tests/functional/gc-non-blocking\.sh$''
''^tests/functional/hash-convert\.sh$''
''^tests/functional/impure-derivations\.sh$''
''^tests/functional/impure-eval\.sh$''
''^tests/functional/install-darwin\.sh$''
''^tests/functional/legacy-ssh-store\.sh$''
''^tests/functional/linux-sandbox\.sh$''
''^tests/functional/local-overlay-store/add-lower-inner\.sh$''
''^tests/functional/local-overlay-store/add-lower\.sh$''
''^tests/functional/local-overlay-store/bad-uris\.sh$''
''^tests/functional/local-overlay-store/build-inner\.sh$''
''^tests/functional/local-overlay-store/build\.sh$''
''^tests/functional/local-overlay-store/check-post-init-inner\.sh$''
''^tests/functional/local-overlay-store/check-post-init\.sh$''
''^tests/functional/local-overlay-store/common\.sh$''
''^tests/functional/local-overlay-store/delete-duplicate-inner\.sh$''
''^tests/functional/local-overlay-store/delete-duplicate\.sh$''
''^tests/functional/local-overlay-store/delete-refs-inner\.sh$''
''^tests/functional/local-overlay-store/delete-refs\.sh$''
''^tests/functional/local-overlay-store/gc-inner\.sh$''
''^tests/functional/local-overlay-store/gc\.sh$''
''^tests/functional/local-overlay-store/optimise-inner\.sh$''
''^tests/functional/local-overlay-store/optimise\.sh$''
''^tests/functional/local-overlay-store/redundant-add-inner\.sh$''
''^tests/functional/local-overlay-store/redundant-add\.sh$''
''^tests/functional/local-overlay-store/remount\.sh$''
''^tests/functional/local-overlay-store/stale-file-handle-inner\.sh$''
''^tests/functional/local-overlay-store/stale-file-handle\.sh$''
''^tests/functional/local-overlay-store/verify-inner\.sh$''
''^tests/functional/local-overlay-store/verify\.sh$''
''^tests/functional/logging\.sh$''
''^tests/functional/misc\.sh$''
''^tests/functional/multiple-outputs\.sh$''
''^tests/functional/nested-sandboxing\.sh$''
''^tests/functional/nested-sandboxing/command\.sh$''
''^tests/functional/nix-build\.sh$''
''^tests/functional/nix-channel\.sh$''
''^tests/functional/nix-collect-garbage-d\.sh$''
''^tests/functional/nix-copy-ssh-common\.sh$''
''^tests/functional/nix-copy-ssh-ng\.sh$''
''^tests/functional/nix-copy-ssh\.sh$''
''^tests/functional/nix-daemon-untrusting\.sh$''
''^tests/functional/nix-profile\.sh$''
''^tests/functional/nix-shell\.sh$''
''^tests/functional/nix_path\.sh$''
''^tests/functional/optimise-store\.sh$''
''^tests/functional/output-normalization\.sh$''
''^tests/functional/parallel\.builder\.sh$''
''^tests/functional/parallel\.sh$''
''^tests/functional/pass-as-file\.sh$''
''^tests/functional/path-from-hash-part\.sh$''
''^tests/functional/path-info\.sh$''
''^tests/functional/placeholders\.sh$''
''^tests/functional/post-hook\.sh$''
''^tests/functional/pure-eval\.sh$''
''^tests/functional/push-to-store-old\.sh$''
''^tests/functional/push-to-store\.sh$''
''^tests/functional/read-only-store\.sh$''
''^tests/functional/readfile-context\.sh$''
''^tests/functional/recursive\.sh$''
''^tests/functional/referrers\.sh$''
''^tests/functional/remote-store\.sh$''
''^tests/functional/repair\.sh$''
''^tests/functional/restricted\.sh$''
''^tests/functional/search\.sh$''
''^tests/functional/secure-drv-outputs\.sh$''
''^tests/functional/selfref-gc\.sh$''
''^tests/functional/shell\.shebang\.sh$''
''^tests/functional/simple\.builder\.sh$''
''^tests/functional/supplementary-groups\.sh$''
''^tests/functional/toString-path\.sh$''
''^tests/functional/user-envs-migration\.sh$''
''^tests/functional/user-envs-test-case\.sh$''
''^tests/functional/user-envs\.builder\.sh$''
''^tests/functional/user-envs\.sh$''
''^tests/functional/why-depends\.sh$''
];
};
};
};

View File

@@ -0,0 +1,110 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGPtMiwBEAC0sFZW2QW/OaDjKm5zGRpDvHXDsMIUtlHfoi5ce8pocC63W05o
FSXbUZjZ1VfYO8lT8DFANCzTkiXYaZx0cPRG2pVY4AOQZDNFt5XrAyvw496XCAIM
DTYGFLjCqgjPt9RUFEy4MyHPJTEpB0x3rXgT4ILNu9vsj9Q0vttps7SpbZ3Ldq5H
o/BBbLW77q/vNjpYzCbBIXF7ycUGpnNv9Go/WuiDnrBMcyxh+8kjjIHB5cxZSnjJ
DUv681+m83v+gLZQGX/jexQrrf5JpS0X9qEnhGLrNUDhtyv5ud3Je4EfamkjLVVC
RlNLofgflOCsl/tP80i+K7S1QdKhUALxuJ6H0prYUflGBDxDyC8XYuJ62TT0OUpa
vJvgwVlCq8/jq+ykYQXlbuBVOzi5wAuI4l3+HqreSQYPSiwe+6N590Zbafdv1fvN
WFtZKCTGMqfyaaAnppioH9/+NWkI2AQxaYVasYM/JEYvY9pJgA7alh51jHW4JglP
ErypKfBKPKJID0QENqYoa3bDDCihuNWhgQf9dxzPlj2ckd35Zb6w4DfuSmtjaa9D
o0jZVY1JbFuxBqP09+saVPrxLHgmPxjcdzPGQQtAqdO2vyJXNEGLFMoVEZPNaLo3
QmcIJnT7oSck+4vGfOYtWUHXQynu/Tnwsv2XkA/uyw8HNe+RRMqv/apnzQARAQAB
tCdTZXJnZWkgWmltbWVybWFuIDxzZXJnZWlAemltbWVybWFuLmZvbz6JAlEEEwEK
ADsCGwEFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQQVim9TDqIC5fZRYRMU+upj
RI4d+QUCaUbsaAIZAQAKCRAU+upjRI4d+VdDD/492HRaJ/8V7R7VUzkafmb2Hb28
SLf7oiB8Uq9I7SukiDEaIT1fUhquYWQ9KWpPRNR1TX6ApXnIeuJRMGFoDVIRnmnr
cKnYYXfqqc81VxIyKvaumB7KWbS7G4Nbor8AH1ouOOOMMS50OTJOWQA4A26inIuG
n+7L8MeS5aT+3uNKDoTKsidC47vnaxNMcke1taPfbfo7vn69PsRCM/g9/7TQYU8b
6xp+pM9Ao9nJneRk2YCpsGYRrWTpaik0DFKnfpPKJM/yunhtGLF2IYAp3l1mvHPK
nnzo92zjpQuZwazEIK+23V1vRT4IjM2BewbJPAzf2/UuxEjjgNQm0tOtH2JhFNeB
VM0BVrGxWrrwrsmv6lWghTtBc6zRWyHrj/rpjtVQNmeKYrHWJeXwVz1rqgGPmB2N
k0MZD1UjHHhEs1Cntn7yLmxTPztRJCtR+euRu81Uo2NAvrMJ4xsDjaM0LeLTnzjV
9AsPjD188dOFyz7VExZum4+XaaEJ41FIPLEqU3U0GAa6stEy0ylSlIN4x9aiXXVW
xfzHHchS5jK6QAjuZxN8t01GRactNylINRf7uoTECFZTtXNqfeuk0HQxBH0LuKVE
0PxJbcNI4mVWw1KgTJ8PUVC1IXP3sEpqPdJOYiRXgnpcS26fWOBu0aQ4mhxiaJhr
/zBfrkLEqp20TdNDZLkCDQRj7TM1ARAAt73xO24curnHTTgXkkVMMRzcMLx3Mb1a
2FuddxC5hzTpEpw01L91UBrXVJEg9K2KAwP5CtCLgPCqXr47Tm7krvHxWwBksgY/
6aHRsoPQfCFUZHc0aiO+C4NCzR+aEeGKn66Oc1Hq9oUTpDgiBWhsuEPiyA1OSGF0
4L0jeTCqfm68kWp4PIK9yuugkdDsoyj6TonuMsb3V5ctHLqop9KH+eHSkUTPo+Lk
+bxaeAOJ1UfbohgbRbrYKAfsaghhOMDH3R1w2pvtUJz+sDbuQsiPFTqbxsXDTFws
H4N/AQCYnnvOhqEek2sOEZ19bJXt5UrAr10mX4PGmAkWqE1JWBxpOKG3BXSGOTu1
3dFhQfPMK+PmvUrs0kcWQr53K/aRUdKKhIfTcMfkqYTGPK5HclHph24WjXj3QFFA
SjksQTdm6486ZmLZK4CTbAFOPfTF/aWg8gu9v4ihdq6lqHNNXxv2xBAChcd59H7p
D5zy9z8SpwWR9V5JDmlF6HWIIau1c6lSsQq1xHvYM8EuPe03vJvor+2u/cn5zYF1
5ZxAuPI2i5vtavg1s8ZGAAogJ9dVcP36LdJfL9quXWvmovkd//qHIepBB+l/zQio
ZRDZlIcfV3Xycaqsb5OqHGARHE0097koipMt5y/iXlqG4Ruue6Idb8bW96EKpaWj
kKy/iNfQfQMAEQEAAYkEcgQYAQoAJgIbAhYhBBWKb1MOogLl9lFhExT66mNEjh35
BQJpRuz3BQkJHCDCAkDBdCAEGQEKAB0WIQRK3hK0WyJ4BicGpcmpsLVXymMjJQUC
Y+0zNQAKCRCpsLVXymMjJbdSD/9+f1FOOeGDAJI6Duo5fsWnf4xJJdtQtDbz6d2A
SeDapxeJ3zWfKBD0wu5sISEa0uiWsYSmLtsa2SqVAKHlEaMGRR+tkBMPQ+rvgI4c
62YjGTgm+IPd+NFIn+ixFU1hpinTh+KhUEoeOwWCvKs9nZfSG9vkienfiG0bBxo2
zrvBzXA50x5hbUL+ghKu/AVfN9qZDwh30O4KZTwk4g4cM9SeaQa4YvHYIS3IEhDZ
hGybwrrqV9cs92ln4IJw9WCy9QReBNrdeFgC4+3ziUp1QsG3RvqrtuMttwBVC1Z3
bj5QjLLOREhhodfvk98t9yVkragObb4rGrLo1mWuF0c4mJGvXwnrqhCMvzv4M+0T
Zdrmw6YpGkGOaOPghVuwoTtqSAkl+zFWIJS89jidvkYG3EqKAkgLKog/TQReCq13
HWrF8cMck+Rf2K8k26q/RNZaA9ZUKjLExzz8lsWmd2C7rvkGLrlxnzxz0gGyNR3Q
KK74vcPhqeABt2GSkHtEXZFFA9IVVzwlRWK3e0S+mVQnZVjNL+cBPn3/hZHMLesB
CucyYZv+DxvT+JkYXBkGSw4s3hpABqGym7gdPUIa0q4rbBFG6xP5sLLBG4yru8vV
2dyCMmFqRuxpT49uNfyQ6Vj+dobN6qHnP/9NwfzOixXYBHXR6LBqb/M+iCiJaaIn
uiRLHwkQFPrqY0SOHfkQpA//W51vj8meuz7snRO+vZFcjLneFFzqfh1Jdz8IqDpO
CkI5pBJmi8e0oSe6r68MkahiQLlYPwm7d+sjHvJhPWipNKWq/uwCgBs+Ac1lpPXR
MwLbrZukcLMYlLmb2MrCKmjcMt0BZsZKBNYL3a3X9nHgwXdeqFYS4WQDMCCc09lz
9YqfdoEsqRO4qN7D0hFqnwjOzb34ixZ6UO8a8ekY9QKxAgWc9fJWGMg6Pjdg4qsK
nqymOIAdGVOJdoRM46wKGVBvbsF2gNfQU4XyzgJo5vHGFwJm6EoSnODlL5e2wsQh
uN1oqBt/8ef/plloMEqVBweUBATqSqjRF6IhhYJvWVuQHQL1p1vnV9FebiVj34ir
Z8ID+o0AnTJcclbUcDwannGJ0cuDcPhk/v/ahVuoMERCi12qnMBo5B/e6Omyh1yB
4pbf4GATGGQipDQG75eC/kP2GQEqJP5WYN0Ar8Le/AA/2xyL7upW0yIByyXCwGEb
JRwEgU3+bPyu58bFt8Pftit6J7rA3oBVVMOPrYH5eZwRaj5m2RptwKGL6BfHnhNv
ZqmCq9EBGX6L1NI0xHMjEFfXJ8jU01XdfG8nCqkwqsHwslXLhqjJphfHcx89YwbV
/15GCuURAv1cKe/7277sOhcvP/QpQqSWgvYExHw8PeFJcTYtF2NrRgNwcQsWS1Rj
gXa5Ag0EY+0zcAEQANC5N6kSfezuucAgi+X3BD+MT37mxQyvICSggEJf1LDSmy0+
bnvD7setL8CP9etTA2fcVNYKI1oboMyhoCnsRP2jDdv1iXOI/hZg4wSb/D1yUkae
fUpxv3Wuci2QKavH2MfraDD7BFMbsQeMcHtn4Rk216T6jndZHnzT1Ih7iX0XeQPb
li5fojOiZssgWAVT4HPXFCJB6lI35Hjp35oRYwrtMmu5INinZ79n9h1igGtt1ItZ
b7rQKNd772Jxcn4UU71ovORSL/xT5i5sxZ+evQOxkpqUAokMOFaoHcOXLmA1NsFv
yryXHK4Ioq9ap2jKlLTWkJWjua9JZ4AmKhbvT8X4ELxIKSCAdJKAWP8ZHbXNu5MD
aznyzZQLxSO7uFvu356De75mI5iohZNj5wB5Wju71pBiorTKVj4+iJ4e+xVIzFdG
hFC0DehNcl2t9w/y8qHwIQ1yUAjXHLXq0/2jsVeH6bU5q/MsgvUP1jcFe0eyOpxy
CDvyFdzZFbI57TnB/fvcZTRZ5ewXMFpH8gzuoFzAjUAP95UjYKgaGdrNPNIy28Ii
4zhvdghei2+n9jgiMfcGQg8lyfH5yF0vWWWynX0KcJsRwEZoL2EauVdwq4PcYOoU
pQFhpcreCjD4LdZ4yRU4InbhcUogXjrQ9Dz01TbPmQD5b5iso21bCEFBXrhzABEB
AAGJAjwEGAEKACYCGwwWIQQVim9TDqIC5fZRYRMU+upjRI4d+QUCaUbs9wUJCRwg
hwAKCRAU+upjRI4d+X/XD/sH5xvHPfTJq52v8weFmB52up+DzqG2lyhGdoUQ1Muw
dRDLTLXLJrFdfpoOo7/j4Scr0rdc7/dpCn0DLcPuCoPxu+SkjEnVehFmZrGSv7Ga
x9dHr3DBh42fdlX/U/EnDuyosY0JU1gNF2/6FIA+bTTOFE3RxfN906RjslYQDjMZ
UAlSeLYHOZofdltI0YIr32vrxgdWQGZXPxU4XusDUc0z163OO+TGg7iUNWFZP5Qj
ubM7e0YbDX0NPIshk8us99YJmrWnhaix1/W5ryO3DXiGaQ7XFi9u7QofRqvRIctg
QXavdepkzJow9V9qpMECAJePIuICq7rm+xy+njjbuF436W7390bfVBwRr+FPADsl
jgQP4KvY5rykss30kheom8wNEbveWkhH5oTfH9b7O4KXJfpfJzrlgOWp2BD9JL8t
/M4HvFXTr2a75H/QbHK5OFrZeGATuv9OTxv7EZvnrPXU+DYTFldpu7TrNNqKCoj3
ZyXmc3Hhg5kskDhfHJppaeOayuhMOpT3ud1MFzROY5SLVIH8rBR12KUgsCUYQcGs
Iy0+0QvEGkjb4cAH1NK3VlbqVNsy1RmqRt2B28R2ueewDfTOoqkzt4MmzLqTdnAx
mTqmHmkEKhEf3K4MRNUPO2yieUg2COk5l6x9HhAnoxxeOZrTmcMsPY/UViG2HEPm
ybkCDQRj7TRDARAA9DZuKdfKq4Bs2+NwxC0aplljWOl8VIsEVg+Q8agD7/HU6/b6
Dry0njtWybn2x6Axf/nUdeOC01Fi1lmht/fpj6mRkgAvd/V6P10xnsUoykPSDSTh
P25MFFGW3JAA82bwdJ4AJpEQvTZG2nTb3237vlBiI1qHQrac8GYkju2O4UfySRN6
7cyi7bMf2pjWBBOEhaNy4b6CMDsb32P/N5J7sTE/TXgrS+u4ITIgjzSrkUkh5Z+B
8QVRa7xPIDZJdvZWTEXWu5fgRPZvxbr154GIkWJkFzlDoB1UcO56/uzRUuKhEV6o
HW3LMUuWdPMjpHpq8hrL0G2rDniJFUtbDFzHdZK1LUU3T2BJM8rjI3D/euph+IDT
27vl5qo72zCYE/iKzx4FMLZcQvx1kUAxkPX8l+dzZEwKeRIIpFDxQvatRtl+z0bM
jbkpDb+Yjv66sC4dYRpgTTGX6rok0PWHR3IxDNzyf2j8zQ4LFJ+rVBM1GjGSt6mG
j9TeL8CVeiSp4SuJ7I/FJVPHsKb50m+BDzeB31qTydNqh2kKr0DVAUa+TUsCr7e0
OYr8WE2adJcRXIW0qw50xXF+W7/05GqSCVD0dpeOUdBTQTsSkQmM3/0hcj9aVo9e
UDCM9RF0WRqiDAoHzJFfg+ztamkQI5HO6CklC4Ok22qrHRf6HDNYSuT6QFkAEQEA
AYkCPQQYAQoAJwMbIAQWIQQVim9TDqIC5fZRYRMU+upjRI4d+QUCaUbs9wUJCRwf
tAAKCRAU+upjRI4d+Y+cD/9yllG6uo934pcHNsVppZBfREFwSc8ywlbosCuSVpay
PjSqgrWwDrnqrsk0F2kUdC6rR3BIcXbn+lA9KqylH+cCXAJCkh8EDq6TlQ7Lt5EV
w1U0MAMXOyxPwDymQ/BO+iDyjXWkRRYgbF5XiFhCfGeuKyhkhACisAgNZ1uA1P5k
0SJYc14YfEhQkB46Y20SpfVHRsQ46FyNB6GHbmTmfoO8La8VTh++7GBdh85HfvkG
VNQ3wpi5oXsOLN9+MJOezc0XsW2LQsKQj1/J7QKzGh+lxN5cemsA5aqPzh8dyxeT
0lYRFp4AHkimqGUomVpRkbegMIPxXqOE+ZAmsddErw0UtmrKxcmMptOJwNgYzEgu
++2vtqerL/NYp+wsdcWaBjCz2F3NiwHgNli7NSB/FPwucZZ5gN5C4SnmeFzrGdHg
Oy+tQUN6ayQKljHeBO7CjMlsFNo/dcVrEMa1ShxBMqlj/6ivoEhktLz0Nru4FwNU
xE5SJYDYfpjD7Ws8y4LoXgWXjFHrMO6N9GzqLN/e8LT7I+w4ps2MrgJ8QSrelmQ3
rjkxp3uWp5v2lqy4rLfpi9iB6zIAeoN2eU1yOM9joxOYMxKYaYeYyP1Mm90wFol8
LcTSaN+tVniPddBiL6zvsGBEMbCR9XN3EQ+mErbuw5ovWBOCrr+dvN3FxvD11y4J
7w==
=mXYP
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,51 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFZu2zwBCADfatenjH3cvhlU6AeInvp4R0JmPBG942aghFj1Qh57smRcO5Bv
y9mqrX3UDdmVvu58V3k1k9/GzPnAG1t+c7ohdymv/AMuNY4pE2sfxx7bX+mncTHX
5wthipn8kTNm4WjREjCJM1Bm5sozzEZetED3+0/dWlnHl8b38evnLsD+WbSrDPVp
o6M6Eg9IfMwTfcXzdmLmSnGolBWDQ9i1a0x0r3o+sDW5UTnr7jVP+zILcnOZ1Ewl
Rn9OJ4Qg3ULM7WTMDYpKH4BO7RLR3aJgmsFAHp17vgUnzzFBZ10MCS3UOyUNoyph
xo3belf7Q9nrHcSNbqSeQuBnW/vafAZUreAlABEBAAG0IkVlbGNvIERvbHN0cmEg
PGVkb2xzdHJhQGdtYWlsLmNvbT6JATwEEwEIACYCGyMHCwkIBwMCAQYVCAIJCgsE
FgIDAQIeAQIXgAUCVm7etAIZAQAKCRCBcLRybXGY3q51B/96qt41tmcDSzrj/UTl
O6rErfW5zFvVsJTZ95Duwu87t/DVhw5lKBQcjALqVddufw1nMzyN/tSOMVDW8xe4
wMEdcU4+QAMzNX80enuyinsw1glxfLcK0+VbTvqNIfw0sG3MjPqNs6cK2VRfMHK4
paJjytBVICszNX9TfjLyIpKKoSSo1vqnT47LDZ5GIMy7l9Cs2sO/rqQHSPcR79yz
8m8tbHpDDEMZmJeklckKP2QoiqnHiIvlisDxLclYnUmNaPdaN/f++qZz5Yqvu1n+
sNUBA5eLaZH64Uy2SwtABxO3JPJ8nQ2+SFZ7ocFm4Gcdv4aM+Ura9S6fvM91tEJp
yAQOiQE5BBMBCAAjBQJWbts8AhsjBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AA
CgkQgXC0cm1xmN6sIAgAielxO8zJREqEkA2xudg/o4e9ZlNZ3X1NvY8OzJH/qlB2
SmwKqwifhtbC1K0uavXA7eaxdtd2zrI+Yq7IooUyv7juMjHTZhLcFbR5iVkQ4Mfp
JmeHXJ/ChYKxD5mMj/C3WbCZ91oCSNZ6Iyi5fvQj/691OC4q+y/2NEUcOI8D8cw8
XKHbKtceFYc+nZmdOv3ZZrNTSN/kszGViNNLKgnpPdDVPtLp+vjXtbmitiFG2HL/
WfbJ+3Gh2Yr1Vy3O9dWKH++e1AmIv7WWqmUjRFVpqC/wr7/BLaScWT8WKF5vkshU
gq8Ez1/cuizsgs3wQIZWgXKQK5njvwnbKg+Zmh/uGbQmRWVsY28gRG9sc3RyYSA8
ZWVsY28uZG9sc3RyYUB0d2VhZy5pbz6JAU4EEwEIADgWIQS1QdVTAScOC88Vyl2B
cLRybXGY3gUCXELt4gIbIwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCBcLRy
bXGY3ujFCADfS5D1xHU8KH6TpqgssSggYVq62Wwn/Ga+4XPPetM+ajcXagyH6SwB
mxlHICcnv9xC93ryiTI10P1ADJl+aBsI66wEdHBU+ty4RTDy4JZNUPtmRCk9LhSc
mtUO3ry/wtWkRLdJxP49hg7BbQvWoU0M6WODp7SJjPKPWNX64mzHBeOuy+DqGCbM
lpGNCvW8ahU/ewbm7+xwWmzqLDoWzXjHsdF4QdzMVM/vkAgWEP4y0wEqFASzIYaR
GNEkBWU4OQVq5Bdm9+wWWAgsbM0FJAQl0GDqnz4QxWzxxCAAXdbh9F5ffafWYsA9
bise4ZQLkvYo6iUnrcFm4dtZbT8iL3gptCtFZWxjbyBEb2xzdHJhIDxlZWxjby5k
b2xzdHJhQGxvZ2ljYmxveC5jb20+iQE5BBMBCAAjBQJWbt6nAhsjBwsJCAcDAgEG
FQgCCQoLBBYCAwECHgECF4AACgkQgXC0cm1xmN4b/wf8DApMV/jSPEpibekrUPQu
Ye3Z8cxBQuRm/nOPowtPEH/ShAevrCdRiob2nuEZWNoqZ2e5/+6ud07Hs9bslvco
cDv1jeY1dof1idxfKhH3kfSpuD2XJhuzQBxBqOrIlCS/rdnW+Y9wOGD7+bs9QpcA
IyAeQGLLkfggAxaGYQ2Aev8pS7i3a/+lOWbFhcTe02I49KemCOJqBorG5FfILLNr
DjO3EoutNGpuz6rZvc/BlymphWBoAdUmxgoObr7NYWgw9pI8WeE6C7bbSOO7p5aQ
spWXU7Hm17DkzsVDpaJlyClllqK+DdKza5oWlBMe/P02jD3Y+0P/2rCCyQQwmH3D
RbkBDQRWbts8AQgA0g556xc08dH5YNEjbCwEt1j+XoRnV4+GfbSJIXOl9joIgzRC
4IaijvL8+4biWvX7HiybfvBKto0XB1AWLZRC3jWKX5p74I77UAcrD+VQ/roWQqlJ
BKbiQMlRYEsj/5Xnf72G90IP4DAFKvNl+rLChe+jUySA91BCtrYoP75Sw1BE9Cyz
xEtm4WUzKAJdXI+ZTBttA2Nbqy+GSuzBs7fSKDwREJaZmVrosvmns+pQVG4WPWf4
0l4mPguDQmZ9wSWZvBDkpG7AgHYDRYRGkMbAGsVfc6cScN2VsSTa6cbeeAEowKxM
qx9RbY3WOq6aKAm0qDvow1nl7WwXwe8K0wQxfQARAQABiQEfBBgBCAAJBQJWbts8
AhsMAAoJEIFwtHJtcZjeuAAH/0YNz2Qe1IAEO5oqEZNFOccL4KxVPrBhWUen83/b
C6PjOnOqv6q5ztAcms88WIKxBlfzIfq+dzJcbKVS/H7TEXgcaC+7EYW8sJVEsipN
BtEZ3LQNJ5coDjm7WZygniah1lfXNuiritAXduK5FWNNndqGArEaeZ8Shzdo/Uyi
b9lOsBIL6xc2ZcnX5f+rTu02LCEtEb0FwCycZLEWYf8hG4k8uttIOZOC+CLk/k8d
kBmPikMwUVTTV0CdT1cemQKdTaoAaK+kurF6FYXwcnjhRlHrisSt/tVMEwTw4LUM
3MYf6qfjjvE4HlDwZal8th7ccoQp/flfJIuRv85xCcKK+PI=
=u5cX
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,13 @@
# Maintainer GPG Keys
Release tags are signed by members of the [Nix maintainer team](https://nixos.org/community/teams/nix/) as part of the [release process](../release-process.md). This directory contains the public GPG keys used for signing.
## Keys
- **Eelco Dolstra**
GPG Fingerprint: `B541 D553 0127 0E0B CF15 CA5D 8170 B472 6D71 98DE`
- **Sergei Zimmerman**
GPG Fingerprint: [`158A 6F53 0EA2 02E5 F651 6113 14FA EA63 448E 1DF9`](https://keys.openpgp.org/vks/v1/by-fingerprint/158A6F530EA202E5F651611314FAEA63448E1DF9)
<!-- TODO: Add keys for other Nix team members -->

58
maintainers/release-notes-todo Executable file
View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
set -euo pipefail
# debug:
# set -x
START_REF="${1}"
END_REF="${2:-upstream/master}"
# Get the merge base
MERGE_BASE=$(git merge-base "$START_REF" "$END_REF")
unset START_REF
# Get date range
START_DATE=$(git show -s --format=%cI "$MERGE_BASE")
END_DATE=$(git show -s --format=%cI "$END_REF")
echo "Checking PRs merged between $START_DATE and $END_DATE" >&2
# Get all commits between merge base and HEAD
COMMITS=$(git rev-list "$MERGE_BASE..$END_REF")
# Convert to set for fast lookup
declare -A commit_set
for commit in $COMMITS; do
commit_set["$commit"]=1
done
# Get the current changelog
LOG_DONE="$(changelog-d doc/manual/rl-next)"
is_done(){
local nr="$1"
echo "$LOG_DONE" | grep -E "^- .*/pull/$nr)"
}
# Query merged PRs in date range
gh pr list \
--repo NixOS/nix \
--state merged \
--limit 1000 \
--json number,title,author,mergeCommit \
--search "merged:$START_DATE..$END_DATE" | \
jq -r '.[] | [.number, .mergeCommit.oid, .title, .author.login] | @tsv' | \
while IFS=$'\t' read -r pr_num merge_commit _title author; do
# Check if this PR's merge commit is in our branch
if [[ -n "${commit_set[$merge_commit]:-}" ]]; then
# Full detail, not suitable for comment due to mass ping and duplicate title
# echo "- #$pr_num $_title (@$author)"
echo "- #$pr_num ($author)"
if is_done "$pr_num"
then
echo " - [x] has note"
else
echo " - [ ] has note"
fi
echo " - [ ] skip"
fi
done

View File

@@ -5,11 +5,11 @@
The release process is intended to create the following for each
release:
* A Git tag
* A signed Git tag (public keys in `maintainers/keys/`)
* Binary tarballs in https://releases.nixos.org/?prefix=nix/
* Docker images
* Docker images (arm64 and amd64 variants, uploaded to DockerHub and GHCR)
* Closures in https://cache.nixos.org
@@ -24,6 +24,12 @@ release:
* In a checkout of the Nix repo, make sure you're on `master` and run
`git pull`.
* Compile a release notes to-do list by running
```console
$ ./maintainers/release-notes-todo PREV_RELEASE HEAD
```
* Compile the release notes by running
```console
@@ -98,21 +104,17 @@ release:
evaluation ID (e.g. `1780832` in
`https://hydra.nixos.org/eval/1780832`).
* Tag the release and upload the release artifacts to
[`releases.nixos.org`](https://releases.nixos.org/) and [Docker Hub](https://hub.docker.com/):
* Tag the release:
```console
$ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID>
$ IS_LATEST=1 ./maintainers/upload-release.pl --skip-docker --skip-s3 --project-root $PWD <EVAL-ID>
```
Note: `IS_LATEST=1` causes the `latest-release` branch to be
force-updated. This is used by the `nixos.org` website to get the
[latest Nix manual](https://nixos.org/manual/nixpkgs/unstable/).
TODO: This script requires the right AWS credentials. Document.
TODO: This script currently requires a
`/home/eelco/Dev/nix-pristine`.
* Trigger the [`upload-release.yml` workflow](https://github.com/NixOS/nix/actions/workflows/upload-release.yml) via `workflow_dispatch` trigger. At the top click `Run workflow` -> select the current release branch from `Use workflow from` -> fill in `Hydra evaluation ID` with `<EVAL-ID>` value from previous steps -> click `Run workflow`. Wait for the run to be approved by `NixOS/nix-team` (or bypass checks if warranted). Wait for the workflow to succeed.
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
@@ -127,6 +129,8 @@ release:
Commit and push this to the maintenance branch.
* Create a backport label.
* Bump the version of `master`:
```console
@@ -134,6 +138,7 @@ release:
$ git pull
$ NEW_VERSION=2.13.0
$ echo $NEW_VERSION > .version
$ ... edit .mergify.yml to add the previous version ...
$ git checkout -b bump-$NEW_VERSION
$ git commit -a -m 'Bump version'
$ git push --set-upstream origin bump-$NEW_VERSION
@@ -141,10 +146,6 @@ release:
Make a pull request and auto-merge it.
* Create a backport label.
* Add the new backport label to `.mergify.yml`.
* Post an [announcement on Discourse](https://discourse.nixos.org/c/announcements/8), including the contents of
`rl-$VERSION.md`.
@@ -177,16 +178,18 @@ release:
* Wait for the desired evaluation of the maintenance jobset to finish
building.
* Run
* Tag the release
```console
$ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID>
$ IS_LATEST=1 ./maintainers/upload-release.pl --skip-docker --skip-s3 --project-root $PWD <EVAL-ID>
```
Omit `IS_LATEST=1` when creating a point release that is not on the
most recent stable branch. This prevents `nixos.org` to going back
to an older release.
* Trigger the [`upload-release.yml` workflow](https://github.com/NixOS/nix/actions/workflows/upload-release.yml) via `workflow_dispatch` trigger. At the top click `Run workflow` -> select the current release branch from `Use workflow from` -> fill in `Hydra evaluation ID` with `<EVAL-ID>` value from previous steps -> click `Run workflow`. Wait for the run to be approved by `NixOS/nix-team` (or bypass checks if warranted). Wait for the workflow to succeed.
* Bump the version number of the release branch as above (e.g. to
`2.12.2`).

View File

@@ -1,7 +1,8 @@
#! /usr/bin/env nix-shell
#! nix-shell -i perl -p perl perlPackages.LWPUserAgent perlPackages.LWPProtocolHttps perlPackages.FileSlurp perlPackages.NetAmazonS3 gnupg1
#! nix-shell -i perl -p awscli2 perl perlPackages.LWPUserAgent perlPackages.LWPProtocolHttps perlPackages.FileSlurp perlPackages.NetAmazonS3 perlPackages.GetoptLongDescriptive gnupg1
use strict;
use Getopt::Long::Descriptive;
use Data::Dumper;
use File::Basename;
use File::Path;
@@ -13,7 +14,30 @@ use Net::Amazon::S3;
delete $ENV{'shell'}; # shut up a LWP::UserAgent.pm warning
my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n";
my ($opt, $usage) = describe_options(
'%c %o <eval-id>',
[ 'skip-docker', 'Skip Docker image upload' ],
[ 'skip-git', 'Skip Git tagging' ],
[ 'skip-s3', 'Skip S3 upload' ],
[ 'docker-owner=s', 'Docker image owner', { default => 'nixos/nix' } ],
[ 'project-root=s', 'Pristine git repository path' ],
[ 's3-endpoint=s', 'Custom S3 endpoint' ],
[ 's3-host=s', 'S3 host', { default => 's3-eu-west-1.amazonaws.com' } ],
[],
[ 'help|h', 'Show this help message', { shortcircuit => 1 } ],
[],
[ 'Environment variables:' ],
[ 'AWS_ACCESS_KEY_ID' ],
[ 'AWS_SECRET_ACCESS_KEY' ],
[ 'AWS_SESSION_TOKEN For OIDC' ],
[ 'IS_LATEST Set to "1" to mark as latest release' ],
);
print($usage->text), exit if $opt->help;
my $evalId = $ARGV[0] or do { print STDERR $usage->text; exit 1 };
die "--project-root is required unless --skip-git is specified\n" unless $opt->skip_git || $opt->project_root;
my $releasesBucketName = "nix-releases";
my $channelsBucketName = "nix-channels";
@@ -62,25 +86,38 @@ File::Path::make_path($narCache);
my $binaryCache = "https://cache.nixos.org/?local-nar-cache=$narCache";
# S3 setup.
my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'} or die "No AWS_ACCESS_KEY_ID given.";
my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'} or die "No AWS_SECRET_ACCESS_KEY given.";
my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'};
my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'};
my $aws_session_token = $ENV{'AWS_SESSION_TOKEN'};
my $s3 = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
retry => 1,
host => "s3-eu-west-1.amazonaws.com",
});
my ($s3, $releasesBucket, $s3_channels, $channelsBucket);
my $releasesBucket = $s3->bucket($releasesBucketName) or die;
unless ($opt->skip_s3) {
$aws_access_key_id or die "No AWS_ACCESS_KEY_ID given.";
$aws_secret_access_key or die "No AWS_SECRET_ACCESS_KEY given.";
my $s3_us = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
retry => 1,
});
$s3 = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
$aws_session_token ? (aws_session_token => $aws_session_token) : (),
retry => 1,
host => $opt->s3_host,
secure => ($opt->s3_endpoint && $opt->s3_endpoint =~ /^http:/) ? 0 : 1,
});
my $channelsBucket = $s3_us->bucket($channelsBucketName) or die;
$releasesBucket = $s3->bucket($releasesBucketName) or die;
$s3_channels = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
$aws_session_token ? (aws_session_token => $aws_session_token) : (),
retry => 1,
$opt->s3_endpoint ? (host => $opt->s3_host) : (),
$opt->s3_endpoint ? (secure => ($opt->s3_endpoint =~ /^http:/) ? 0 : 1) : (),
});
$channelsBucket = $s3_channels->bucket($channelsBucketName) or die;
}
sub getStorePath {
my ($jobName, $output) = @_;
@@ -115,11 +152,12 @@ sub copyManual {
File::Path::remove_tree("$tmpDir/manual.tmp", {safe => 1});
}
system("aws s3 sync '$tmpDir/manual' s3://$releasesBucketName/$releaseDir/manual") == 0
my $awsEndpoint = $opt->s3_endpoint ? "--endpoint-url " . $opt->s3_endpoint : "";
system("aws $awsEndpoint s3 sync '$tmpDir/manual' s3://$releasesBucketName/$releaseDir/manual") == 0
or die "syncing manual to S3\n";
}
copyManual;
copyManual unless $opt->skip_s3;
sub downloadFile {
my ($jobName, $productNr, $dstName) = @_;
@@ -158,30 +196,12 @@ sub downloadFile {
return $sha256_expected;
}
downloadFile("binaryTarball.i686-linux", "1");
downloadFile("binaryTarball.x86_64-linux", "1");
downloadFile("binaryTarball.aarch64-linux", "1");
downloadFile("binaryTarball.x86_64-darwin", "1");
downloadFile("binaryTarball.aarch64-darwin", "1");
eval {
downloadFile("binaryTarballCross.x86_64-linux.armv6l-unknown-linux-gnueabihf", "1");
};
warn "$@" if $@;
eval {
downloadFile("binaryTarballCross.x86_64-linux.armv7l-unknown-linux-gnueabihf", "1");
};
warn "$@" if $@;
eval {
downloadFile("binaryTarballCross.x86_64-linux.riscv64-unknown-linux-gnu", "1");
};
warn "$@" if $@;
downloadFile("installerScript", "1");
# Upload docker images to dockerhub.
# Upload docker images.
my $dockerManifest = "";
my $dockerManifestLatest = "";
my $haveDocker = 0;
unless ($opt->skip_docker) {
for my $platforms (["x86_64-linux", "amd64"], ["aarch64-linux", "arm64"]) {
my $system = $platforms->[0];
my $dockerPlatform = $platforms->[1];
@@ -195,8 +215,8 @@ for my $platforms (["x86_64-linux", "amd64"], ["aarch64-linux", "arm64"]) {
print STDERR "loading docker image for $dockerPlatform...\n";
system("docker load -i $tmpDir/$fn") == 0 or die;
my $tag = "nixos/nix:$version-$dockerPlatform";
my $latestTag = "nixos/nix:latest-$dockerPlatform";
my $tag = $opt->docker_owner . ":$version-$dockerPlatform";
my $latestTag = $opt->docker_owner . ":latest-$dockerPlatform";
print STDERR "tagging $version docker image for $dockerPlatform...\n";
system("docker tag nix:$version $tag") == 0 or die;
@@ -219,68 +239,94 @@ for my $platforms (["x86_64-linux", "amd64"], ["aarch64-linux", "arm64"]) {
}
if ($haveDocker) {
my $dockerOwner = $opt->docker_owner;
print STDERR "creating multi-platform docker manifest...\n";
system("docker manifest rm nixos/nix:$version");
system("docker manifest create nixos/nix:$version $dockerManifest") == 0 or die;
system("docker manifest rm $dockerOwner:$version");
system("docker manifest create $dockerOwner:$version $dockerManifest") == 0 or die;
if ($isLatest) {
print STDERR "creating latest multi-platform docker manifest...\n";
system("docker manifest rm nixos/nix:latest");
system("docker manifest create nixos/nix:latest $dockerManifestLatest") == 0 or die;
system("docker manifest rm $dockerOwner:latest");
system("docker manifest create $dockerOwner:latest $dockerManifestLatest") == 0 or die;
}
print STDERR "pushing multi-platform docker manifest...\n";
system("docker manifest push nixos/nix:$version") == 0 or die;
system("docker manifest push $dockerOwner:$version") == 0 or die;
if ($isLatest) {
print STDERR "pushing latest multi-platform docker manifest...\n";
system("docker manifest push nixos/nix:latest") == 0 or die;
system("docker manifest push $dockerOwner:latest") == 0 or die;
}
}
}
# Upload nix-fallback-paths.nix.
write_file("$tmpDir/fallback-paths.nix",
"{\n" .
" x86_64-linux = \"" . getStorePath("build.nix-everything.x86_64-linux") . "\";\n" .
" i686-linux = \"" . getStorePath("build.nix-everything.i686-linux") . "\";\n" .
" aarch64-linux = \"" . getStorePath("build.nix-everything.aarch64-linux") . "\";\n" .
" riscv64-linux = \"" . getStorePath("buildCross.nix-everything.riscv64-unknown-linux-gnu.x86_64-linux") . "\";\n" .
" x86_64-darwin = \"" . getStorePath("build.nix-everything.x86_64-darwin") . "\";\n" .
" aarch64-darwin = \"" . getStorePath("build.nix-everything.aarch64-darwin") . "\";\n" .
"}\n");
# Upload release files to S3.
for my $fn (glob "$tmpDir/*") {
my $name = basename($fn);
next if $name eq "manual";
my $dstKey = "$releaseDir/" . $name;
unless (defined $releasesBucket->head_key($dstKey)) {
print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n";
unless ($opt->skip_s3) {
downloadFile("binaryTarball.i686-linux", "1");
downloadFile("binaryTarball.x86_64-linux", "1");
downloadFile("binaryTarball.aarch64-linux", "1");
downloadFile("binaryTarball.x86_64-darwin", "1");
downloadFile("binaryTarball.aarch64-darwin", "1");
eval {
downloadFile("binaryTarballCross.x86_64-linux.armv6l-unknown-linux-gnueabihf", "1");
};
warn "$@" if $@;
eval {
downloadFile("binaryTarballCross.x86_64-linux.armv7l-unknown-linux-gnueabihf", "1");
};
warn "$@" if $@;
eval {
downloadFile("binaryTarballCross.x86_64-linux.riscv64-unknown-linux-gnu", "1");
};
warn "$@" if $@;
downloadFile("installerScript", "1");
my $configuration = ();
$configuration->{content_type} = "application/octet-stream";
# Upload nix-fallback-paths.nix.
write_file("$tmpDir/fallback-paths.nix",
"{\n" .
" x86_64-linux = \"" . getStorePath("build.nix-everything.x86_64-linux") . "\";\n" .
" i686-linux = \"" . getStorePath("build.nix-everything.i686-linux") . "\";\n" .
" aarch64-linux = \"" . getStorePath("build.nix-everything.aarch64-linux") . "\";\n" .
" riscv64-linux = \"" . getStorePath("buildCross.nix-everything.riscv64-unknown-linux-gnu.x86_64-linux") . "\";\n" .
" x86_64-darwin = \"" . getStorePath("build.nix-everything.x86_64-darwin") . "\";\n" .
" aarch64-darwin = \"" . getStorePath("build.nix-everything.aarch64-darwin") . "\";\n" .
"}\n");
if ($fn =~ /.sha256|install|\.nix$/) {
$configuration->{content_type} = "text/plain";
for my $fn (glob "$tmpDir/*") {
my $name = basename($fn);
next if $name eq "manual";
my $dstKey = "$releaseDir/" . $name;
unless (defined $releasesBucket->head_key($dstKey)) {
print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n";
my $configuration = ();
$configuration->{content_type} = "application/octet-stream";
if ($fn =~ /.sha256|install|\.nix$/) {
$configuration->{content_type} = "text/plain";
}
$releasesBucket->add_key_filename($dstKey, $fn, $configuration)
or die $releasesBucket->err . ": " . $releasesBucket->errstr;
}
$releasesBucket->add_key_filename($dstKey, $fn, $configuration)
or die $releasesBucket->err . ": " . $releasesBucket->errstr;
}
# Update the "latest" symlink.
$channelsBucket->add_key(
"nix-latest/install", "",
{ "x-amz-website-redirect-location" => "https://releases.nixos.org/$releaseDir/install" })
or die $channelsBucket->err . ": " . $channelsBucket->errstr
if $isLatest;
}
# Update the "latest" symlink.
$channelsBucket->add_key(
"nix-latest/install", "",
{ "x-amz-website-redirect-location" => "https://releases.nixos.org/$releaseDir/install" })
or die $channelsBucket->err . ": " . $channelsBucket->errstr
if $isLatest;
# Tag the release in Git.
chdir("/home/eelco/Dev/nix-pristine") or die;
system("git remote update origin") == 0 or die;
system("git tag --force --sign $version $nixRev -m 'Tagging release $version'") == 0 or die;
system("git push --tags") == 0 or die;
system("git push --force-with-lease origin $nixRev:refs/heads/latest-release") == 0 or die if $isLatest;
unless ($opt->skip_git) {
chdir($opt->project_root) or die "Cannot chdir to " . $opt->project_root . ": $!";
system("git remote update origin") == 0 or die;
system("git tag --force --sign $version $nixRev -m 'Tagging release $version'") == 0 or die;
system("git push origin refs/tags/$version") == 0 or die;
system("git push --force-with-lease origin $nixRev:refs/heads/latest-release") == 0 or die if $isLatest;
}
File::Path::remove_tree($narCache, {safe => 1});
File::Path::remove_tree($tmpDir, {safe => 1});

View File

@@ -41,8 +41,10 @@ subproject('libexpr-c')
subproject('libflake-c')
subproject('libmain-c')
asan_enabled = 'address' in get_option('b_sanitize')
# Language Bindings
if get_option('bindings') and not meson.is_cross_build()
if get_option('bindings') and not meson.is_cross_build() and not asan_enabled
subproject('perl')
endif

View File

@@ -1,3 +1,4 @@
# shellcheck shell=bash
function _complete_nix {
local -a words
local cword cur

View File

@@ -1,3 +1,4 @@
# shellcheck disable=all
function _nix_complete
# Get the current command up to a cursor.
# - Behaves correctly even with pipes and nested in commands like env.

View File

@@ -1,4 +1,5 @@
#compdef nix
# shellcheck disable=all
function _nix() {
local ifs_bk="$IFS"

View File

@@ -0,0 +1,12 @@
asan_test_options_env = {
'ASAN_OPTIONS' : 'abort_on_error=1:print_summary=1:detect_leaks=0',
}
# Clang gets grumpy about missing libasan symbols if -shared-libasan is not
# passed when building shared libs, at least on Linux
if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefined' in get_option(
'b_sanitize',
))
add_project_link_arguments('-shared-libasan', language : 'cpp')
endif

View File

@@ -0,0 +1,32 @@
can_wrap_assert_fail_test_code = '''
#include <cstdlib>
#include <cassert>
int main()
{
assert(0);
}
extern "C" void * __real___assert_fail(const char *, const char *, unsigned int, const char *);
extern "C" void *
__wrap___assert_fail(const char *, const char *, unsigned int, const char *)
{
return __real___assert_fail(nullptr, nullptr, 0, nullptr);
}
'''
wrap_assert_fail_args = [ '-Wl,--wrap=__assert_fail' ]
can_wrap_assert_fail = cxx.links(
can_wrap_assert_fail_test_code,
args : wrap_assert_fail_args,
name : 'linker can wrap __assert_fail',
)
if can_wrap_assert_fail
deps_other += declare_dependency(
sources : 'wrap-assert-fail.cc',
link_args : wrap_assert_fail_args,
)
endif

View File

@@ -0,0 +1,17 @@
#include "nix/util/error.hh"
#include <cstdio>
#include <cstdlib>
#include <cinttypes>
#include <string_view>
extern "C" [[noreturn]] void __attribute__((weak))
__wrap___assert_fail(const char * assertion, const char * file, unsigned int line, const char * function)
{
char buf[512];
int n =
snprintf(buf, sizeof(buf), "Assertion '%s' failed in %s at %s:%" PRIuLEAST32, assertion, function, file, line);
if (n < 0)
nix::panic("Assertion failed and could not format error message");
nix::panic(std::string_view(buf, std::min(static_cast<int>(sizeof(buf)), n)));
}

View File

@@ -5,6 +5,15 @@ if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
deps_private += dependency('threads')
endif
if host_machine.system() == 'cygwin'
# -std=gnu on cygwin defines 'unix', which conflicts with the namespace
add_project_arguments(
'-D_POSIX_C_SOURCE=200809L',
'-D_GNU_SOURCE',
language : 'cpp',
)
endif
add_project_arguments(
'-Wdeprecated-copy',
'-Werror=suggest-override',
@@ -33,10 +42,27 @@ if cxx.get_id() == 'clang'
add_project_arguments('-fpch-instantiate-templates', language : 'cpp')
endif
# Clang gets grumpy about missing libasan symbols if -shared-libasan is not
# passed when building shared libs, at least on Linux
if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefined' in get_option(
'b_sanitize',
))
add_project_link_arguments('-shared-libasan', language : 'cpp')
# Detect if we're using libstdc++ (GCC's standard library)
# libstdc++ uses Intel TBB as backend for C++17 parallel algorithms when <execution> is included.
# boost::concurrent_flat_map includes <execution>, which would require linking against TBB.
# Since we don't actually use parallel algorithms, disable the TBB backend to avoid the dependency.
# TBB is a dependency of blake3 and leaking into our build environment.
is_using_libstdcxx = cxx.compiles(
'''
#include <ciso646>
#ifndef __GLIBCXX__
#error "not libstdc++"
#endif
int main() { return 0; }
''',
name : 'using libstdc++',
)
if is_using_libstdcxx
add_project_arguments('-D_GLIBCXX_USE_TBB_PAR_BACKEND=0', language : 'cpp')
endif
# Darwin ld doesn't like "X.Y.ZpreABCD+W"
nix_soversion = meson.project_version().split('+')[0].split('pre')[0]
subdir('assert-fail')

View File

@@ -3,6 +3,6 @@
# This is needed for std::atomic on some platforms
# We did not manage to test this reliably on all platforms, so we hardcode
# it for now.
if host_machine.cpu_family() == 'arm'
if host_machine.cpu_family() in [ 'arm', 'ppc' ]
deps_other += cxx.find_library('atomic')
endif

View File

@@ -164,6 +164,24 @@ let
};
mesonLibraryLayer = finalAttrs: prevAttrs: {
preConfigure =
let
interpositionFlags = [
"-fno-semantic-interposition"
"-Wl,-Bsymbolic-functions"
];
in
# NOTE: By default GCC disables interprocedular optimizations (in particular inlining) for
# position-independent code and thus shared libraries.
# Since LD_PRELOAD tricks aren't worth losing out on optimizations, we disable it for good.
# This is not the case for Clang, where inlining is done by default even without -fno-semantic-interposition.
# https://reviews.llvm.org/D102453
# https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup
prevAttrs.preConfigure or ""
+ lib.optionalString stdenv.cc.isGNU ''
export CFLAGS="''${CFLAGS:-} ${toString interpositionFlags}"
export CXXFLAGS="''${CXXFLAGS:-} ${toString interpositionFlags}"
'';
outputs = prevAttrs.outputs or [ "out" ] ++ [ "dev" ];
};

View File

@@ -10,27 +10,8 @@
stdenv,
}:
let
prevStdenv = stdenv;
in
let
inherit (pkgs) lib;
stdenv = if prevStdenv.isDarwin && prevStdenv.isx86_64 then darwinStdenv else prevStdenv;
# Fix the following error with the default x86_64-darwin SDK:
#
# error: aligned allocation function of type 'void *(std::size_t, std::align_val_t)' is only available on macOS 10.13 or newer
#
# Despite the use of the 10.13 deployment target here, the aligned
# allocation function Clang uses with this setting actually works
# all the way back to 10.6.
# NOTE: this is not just a version constraint, but a request to make Darwin
# provide this version level of support. Removing this minimum version
# request will regress the above error.
darwinStdenv = pkgs.overrideSDK prevStdenv { darwinMinVersion = "10.13"; };
in
scope: {
inherit stdenv;
@@ -73,9 +54,24 @@ scope: {
nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ pkgs.buildPackages.bmake ];
postInstall =
lib.replaceStrings [ "lowdown.so.1" "lowdown.1.dylib" ] [ "lowdown.so.2" "lowdown.2.dylib" ]
prevAttrs.postInstall;
(prevAttrs.postInstall or "");
});
# TODO: Remove this when https://github.com/NixOS/nixpkgs/pull/442682 is included in a stable release
toml11 =
if lib.versionAtLeast pkgs.toml11.version "4.4.0" then
pkgs.toml11
else
pkgs.toml11.overrideAttrs rec {
version = "4.4.0";
src = pkgs.fetchFromGitHub {
owner = "ToruNiina";
repo = "toml11";
tag = "v${version}";
hash = "sha256-sgWKYxNT22nw376ttGsTdg0AMzOwp8QH3E8mx0BZJTQ=";
};
};
# TODO Hack until https://github.com/NixOS/nixpkgs/issues/45462 is fixed.
boost =
(pkgs.boost.override {

View File

@@ -118,6 +118,7 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
modular.pre-commit.settings.package
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
pkgs.buildPackages.nixfmt-rfc-style
pkgs.buildPackages.shellcheck
pkgs.buildPackages.gdb
]
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (

View File

@@ -55,18 +55,22 @@ readonly NIX_INSTALLED_NIX="@nix@"
readonly NIX_INSTALLED_CACERT="@cacert@"
#readonly NIX_INSTALLED_NIX="/nix/store/j8dbv5w6jl34caywh2ygdy88knx1mdf7-nix-2.3.6"
#readonly NIX_INSTALLED_CACERT="/nix/store/7dxhzymvy330i28ii676fl1pqwcahv2f-nss-cacert-3.49.2"
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
EXTRACTED_NIX_PATH="$(dirname "$0")"
readonly EXTRACTED_NIX_PATH
# allow to override identity change command
readonly NIX_BECOME=${NIX_BECOME:-sudo}
NIX_BECOME=${NIX_BECOME:-sudo}
readonly NIX_BECOME
readonly ROOT_HOME=~root
ROOT_HOME=~root
readonly ROOT_HOME
if [ -t 0 ] && [ -z "${NIX_INSTALLER_YES:-}" ]; then
readonly IS_HEADLESS='no'
IS_HEADLESS='no'
else
readonly IS_HEADLESS='yes'
IS_HEADLESS='yes'
fi
readonly IS_HEADLESS
headless() {
if [ "$IS_HEADLESS" = "yes" ]; then
@@ -156,6 +160,7 @@ EOF
}
nix_user_for_core() {
# shellcheck disable=SC2059
printf "$NIX_BUILD_USER_NAME_TEMPLATE" "$1"
}
@@ -381,10 +386,12 @@ _sudo() {
# Ensure that $TMPDIR exists if defined.
if [[ -n "${TMPDIR:-}" ]] && [[ ! -d "${TMPDIR:-}" ]]; then
# shellcheck disable=SC2174
mkdir -m 0700 -p "${TMPDIR:-}"
fi
readonly SCRATCH=$(mktemp -d)
SCRATCH=$(mktemp -d)
readonly SCRATCH
finish_cleanup() {
rm -rf "$SCRATCH"
}
@@ -677,7 +684,8 @@ create_directories() {
# hiding behind || true, and the general state
# should be one the user can repair once they
# figure out where chown is...
local get_chr_own="$(PATH="$(getconf PATH 2>/dev/null)" command -vp chown)"
local get_chr_own
get_chr_own="$(PATH="$(getconf PATH 2>/dev/null)" command -vp chown)"
if [[ -z "$get_chr_own" ]]; then
get_chr_own="$(command -v chown)"
fi
@@ -915,9 +923,11 @@ configure_shell_profile() {
fi
if [ -e "$profile_target" ]; then
shell_source_lines \
| _sudo "extend your $profile_target with nix-daemon settings" \
tee -a "$profile_target"
{
shell_source_lines
cat "$profile_target"
} | _sudo "extend your $profile_target with nix-daemon settings" \
tee "$profile_target"
fi
done
@@ -1013,6 +1023,7 @@ main() {
# Set profile targets after OS-specific scripts are loaded
if command -v poly_configure_default_profile_targets > /dev/null 2>&1; then
# shellcheck disable=SC2207
PROFILE_TARGETS=($(poly_configure_default_profile_targets))
else
PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc")

View File

@@ -39,7 +39,7 @@ create_systemd_proxy_env() {
vars="http_proxy https_proxy ftp_proxy all_proxy no_proxy HTTP_PROXY HTTPS_PROXY FTP_PROXY ALL_PROXY NO_PROXY"
for v in $vars; do
if [ "x${!v:-}" != "x" ]; then
echo "Environment=${v}=$(escape_systemd_env ${!v})"
echo "Environment=${v}=$(escape_systemd_env "${!v}")"
fi
done
}

View File

@@ -83,12 +83,22 @@ nlohmann::json SingleBuiltPath::Built::toJSON(const StoreDirConfig & store) cons
nlohmann::json SingleBuiltPath::toJSON(const StoreDirConfig & store) const
{
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
return std::visit(
overloaded{
[&](const SingleBuiltPath::Opaque & o) -> nlohmann::json { return store.printStorePath(o.path); },
[&](const SingleBuiltPath::Built & b) { return b.toJSON(store); },
},
raw());
}
nlohmann::json BuiltPath::toJSON(const StoreDirConfig & store) const
{
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
return std::visit(
overloaded{
[&](const BuiltPath::Opaque & o) -> nlohmann::json { return store.printStorePath(o.path); },
[&](const BuiltPath::Built & b) { return b.toJSON(store); },
},
raw());
}
RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const

View File

@@ -2,6 +2,7 @@
#include <nlohmann/json.hpp>
#include "nix/cmd/command.hh"
#include "nix/cmd/legacy.hh"
#include "nix/cmd/markdown.hh"
#include "nix/store/store-open.hh"
#include "nix/store/local-fs-store.hh"
@@ -14,6 +15,18 @@
namespace nix {
RegisterCommand::Commands & RegisterCommand::commands()
{
static RegisterCommand::Commands commands;
return commands;
}
RegisterLegacyCommand::Commands & RegisterLegacyCommand::commands()
{
static RegisterLegacyCommand::Commands commands;
return commands;
}
nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
{
nix::Commands res;

View File

@@ -286,11 +286,7 @@ struct RegisterCommand
{
typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands;
static Commands & commands()
{
static Commands commands;
return commands;
}
static Commands & commands();
RegisterCommand(std::vector<std::string> && name, std::function<ref<Command>()> command)
{

View File

@@ -13,11 +13,7 @@ struct RegisterLegacyCommand
{
typedef std::map<std::string, MainFunction> Commands;
static Commands & commands()
{
static Commands commands;
return commands;
}
static Commands & commands();
RegisterLegacyCommand(const std::string & name, MainFunction fun)
{

View File

@@ -105,8 +105,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
std::optional<NixInt::Inner> priority;
if (attr->maybeGetAttr(state->sOutputSpecified)) {
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
if (attr->maybeGetAttr(state->s.outputSpecified)) {
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
if (auto aPriority = aMeta->maybeGetAttr("priority"))
priority = aPriority->getInt().value;
}
@@ -119,12 +119,12 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
overloaded{
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
StringSet outputsToInstall;
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
if (auto aOutputSpecified = attr->maybeGetAttr(state->s.outputSpecified)) {
if (aOutputSpecified->getBool()) {
if (auto aOutputName = attr->maybeGetAttr("outputName"))
outputsToInstall = {aOutputName->getString()};
}
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
for (auto & s : aOutputsToInstall->getListOfStrings())
outputsToInstall.insert(s);

View File

@@ -178,10 +178,16 @@ MixFlakeOptions::MixFlakeOptions()
for (auto & [inputName, input] : flake.lockFile.root->inputs) {
auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes
if (auto input3 = std::dynamic_pointer_cast<const flake::LockedNode>(input2)) {
fetchers::Attrs extraAttrs;
if (!input3->lockedRef.subdir.empty()) {
extraAttrs["dir"] = input3->lockedRef.subdir;
}
overrideRegistry(
fetchers::Input::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", inputName}}),
input3->lockedRef.input,
{});
extraAttrs);
}
}
}},
@@ -598,28 +604,28 @@ std::vector<BuiltPathWithResult> Installable::build(
static void throwBuildErrors(std::vector<KeyedBuildResult> & buildResults, const Store & store)
{
std::vector<KeyedBuildResult> failed;
std::vector<std::pair<const KeyedBuildResult *, const KeyedBuildResult::Failure *>> failed;
for (auto & buildResult : buildResults) {
if (!buildResult.success()) {
failed.push_back(buildResult);
if (auto * failure = buildResult.tryGetFailure()) {
failed.push_back({&buildResult, failure});
}
}
auto failedResult = failed.begin();
if (failedResult != failed.end()) {
if (failed.size() == 1) {
failedResult->rethrow();
failedResult->second->rethrow();
} else {
StringSet failedPaths;
for (; failedResult != failed.end(); failedResult++) {
if (!failedResult->errorMsg.empty()) {
if (!failedResult->second->errorMsg.empty()) {
logError(
ErrorInfo{
.level = lvlError,
.msg = failedResult->errorMsg,
.msg = failedResult->second->errorMsg,
});
}
failedPaths.insert(failedResult->path.to_string(store));
failedPaths.insert(failedResult->first->path.to_string(store));
}
throw Error("build of %s failed", concatStringsSep(", ", quoteStrings(failedPaths)));
}
@@ -689,12 +695,14 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
auto buildResults = store->buildPathsWithResults(pathsToBuild, bMode, evalStore);
throwBuildErrors(buildResults, *store);
for (auto & buildResult : buildResults) {
// If we didn't throw, they must all be sucesses
auto & success = std::get<nix::BuildResult::Success>(buildResult.inner);
for (auto & aux : backmap[buildResult.path]) {
std::visit(
overloaded{
[&](const DerivedPath::Built & bfd) {
std::map<std::string, StorePath> outputs;
for (auto & [outputName, realisation] : buildResult.builtOutputs)
for (auto & [outputName, realisation] : success.builtOutputs)
outputs.emplace(outputName, realisation.outPath);
res.push_back(
{aux.installable,

View File

@@ -67,6 +67,7 @@ config_priv_h = configure_file(
)
subdir('nix-meson-build-support/common')
subdir('nix-meson-build-support/asan-options')
sources = files(
'built-path.cc',
@@ -95,6 +96,7 @@ this_library = library(
'nixcmd',
sources,
config_priv_h,
soversion : nix_soversion,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args : linker_export_flags,

View File

@@ -669,7 +669,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
ss << "No documentation found.\n\n";
}
auto markdown = toView(ss);
auto markdown = ss.view();
logger->cout(trim(renderMarkdownToTerminal(markdown)));
} else
@@ -760,7 +760,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
void NixRepl::initEnv()
{
env = &state->allocEnv(envSize);
env = &state->mem.allocEnv(envSize);
env->up = &state->baseEnv;
displ = 0;
staticEnv->vars.clear();
@@ -869,14 +869,8 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
Expr * NixRepl::parseString(std::string s)
{
return state->parseExprFromString(std::move(s), state->rootPath("."), staticEnv);
}
void NixRepl::evalString(std::string s, Value & v)
{
Expr * e;
try {
e = parseString(s);
return state->parseExprFromString(std::move(s), state->rootPath("."), staticEnv);
} catch (ParseError & e) {
if (e.msg().find("unexpected end of file") != std::string::npos)
// For parse errors on incomplete input, we continue waiting for the next line of
@@ -885,6 +879,11 @@ void NixRepl::evalString(std::string s, Value & v)
else
throw;
}
}
void NixRepl::evalString(std::string s, Value & v)
{
Expr * e = parseString(s);
e->eval(*state, *env, v);
state->forceValue(v, v.determinePos(noPos));
}

View File

@@ -28,6 +28,7 @@ deps_public_maybe_subproject = [
subdir('nix-meson-build-support/subprojects')
subdir('nix-meson-build-support/common')
subdir('nix-meson-build-support/asan-options')
sources = files(
'nix_api_expr.cc',
@@ -50,6 +51,7 @@ subdir('nix-meson-build-support/windows-version')
this_library = library(
'nixexprc',
sources,
soversion : nix_soversion,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args : linker_export_flags,

View File

@@ -16,7 +16,7 @@
#include "nix_api_util_internal.h"
#if NIX_USE_BOEHMGC
# include <mutex>
# include <boost/unordered/concurrent_flat_map.hpp>
#endif
/**
@@ -40,6 +40,8 @@ static T * unsafe_new_with_self(F && init)
return new (p) T(init(static_cast<T *>(p)));
}
extern "C" {
nix_err nix_libexpr_init(nix_c_context * context)
{
if (context)
@@ -135,7 +137,7 @@ nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Sto
void nix_eval_state_builder_free(nix_eval_state_builder * builder)
{
delete builder;
operator delete(builder, static_cast<std::align_val_t>(alignof(nix_eval_state_builder)));
}
nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_builder * builder)
@@ -201,32 +203,24 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
void nix_state_free(EvalState * state)
{
delete state;
operator delete(state, static_cast<std::align_val_t>(alignof(EvalState)));
}
#if NIX_USE_BOEHMGC
std::unordered_map<
boost::concurrent_flat_map<
const void *,
unsigned int,
std::hash<const void *>,
std::equal_to<const void *>,
traceable_allocator<std::pair<const void * const, unsigned int>>>
nix_refcounts;
std::mutex nix_refcount_lock;
nix_refcounts{};
nix_err nix_gc_incref(nix_c_context * context, const void * p)
{
if (context)
context->last_err_code = NIX_OK;
try {
std::scoped_lock lock(nix_refcount_lock);
auto f = nix_refcounts.find(p);
if (f != nix_refcounts.end()) {
f->second++;
} else {
nix_refcounts[p] = 1;
}
nix_refcounts.insert_or_visit({p, 1}, [](auto & kv) { kv.second++; });
}
NIXC_CATCH_ERRS
}
@@ -237,12 +231,12 @@ nix_err nix_gc_decref(nix_c_context * context, const void * p)
if (context)
context->last_err_code = NIX_OK;
try {
std::scoped_lock lock(nix_refcount_lock);
auto f = nix_refcounts.find(p);
if (f != nix_refcounts.end()) {
if (--f->second == 0)
nix_refcounts.erase(f);
} else
bool fail = true;
nix_refcounts.erase_if(p, [&](auto & kv) {
fail = false;
return !--kv.second;
});
if (fail)
throw std::runtime_error("nix_gc_decref: object was not referenced");
}
NIXC_CATCH_ERRS
@@ -287,3 +281,5 @@ void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * o
GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
#endif
}
} // extern "C"

View File

@@ -8,6 +8,8 @@
#include "nix_api_value.h"
#include "nix/expr/search-path.hh"
extern "C" {
struct nix_eval_state_builder
{
nix::ref<nix::Store> store;
@@ -61,4 +63,6 @@ struct nix_realised_string
std::vector<StorePath> storePaths;
};
} // extern "C"
#endif // NIX_API_EXPR_INTERNAL_H

View File

@@ -14,6 +14,8 @@
#include <nlohmann/json.hpp>
extern "C" {
void nix_set_string_return(nix_string_return * str, const char * c)
{
str->str = c;
@@ -40,6 +42,8 @@ nix_err nix_external_add_string_context(nix_c_context * context, nix_string_cont
NIXC_CATCH_ERRS
}
} // extern "C"
class NixCExternalValue : public nix::ExternalValueBase
{
NixCExternalValueDesc & desc;
@@ -170,6 +174,8 @@ public:
virtual ~NixCExternalValue() override {};
};
extern "C" {
ExternalValue * nix_create_external_value(nix_c_context * context, NixCExternalValueDesc * desc, void * v)
{
if (context)
@@ -198,3 +204,5 @@ void * nix_get_external_value_content(nix_c_context * context, ExternalValue * b
}
NIXC_CATCH_ERRS_NULL
}
} // extern "C"

View File

@@ -111,6 +111,8 @@ static void nix_c_primop_wrapper(
v = vTmp;
}
extern "C" {
PrimOp * nix_alloc_primop(
nix_c_context * context,
PrimOpFun fun,
@@ -324,6 +326,10 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
try {
auto & v = check_value_in(value);
assert(v.type() == nix::nList);
if (ix >= v.listSize()) {
nix_set_err_msg(context, NIX_ERR_KEY, "list index out of bounds");
return nullptr;
}
auto * p = v.listView()[ix];
nix_gc_incref(nullptr, p);
if (p != nullptr)
@@ -333,6 +339,26 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
NIXC_CATCH_ERRS_NULL
}
nix_value *
nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
assert(v.type() == nix::nList);
if (ix >= v.listSize()) {
nix_set_err_msg(context, NIX_ERR_KEY, "list index out of bounds");
return nullptr;
}
auto * p = v.listView()[ix];
nix_gc_incref(nullptr, p);
// Note: intentionally NOT calling forceValue() to keep the element lazy
return as_nix_value_ptr(p);
}
NIXC_CATCH_ERRS_NULL
}
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
{
if (context)
@@ -353,6 +379,27 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
NIXC_CATCH_ERRS_NULL
}
nix_value *
nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs()->get(s);
if (attr) {
nix_gc_incref(nullptr, attr->value);
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
return as_nix_value_ptr(attr->value);
}
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
return nullptr;
}
NIXC_CATCH_ERRS_NULL
}
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
{
if (context)
@@ -369,13 +416,28 @@ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalS
NIXC_CATCH_ERRS_RES(false);
}
nix_value * nix_get_attr_byidx(
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name)
static void collapse_attrset_layer_chain_if_needed(nix::Value & v, EvalState * state)
{
auto & attrs = *v.attrs();
if (attrs.isLayered()) {
auto bindings = state->state.buildBindings(attrs.size());
std::ranges::copy(attrs, std::back_inserter(bindings));
v.mkAttrs(bindings);
}
}
nix_value *
nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
collapse_attrset_layer_chain_if_needed(v, state);
if (i >= v.attrs()->size()) {
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds");
return nullptr;
}
const nix::Attr & a = (*v.attrs())[i];
*name = state->state.symbols[a.name].c_str();
nix_gc_incref(nullptr, a.value);
@@ -385,13 +447,38 @@ nix_value * nix_get_attr_byidx(
NIXC_CATCH_ERRS_NULL
}
const char *
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i)
nix_value * nix_get_attr_byidx_lazy(
nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
collapse_attrset_layer_chain_if_needed(v, state);
if (i >= v.attrs()->size()) {
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds (Nix C API contract violation)");
return nullptr;
}
const nix::Attr & a = (*v.attrs())[i];
*name = state->state.symbols[a.name].c_str();
nix_gc_incref(nullptr, a.value);
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
return as_nix_value_ptr(a.value);
}
NIXC_CATCH_ERRS_NULL
}
const char * nix_get_attr_name_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto & v = check_value_in(value);
collapse_attrset_layer_chain_if_needed(v, state);
if (i >= v.attrs()->size()) {
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds (Nix C API contract violation)");
return nullptr;
}
const nix::Attr & a = (*v.attrs())[i];
return state->state.symbols[a.name].c_str();
}
@@ -592,7 +679,7 @@ nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * b
context->last_err_code = NIX_OK;
try {
auto & v = check_value_not_null(value);
nix::Symbol s = bb->builder.state.symbols.create(name);
nix::Symbol s = bb->builder.symbols.get().create(name);
bb->builder.insert(s, &v);
}
NIXC_CATCH_ERRS
@@ -651,3 +738,5 @@ const StorePath * nix_realised_string_get_store_path(nix_realised_string * s, si
{
return &s->storePaths[i];
}
} // extern "C"

View File

@@ -265,10 +265,25 @@ ExternalValue * nix_get_external(nix_c_context * context, nix_value * value);
*/
nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
/** @brief Get an attr by name
/** @brief Get the ix'th element of a list without forcing evaluation of the element
*
* Returns the list element without forcing its evaluation, allowing access to lazy values.
* The list value itself must already be evaluated.
*
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect (must be an evaluated list)
* @param[in] state nix evaluator state
* @param[in] ix list element to get
* @return value, NULL in case of errors
*/
nix_value *
nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
/** @brief Get an attr by name
*
* Use nix_gc_decref when you're done with the pointer
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect
* @param[in] state nix evaluator state
* @param[in] name attribute name
@@ -276,6 +291,21 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
*/
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
/** @brief Get an attribute value by attribute name, without forcing evaluation of the attribute's value
*
* Returns the attribute value without forcing its evaluation, allowing access to lazy values.
* The attribute set value itself must already be evaluated.
*
* Use nix_gc_decref when you're done with the pointer
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect (must be an evaluated attribute set)
* @param[in] state nix evaluator state
* @param[in] name attribute name
* @return value, NULL in case of errors
*/
nix_value *
nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
/** @brief Check if an attribute name exists on a value
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect
@@ -285,11 +315,21 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
*/
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
/** @brief Get an attribute by index in the sorted bindings
/** @brief Get an attribute by index
*
* Also gives you the name.
*
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
* Attributes are returned in an unspecified order which is NOT suitable for
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
* is responsible for sorting the attributes or storing them in an ordered map to
* ensure deterministic behavior in your application.
*
* @note When Nix does sort attributes, which it does for virtually all intermediate
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
* applying this same ordering for consistency.
*
* Use nix_gc_decref when you're done with the pointer
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect
* @param[in] state nix evaluator state
@@ -297,12 +337,50 @@ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalS
* @param[out] name will store a pointer to the attribute name
* @return value, NULL in case of errors
*/
nix_value * nix_get_attr_byidx(
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name);
nix_value *
nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name);
/** @brief Get an attribute name by index in the sorted bindings
/** @brief Get an attribute by index, without forcing evaluation of the attribute's value
*
* Useful when you want the name but want to avoid evaluation.
* Also gives you the name.
*
* Returns the attribute value without forcing its evaluation, allowing access to lazy values.
* The attribute set value itself must already have been evaluated.
*
* Attributes are returned in an unspecified order which is NOT suitable for
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
* is responsible for sorting the attributes or storing them in an ordered map to
* ensure deterministic behavior in your application.
*
* @note When Nix does sort attributes, which it does for virtually all intermediate
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
* applying this same ordering for consistency.
*
* Use nix_gc_decref when you're done with the pointer
* @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect (must be an evaluated attribute set)
* @param[in] state nix evaluator state
* @param[in] i attribute index
* @param[out] name will store a pointer to the attribute name
* @return value, NULL in case of errors
*/
nix_value * nix_get_attr_byidx_lazy(
nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name);
/** @brief Get an attribute name by index
*
* Returns the attribute name without forcing evaluation of the attribute's value.
*
* Attributes are returned in an unspecified order which is NOT suitable for
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
* is responsible for sorting the attributes or storing them in an ordered map to
* ensure deterministic behavior in your application.
*
* @note When Nix does sort attributes, which it does for virtually all intermediate
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
* applying this same ordering for consistency.
*
* Owned by the nix EvalState
* @param[out] context Optional, stores error information
@@ -311,8 +389,7 @@ nix_value * nix_get_attr_byidx(
* @param[in] i attribute index
* @return name, NULL in case of errors
*/
const char *
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i);
const char * nix_get_attr_name_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i);
/**@}*/
/** @name Initializers

View File

@@ -26,11 +26,20 @@ public:
}
protected:
LibExprTest()
LibExprTest(ref<Store> store, auto && makeEvalSettings)
: LibStoreTest()
, evalSettings(makeEvalSettings(readOnlyMode))
, state({}, store, fetchSettings, evalSettings, nullptr)
{
evalSettings.nixPath = {};
}
LibExprTest()
: LibExprTest(openStore("dummy://"), [](bool & readOnlyMode) {
EvalSettings settings{readOnlyMode};
settings.nixPath = {};
return settings;
})
{
}
Value eval(std::string input, bool forceValue = true)

View File

@@ -31,6 +31,7 @@ rapidcheck = dependency('rapidcheck')
deps_public += rapidcheck
subdir('nix-meson-build-support/common')
subdir('nix-meson-build-support/asan-options')
sources = files(
'tests/value/context.cc',
@@ -44,6 +45,7 @@ subdir('nix-meson-build-support/windows-version')
this_library = library(
'nix-expr-test-support',
sources,
soversion : nix_soversion,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326

View File

@@ -3,6 +3,7 @@
#include "nix/expr/eval.hh"
#include "nix/expr/tests/libexpr.hh"
#include "nix/util/memory-source-accessor.hh"
namespace nix {
@@ -174,4 +175,41 @@ TEST_F(EvalStateTest, getBuiltin_fail)
ASSERT_THROW(state.getBuiltin("nonexistent"), EvalError);
}
class PureEvalTest : public LibExprTest
{
public:
PureEvalTest()
: LibExprTest(openStore("dummy://", {{"read-only", "false"}}), [](bool & readOnlyMode) {
EvalSettings settings{readOnlyMode};
settings.pureEval = true;
settings.restrictEval = true;
return settings;
})
{
}
};
TEST_F(PureEvalTest, pathExists)
{
ASSERT_THAT(eval("builtins.pathExists /."), IsFalse());
ASSERT_THAT(eval("builtins.pathExists /nix"), IsFalse());
ASSERT_THAT(eval("builtins.pathExists /nix/store"), IsFalse());
{
std::string contents = "Lorem ipsum";
StringSource s{contents};
auto path = state.store->addToStoreFromDump(
s, "source", FileSerialisationMethod::Flat, ContentAddressMethod::Raw::Text, HashAlgorithm::SHA256);
auto printed = store->printStorePath(path);
ASSERT_THROW(eval(fmt("builtins.readFile %s", printed)), RestrictedPathError);
ASSERT_THAT(eval(fmt("builtins.pathExists %s", printed)), IsFalse());
ASSERT_THROW(eval("builtins.readDir /."), RestrictedPathError);
state.allowPath(path); // FIXME: This shouldn't behave this way.
ASSERT_THAT(eval("builtins.readDir /."), IsAttrsOfSize(0));
}
}
} // namespace nix

View File

@@ -54,7 +54,7 @@ TEST_F(JSONValueTest, IntNegative)
TEST_F(JSONValueTest, String)
{
Value v;
v.mkString("test");
v.mkStringNoCopy("test");
ASSERT_EQ(getJSONValue(v), "\"test\"");
}
@@ -62,7 +62,7 @@ TEST_F(JSONValueTest, StringQuotes)
{
Value v;
v.mkString("test\"");
v.mkStringNoCopy("test\"");
ASSERT_EQ(getJSONValue(v), "\"test\\\"\"");
}

View File

@@ -1,40 +1,15 @@
#include <gtest/gtest.h>
#include <cstdlib>
#include "nix/store/globals.hh"
#include "nix/util/logging.hh"
#include "nix/store/tests/test-main.hh"
#include "nix/util/config-global.hh"
using namespace nix;
int main(int argc, char ** argv)
{
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
printError("test-build-remote: not supported in libexpr unit tests");
return 1;
}
// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
settings.buildHook = {};
#ifdef __linux__ // should match the conditional around sandboxBuildDir declaration.
// When building and testing nix within the host's Nix sandbox, our store dir will be located in the host's
// sandboxBuildDir, e.g.: Host
// storeDir = /nix/store
// sandboxBuildDir = /build
// This process
// storeDir = /build/foo/bar/store
// sandboxBuildDir = /build
// However, we have a rule that the store dir must not be inside the storeDir, so we need to pick a different
// sandboxBuildDir.
settings.sandboxBuildDir = "/test-build-dir-instead-of-usual-build-dir";
#endif
#ifdef __APPLE__
// Avoid this error, when already running in a sandbox:
// sandbox-exec: sandbox_apply: Operation not permitted
settings.sandboxMode = smDisabled;
setEnv("_NIX_TEST_NO_SANDBOX", "1");
#endif
auto res = testMainForBuidingPre(argc, argv);
if (res)
return res;
// For pipe operator tests in trivial.cc
experimentalFeatureSettings.set("experimental-features", "pipe-operators");

View File

@@ -45,6 +45,7 @@ config_priv_h = configure_file(
)
subdir('nix-meson-build-support/common')
subdir('nix-meson-build-support/asan-options')
sources = files(
'derived-path.cc',
@@ -55,6 +56,7 @@ sources = files(
'nix_api_expr.cc',
'nix_api_external.cc',
'nix_api_value.cc',
'nix_api_value_internal.cc',
'primops.cc',
'search-path.cc',
'trivial.cc',
@@ -81,7 +83,7 @@ this_exe = executable(
test(
meson.project_name(),
this_exe,
env : {
env : asan_test_options_env + {
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
},
protocol : 'gtest',

View File

@@ -1,7 +1,5 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
@@ -151,8 +149,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_value)
assert_ctx_ok();
auto r = nix_string_realise(ctx, state, value, false);
ASSERT_EQ(nullptr, r);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("cannot coerce")));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("cannot coerce"));
}
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
@@ -168,8 +166,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
assert_ctx_ok();
auto r = nix_string_realise(ctx, state, value, false);
ASSERT_EQ(nullptr, r);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("failed with exit code 1")));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("failed with exit code 1"));
}
TEST_F(nix_api_expr_test, nix_expr_realise_context)
@@ -381,12 +379,11 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_no_return)
nix_value * result = nix_alloc_value(ctx, state);
assert_ctx_ok();
nix_value_call(ctx, state, primopValue, three, result);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
ctx->last_err,
testing::Optional(
testing::HasSubstr("Implementation error in custom function: return value was not initialized")));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badNoReturn")));
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("Implementation error in custom function: return value was not initialized"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badNoReturn"));
}
static void primop_bad_return_thunk(
@@ -419,12 +416,60 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_return_thunk)
assert_ctx_ok();
NIX_VALUE_CALL(ctx, state, result, primopValue, toString, four);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
ctx->last_err,
testing::Optional(
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk")));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badReturnThunk")));
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badReturnThunk"));
}
static void primop_with_nix_err_key(
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret)
{
nix_set_err_msg(context, NIX_ERR_KEY, "Test error from primop");
}
TEST_F(nix_api_expr_test, nix_expr_primop_nix_err_key_conversion)
{
// Test that NIX_ERR_KEY from a custom primop gets converted to a generic EvalError
//
// RATIONALE: NIX_ERR_KEY must not be propagated from custom primops because it would
// create semantic confusion. NIX_ERR_KEY indicates missing keys/indices in C API functions
// (like nix_get_attr_byname, nix_get_list_byidx). If custom primops could return NIX_ERR_KEY,
// an evaluation error would be indistinguishable from an actual missing attribute.
//
// For example, if nix_get_attr_byname returned NIX_ERR_KEY when the attribute is present
// but the value evaluation fails, callers expecting NIX_ERR_KEY to mean "missing attribute"
// would incorrectly handle evaluation failures as missing attributes. In places where
// missing attributes are tolerated (like optional attributes), this would cause the
// program to continue after swallowing the error, leading to silent failures.
PrimOp * primop = nix_alloc_primop(
ctx, primop_with_nix_err_key, 1, "testErrorPrimop", nullptr, "a test primop that sets NIX_ERR_KEY", nullptr);
assert_ctx_ok();
nix_value * primopValue = nix_alloc_value(ctx, state);
assert_ctx_ok();
nix_init_primop(ctx, primopValue, primop);
assert_ctx_ok();
nix_value * arg = nix_alloc_value(ctx, state);
assert_ctx_ok();
nix_init_int(ctx, arg, 42);
assert_ctx_ok();
nix_value * result = nix_alloc_value(ctx, state);
assert_ctx_ok();
nix_value_call(ctx, state, primopValue, arg, result);
// Verify that NIX_ERR_KEY gets converted to NIX_ERR_NIX_ERROR (generic evaluation error)
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("Error from custom function"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("Test error from primop"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("testErrorPrimop"));
// Clean up
nix_gc_decref(ctx, primopValue);
nix_gc_decref(ctx, arg);
nix_gc_decref(ctx, result);
}
TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
@@ -441,4 +486,31 @@ TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
assert_ctx_ok();
ASSERT_EQ(3, rInt);
}
TEST_F(nix_api_expr_test, nix_expr_attrset_update)
{
nix_expr_eval_from_string(ctx, state, "{ a = 0; b = 2; } // { a = 1; b = 3; } // { a = 2; }", ".", value);
assert_ctx_ok();
ASSERT_EQ(nix_get_attrs_size(ctx, value), 2);
assert_ctx_ok();
std::array<std::pair<std::string_view, nix_value *>, 2> values;
for (unsigned int i = 0; i < 2; ++i) {
const char * name;
values[i].second = nix_get_attr_byidx(ctx, value, state, i, &name);
assert_ctx_ok();
values[i].first = name;
}
std::sort(values.begin(), values.end(), [](const auto & lhs, const auto & rhs) { return lhs.first < rhs.first; });
nix_value * a = values[0].second;
ASSERT_EQ("a", values[0].first);
ASSERT_EQ(nix_get_int(ctx, a), 2);
assert_ctx_ok();
nix_value * b = values[1].second;
ASSERT_EQ("b", values[1].first);
ASSERT_EQ(nix_get_int(ctx, b), 3);
assert_ctx_ok();
}
} // namespace nixC

View File

@@ -1,9 +1,6 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
#include "nix_api_value.h"
#include "nix_api_external.h"
@@ -39,7 +36,7 @@ private:
std::string type_string = "nix-external<MyExternalValueDesc( ";
type_string += std::to_string(obj->_x);
type_string += " )>";
res->str = &*type_string.begin();
nix_set_string_return(res, &*type_string.begin());
}
};

View File

@@ -1,10 +1,7 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
#include "nix_api_expr_internal.h"
#include "nix/expr/tests/nix_api_expr.hh"
#include "nix/util/tests/string_callback.hh"
@@ -16,14 +13,6 @@
namespace nixC {
TEST_F(nix_api_expr_test, as_nix_value_ptr)
{
// nix_alloc_value casts nix::Value to nix_value
// It should be obvious from the decl that that works, but if it doesn't,
// the whole implementation would be utterly broken.
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
}
TEST_F(nix_api_expr_test, nix_value_get_int_invalid)
{
ASSERT_EQ(0, nix_get_int(ctx, nullptr));
@@ -173,6 +162,114 @@ TEST_F(nix_api_expr_test, nix_build_and_init_list)
nix_gc_decref(ctx, intValue);
}
TEST_F(nix_api_expr_test, nix_get_list_byidx_large_indices)
{
// Create a small list to test extremely large out-of-bounds access
ListBuilder * builder = nix_make_list_builder(ctx, state, 2);
nix_value * intValue = nix_alloc_value(ctx, state);
nix_init_int(ctx, intValue, 42);
nix_list_builder_insert(ctx, builder, 0, intValue);
nix_list_builder_insert(ctx, builder, 1, intValue);
nix_make_list(ctx, builder, value);
nix_list_builder_free(builder);
// Test extremely large indices that would definitely crash without bounds checking
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 1000000));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, UINT_MAX / 2));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, UINT_MAX / 2 + 1000000));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
// Clean up
nix_gc_decref(ctx, intValue);
}
TEST_F(nix_api_expr_test, nix_get_list_byidx_lazy)
{
// Create a list with a throwing lazy element, an already-evaluated int, and a lazy function call
// 1. Throwing lazy element - create a function application thunk that will throw when forced
nix_value * throwingFn = nix_alloc_value(ctx, state);
nix_value * throwingValue = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(
ctx,
state,
R"(
_: throw "This should not be evaluated by the lazy accessor"
)",
"<test>",
throwingFn);
assert_ctx_ok();
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
assert_ctx_ok();
// 2. Already evaluated int (not lazy)
nix_value * intValue = nix_alloc_value(ctx, state);
nix_init_int(ctx, intValue, 42);
assert_ctx_ok();
// 3. Lazy function application that would compute increment 5 = 6
nix_value * lazyApply = nix_alloc_value(ctx, state);
nix_value * incrementFn = nix_alloc_value(ctx, state);
nix_value * argFive = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
assert_ctx_ok();
nix_init_int(ctx, argFive, 5);
// Create a lazy application: (x: x + 1) 5
nix_init_apply(ctx, lazyApply, incrementFn, argFive);
assert_ctx_ok();
ListBuilder * builder = nix_make_list_builder(ctx, state, 3);
nix_list_builder_insert(ctx, builder, 0, throwingValue);
nix_list_builder_insert(ctx, builder, 1, intValue);
nix_list_builder_insert(ctx, builder, 2, lazyApply);
nix_make_list(ctx, builder, value);
nix_list_builder_free(builder);
// Test 1: Lazy accessor should return the throwing element without forcing evaluation
nix_value * lazyThrowingElement = nix_get_list_byidx_lazy(ctx, value, state, 0);
assert_ctx_ok();
ASSERT_NE(nullptr, lazyThrowingElement);
// Verify the element is still lazy by checking that forcing it throws
nix_value_force(ctx, state, lazyThrowingElement);
assert_ctx_err();
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
// Test 2: Lazy accessor should return the already-evaluated int
nix_value * intElement = nix_get_list_byidx_lazy(ctx, value, state, 1);
assert_ctx_ok();
ASSERT_NE(nullptr, intElement);
ASSERT_EQ(42, nix_get_int(ctx, intElement));
// Test 3: Lazy accessor should return the lazy function application without forcing
nix_value * lazyFunctionElement = nix_get_list_byidx_lazy(ctx, value, state, 2);
assert_ctx_ok();
ASSERT_NE(nullptr, lazyFunctionElement);
// Force the lazy function application - should compute 5 + 1 = 6
nix_value_force(ctx, state, lazyFunctionElement);
assert_ctx_ok();
ASSERT_EQ(6, nix_get_int(ctx, lazyFunctionElement));
// Clean up
nix_gc_decref(ctx, throwingFn);
nix_gc_decref(ctx, throwingValue);
nix_gc_decref(ctx, intValue);
nix_gc_decref(ctx, lazyApply);
nix_gc_decref(ctx, incrementFn);
nix_gc_decref(ctx, argFive);
nix_gc_decref(ctx, lazyThrowingElement);
nix_gc_decref(ctx, intElement);
nix_gc_decref(ctx, lazyFunctionElement);
}
TEST_F(nix_api_expr_test, nix_build_and_init_attr_invalid)
{
ASSERT_EQ(nullptr, nix_get_attr_byname(ctx, nullptr, state, 0));
@@ -255,6 +352,225 @@ TEST_F(nix_api_expr_test, nix_build_and_init_attr)
free(out_name);
}
TEST_F(nix_api_expr_test, nix_get_attr_byidx_large_indices)
{
// Create a small attribute set to test extremely large out-of-bounds access
const char ** out_name = (const char **) malloc(sizeof(char *));
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 2);
nix_value * intValue = nix_alloc_value(ctx, state);
nix_init_int(ctx, intValue, 42);
nix_bindings_builder_insert(ctx, builder, "test", intValue);
nix_make_attrs(ctx, value, builder);
nix_bindings_builder_free(builder);
// Test extremely large indices that would definitely crash without bounds checking
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, 1000000, out_name));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, UINT_MAX / 2, out_name));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, UINT_MAX / 2 + 1000000, out_name));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
// Test nix_get_attr_name_byidx with large indices too
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, 1000000));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, UINT_MAX / 2));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, UINT_MAX / 2 + 1000000));
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
// Clean up
nix_gc_decref(ctx, intValue);
free(out_name);
}
TEST_F(nix_api_expr_test, nix_get_attr_byname_lazy)
{
// Create an attribute set with a throwing lazy attribute, an already-evaluated int, and a lazy function call
// 1. Throwing lazy element - create a function application thunk that will throw when forced
nix_value * throwingFn = nix_alloc_value(ctx, state);
nix_value * throwingValue = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(
ctx,
state,
R"(
_: throw "This should not be evaluated by the lazy accessor"
)",
"<test>",
throwingFn);
assert_ctx_ok();
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
assert_ctx_ok();
// 2. Already evaluated int (not lazy)
nix_value * intValue = nix_alloc_value(ctx, state);
nix_init_int(ctx, intValue, 42);
assert_ctx_ok();
// 3. Lazy function application that would compute increment 7 = 8
nix_value * lazyApply = nix_alloc_value(ctx, state);
nix_value * incrementFn = nix_alloc_value(ctx, state);
nix_value * argSeven = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
assert_ctx_ok();
nix_init_int(ctx, argSeven, 7);
// Create a lazy application: (x: x + 1) 7
nix_init_apply(ctx, lazyApply, incrementFn, argSeven);
assert_ctx_ok();
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 3);
nix_bindings_builder_insert(ctx, builder, "throwing", throwingValue);
nix_bindings_builder_insert(ctx, builder, "normal", intValue);
nix_bindings_builder_insert(ctx, builder, "lazy", lazyApply);
nix_make_attrs(ctx, value, builder);
nix_bindings_builder_free(builder);
// Test 1: Lazy accessor should return the throwing attribute without forcing evaluation
nix_value * lazyThrowingAttr = nix_get_attr_byname_lazy(ctx, value, state, "throwing");
assert_ctx_ok();
ASSERT_NE(nullptr, lazyThrowingAttr);
// Verify the attribute is still lazy by checking that forcing it throws
nix_value_force(ctx, state, lazyThrowingAttr);
assert_ctx_err();
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
// Test 2: Lazy accessor should return the already-evaluated int
nix_value * intAttr = nix_get_attr_byname_lazy(ctx, value, state, "normal");
assert_ctx_ok();
ASSERT_NE(nullptr, intAttr);
ASSERT_EQ(42, nix_get_int(ctx, intAttr));
// Test 3: Lazy accessor should return the lazy function application without forcing
nix_value * lazyFunctionAttr = nix_get_attr_byname_lazy(ctx, value, state, "lazy");
assert_ctx_ok();
ASSERT_NE(nullptr, lazyFunctionAttr);
// Force the lazy function application - should compute 7 + 1 = 8
nix_value_force(ctx, state, lazyFunctionAttr);
assert_ctx_ok();
ASSERT_EQ(8, nix_get_int(ctx, lazyFunctionAttr));
// Test 4: Missing attribute should return NULL with NIX_ERR_KEY
nix_value * missingAttr = nix_get_attr_byname_lazy(ctx, value, state, "nonexistent");
ASSERT_EQ(nullptr, missingAttr);
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
// Clean up
nix_gc_decref(ctx, throwingFn);
nix_gc_decref(ctx, throwingValue);
nix_gc_decref(ctx, intValue);
nix_gc_decref(ctx, lazyApply);
nix_gc_decref(ctx, incrementFn);
nix_gc_decref(ctx, argSeven);
nix_gc_decref(ctx, lazyThrowingAttr);
nix_gc_decref(ctx, intAttr);
nix_gc_decref(ctx, lazyFunctionAttr);
}
TEST_F(nix_api_expr_test, nix_get_attr_byidx_lazy)
{
// Create an attribute set with a throwing lazy attribute, an already-evaluated int, and a lazy function call
// 1. Throwing lazy element - create a function application thunk that will throw when forced
nix_value * throwingFn = nix_alloc_value(ctx, state);
nix_value * throwingValue = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(
ctx,
state,
R"(
_: throw "This should not be evaluated by the lazy accessor"
)",
"<test>",
throwingFn);
assert_ctx_ok();
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
assert_ctx_ok();
// 2. Already evaluated int (not lazy)
nix_value * intValue = nix_alloc_value(ctx, state);
nix_init_int(ctx, intValue, 99);
assert_ctx_ok();
// 3. Lazy function application that would compute increment 10 = 11
nix_value * lazyApply = nix_alloc_value(ctx, state);
nix_value * incrementFn = nix_alloc_value(ctx, state);
nix_value * argTen = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
assert_ctx_ok();
nix_init_int(ctx, argTen, 10);
// Create a lazy application: (x: x + 1) 10
nix_init_apply(ctx, lazyApply, incrementFn, argTen);
assert_ctx_ok();
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 3);
nix_bindings_builder_insert(ctx, builder, "a_throwing", throwingValue);
nix_bindings_builder_insert(ctx, builder, "b_normal", intValue);
nix_bindings_builder_insert(ctx, builder, "c_lazy", lazyApply);
nix_make_attrs(ctx, value, builder);
nix_bindings_builder_free(builder);
// Proper usage: first get the size and gather all attributes into a map
unsigned int attrCount = nix_get_attrs_size(ctx, value);
assert_ctx_ok();
ASSERT_EQ(3u, attrCount);
// Gather all attributes into a map (proper contract usage)
std::map<std::string, nix_value *> attrMap;
const char * name;
for (unsigned int i = 0; i < attrCount; i++) {
nix_value * attr = nix_get_attr_byidx_lazy(ctx, value, state, i, &name);
assert_ctx_ok();
ASSERT_NE(nullptr, attr);
attrMap[std::string(name)] = attr;
}
// Now test the gathered attributes
ASSERT_EQ(3u, attrMap.size());
ASSERT_TRUE(attrMap.count("a_throwing"));
ASSERT_TRUE(attrMap.count("b_normal"));
ASSERT_TRUE(attrMap.count("c_lazy"));
// Test 1: Throwing attribute should be lazy
nix_value * throwingAttr = attrMap["a_throwing"];
nix_value_force(ctx, state, throwingAttr);
assert_ctx_err();
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
// Test 2: Normal attribute should be already evaluated
nix_value * normalAttr = attrMap["b_normal"];
ASSERT_EQ(99, nix_get_int(ctx, normalAttr));
// Test 3: Lazy function should compute when forced
nix_value * lazyAttr = attrMap["c_lazy"];
nix_value_force(ctx, state, lazyAttr);
assert_ctx_ok();
ASSERT_EQ(11, nix_get_int(ctx, lazyAttr));
// Clean up
nix_gc_decref(ctx, throwingFn);
nix_gc_decref(ctx, throwingValue);
nix_gc_decref(ctx, intValue);
nix_gc_decref(ctx, lazyApply);
nix_gc_decref(ctx, incrementFn);
nix_gc_decref(ctx, argTen);
for (auto & pair : attrMap) {
nix_gc_decref(ctx, pair.second);
}
}
TEST_F(nix_api_expr_test, nix_value_init)
{
// Setup
@@ -320,8 +636,10 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_error)
// Evaluate it
nix_value_force(ctx, state, v);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("attempt to call something which is not a function but"));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("attempt to call something which is not a function but"));
// Clean up
nix_gc_decref(ctx, some_string);
@@ -380,7 +698,9 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_lazy_arg)
// nix_get_attr_byname isn't lazy (it could have been) so it will throw the exception
nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo");
ASSERT_EQ(nullptr, foo);
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
// Clean up
nix_gc_decref(ctx, f);

View File

@@ -0,0 +1,25 @@
#include "nix_api_store.h"
#include "nix_api_util.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
#include "nix_api_expr_internal.h"
#include "nix/expr/tests/nix_api_expr.hh"
#include "nix/util/tests/string_callback.hh"
#include <gmock/gmock.h>
#include <cstddef>
#include <cstdlib>
#include <gtest/gtest.h>
namespace nixC {
TEST_F(nix_api_expr_test, as_nix_value_ptr)
{
// nix_alloc_value casts nix::Value to nix_value
// It should be obvious from the decl that that works, but if it doesn't,
// the whole implementation would be utterly broken.
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
}
} // namespace nixC

View File

@@ -62,6 +62,7 @@ mkMesonExecutable (finalAttrs: {
mkdir -p "$HOME"
''
+ ''
export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0
export _NIX_TEST_UNIT_DATA=${resolvePath ./data}
${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage}
touch $out

View File

@@ -195,18 +195,18 @@ TEST_F(PrimOpTest, unsafeGetAttrPos)
auto v = eval(expr);
ASSERT_THAT(v, IsAttrsOfSize(3));
auto file = v.attrs()->find(createSymbol("file"));
auto file = v.attrs()->get(createSymbol("file"));
ASSERT_NE(file, nullptr);
ASSERT_THAT(*file->value, IsString());
auto s = baseNameOf(file->value->string_view());
ASSERT_EQ(s, "foo.nix");
auto line = v.attrs()->find(createSymbol("line"));
auto line = v.attrs()->get(createSymbol("line"));
ASSERT_NE(line, nullptr);
state.forceValue(*line->value, noPos);
ASSERT_THAT(*line->value, IsIntEq(4));
auto column = v.attrs()->find(createSymbol("column"));
auto column = v.attrs()->get(createSymbol("column"));
ASSERT_NE(column, nullptr);
state.forceValue(*column->value, noPos);
ASSERT_THAT(*column->value, IsIntEq(3));
@@ -246,7 +246,7 @@ TEST_F(PrimOpTest, removeAttrsRetains)
{
auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]");
ASSERT_THAT(v, IsAttrsOfSize(1));
ASSERT_NE(v.attrs()->find(createSymbol("y")), nullptr);
ASSERT_NE(v.attrs()->get(createSymbol("y")), nullptr);
}
TEST_F(PrimOpTest, listToAttrsEmptyList)
@@ -266,7 +266,7 @@ TEST_F(PrimOpTest, listToAttrs)
{
auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]");
ASSERT_THAT(v, IsAttrsOfSize(1));
auto key = v.attrs()->find(createSymbol("key"));
auto key = v.attrs()->get(createSymbol("key"));
ASSERT_NE(key, nullptr);
ASSERT_THAT(*key->value, IsIntEq(123));
}
@@ -275,7 +275,7 @@ TEST_F(PrimOpTest, intersectAttrs)
{
auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }");
ASSERT_THAT(v, IsAttrsOfSize(1));
auto b = v.attrs()->find(createSymbol("b"));
auto b = v.attrs()->get(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(3));
}
@@ -293,11 +293,11 @@ TEST_F(PrimOpTest, functionArgs)
auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)");
ASSERT_THAT(v, IsAttrsOfSize(2));
auto x = v.attrs()->find(createSymbol("x"));
auto x = v.attrs()->get(createSymbol("x"));
ASSERT_NE(x, nullptr);
ASSERT_THAT(*x->value, IsFalse());
auto y = v.attrs()->find(createSymbol("y"));
auto y = v.attrs()->get(createSymbol("y"));
ASSERT_NE(y, nullptr);
ASSERT_THAT(*y->value, IsTrue());
}
@@ -307,13 +307,13 @@ TEST_F(PrimOpTest, mapAttrs)
auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }");
ASSERT_THAT(v, IsAttrsOfSize(2));
auto a = v.attrs()->find(createSymbol("a"));
auto a = v.attrs()->get(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsThunk());
state.forceValue(*a->value, noPos);
ASSERT_THAT(*a->value, IsIntEq(10));
auto b = v.attrs()->find(createSymbol("b"));
auto b = v.attrs()->get(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsThunk());
state.forceValue(*b->value, noPos);
@@ -642,7 +642,7 @@ class ToStringPrimOpTest : public PrimOpTest,
TEST_P(ToStringPrimOpTest, toString)
{
const auto [input, output] = GetParam();
const auto & [input, output] = GetParam();
auto v = eval(input);
ASSERT_THAT(v, IsStringEq(output));
}
@@ -798,7 +798,7 @@ class CompareVersionsPrimOpTest : public PrimOpTest,
TEST_P(CompareVersionsPrimOpTest, compareVersions)
{
auto [expression, expectation] = GetParam();
const auto & [expression, expectation] = GetParam();
auto v = eval(expression);
ASSERT_THAT(v, IsIntEq(expectation));
}
@@ -834,16 +834,16 @@ class ParseDrvNamePrimOpTest
TEST_P(ParseDrvNamePrimOpTest, parseDrvName)
{
auto [input, expectedName, expectedVersion] = GetParam();
const auto & [input, expectedName, expectedVersion] = GetParam();
const auto expr = fmt("builtins.parseDrvName \"%1%\"", input);
auto v = eval(expr);
ASSERT_THAT(v, IsAttrsOfSize(2));
auto name = v.attrs()->find(createSymbol("name"));
auto name = v.attrs()->get(createSymbol("name"));
ASSERT_TRUE(name);
ASSERT_THAT(*name->value, IsStringEq(expectedName));
auto version = v.attrs()->find(createSymbol("version"));
auto version = v.attrs()->get(createSymbol("version"));
ASSERT_TRUE(version);
ASSERT_THAT(*version->value, IsStringEq(expectedVersion));
}

View File

@@ -75,11 +75,11 @@ TEST_F(TrivialExpressionTest, updateAttrs)
{
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
ASSERT_THAT(v, IsAttrsOfSize(2));
auto a = v.attrs()->find(createSymbol("a"));
auto a = v.attrs()->get(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsIntEq(3));
auto b = v.attrs()->find(createSymbol("b"));
auto b = v.attrs()->get(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(2));
}
@@ -176,7 +176,7 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
auto v = eval(expr);
ASSERT_THAT(v, IsAttrsOfSize(1));
auto a = v.attrs()->find(createSymbol("a"));
auto a = v.attrs()->get(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsThunk());
@@ -184,11 +184,11 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
auto b = a->value->attrs()->find(createSymbol("b"));
auto b = a->value->attrs()->get(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
auto c = a->value->attrs()->find(createSymbol("c"));
auto c = a->value->attrs()->get(createSymbol("c"));
ASSERT_NE(c, nullptr);
ASSERT_THAT(*c->value, IsIntEq(2));
}
@@ -330,7 +330,7 @@ TEST_F(TrivialExpressionTest, bindOr)
{
auto v = eval("{ or = 1; }");
ASSERT_THAT(v, IsAttrsOfSize(1));
auto b = v.attrs()->find(createSymbol("or"));
auto b = v.attrs()->get(createSymbol("or"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
}

View File

@@ -35,14 +35,14 @@ TEST_F(ValuePrintingTests, tBool)
TEST_F(ValuePrintingTests, tString)
{
Value vString;
vString.mkString("some-string");
vString.mkStringNoCopy("some-string");
test(vString, "\"some-string\"");
}
TEST_F(ValuePrintingTests, tPath)
{
Value vPath;
vPath.mkString("/foo");
vPath.mkStringNoCopy("/foo");
test(vPath, "\"/foo\"");
}
@@ -61,7 +61,7 @@ TEST_F(ValuePrintingTests, tAttrs)
Value vTwo;
vTwo.mkInt(2);
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
@@ -196,11 +196,11 @@ TEST_F(ValuePrintingTests, depthAttrs)
Value vTwo;
vTwo.mkInt(2);
BindingsBuilder builderEmpty(state, state.allocBindings(0));
BindingsBuilder builderEmpty = state.buildBindings(0);
Value vAttrsEmpty;
vAttrsEmpty.mkAttrs(builderEmpty.finish());
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
builder.insert(state.symbols.create("nested"), &vAttrsEmpty);
@@ -208,7 +208,7 @@ TEST_F(ValuePrintingTests, depthAttrs)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
BindingsBuilder builder2(state, state.allocBindings(10));
BindingsBuilder builder2 = state.buildBindings(10);
builder2.insert(state.symbols.create("one"), &vOne);
builder2.insert(state.symbols.create("two"), &vTwo);
builder2.insert(state.symbols.create("nested"), &vAttrs);
@@ -233,14 +233,14 @@ TEST_F(ValuePrintingTests, depthList)
Value vTwo;
vTwo.mkInt(2);
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
BindingsBuilder builder2(state, state.allocBindings(10));
BindingsBuilder builder2 = state.buildBindings(10);
builder2.insert(state.symbols.create("one"), &vOne);
builder2.insert(state.symbols.create("two"), &vTwo);
builder2.insert(state.symbols.create("nested"), &vAttrs);
@@ -290,12 +290,12 @@ TEST_F(StringPrintingTests, maxLengthTruncation)
TEST_F(ValuePrintingTests, attrsTypeFirst)
{
Value vType;
vType.mkString("puppy");
vType.mkStringNoCopy("puppy");
Value vApple;
vApple.mkString("apple");
vApple.mkStringNoCopy("apple");
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("type"), &vType);
builder.insert(state.symbols.create("apple"), &vApple);
@@ -334,7 +334,7 @@ TEST_F(ValuePrintingTests, ansiColorsBool)
TEST_F(ValuePrintingTests, ansiColorsString)
{
Value v;
v.mkString("puppy");
v.mkStringNoCopy("puppy");
test(v, ANSI_MAGENTA "\"puppy\"" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
@@ -342,7 +342,7 @@ TEST_F(ValuePrintingTests, ansiColorsString)
TEST_F(ValuePrintingTests, ansiColorsStringElided)
{
Value v;
v.mkString("puppy");
v.mkStringNoCopy("puppy");
test(
v,
@@ -374,7 +374,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
Value vTwo;
vTwo.mkInt(2);
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
@@ -390,10 +390,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
TEST_F(ValuePrintingTests, ansiColorsDerivation)
{
Value vDerivation;
vDerivation.mkString("derivation");
vDerivation.mkStringNoCopy("derivation");
BindingsBuilder builder(state, state.allocBindings(10));
builder.insert(state.sType, &vDerivation);
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.s.type, &vDerivation);
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
@@ -413,7 +413,7 @@ TEST_F(ValuePrintingTests, ansiColorsError)
{
Value throw_ = state.getBuiltin("throw");
Value message;
message.mkString("uh oh!");
message.mkStringNoCopy("uh oh!");
Value vError;
vError.mkApp(&throw_, &message);
@@ -430,16 +430,16 @@ TEST_F(ValuePrintingTests, ansiColorsDerivationError)
{
Value throw_ = state.getBuiltin("throw");
Value message;
message.mkString("uh oh!");
message.mkStringNoCopy("uh oh!");
Value vError;
vError.mkApp(&throw_, &message);
Value vDerivation;
vDerivation.mkString("derivation");
vDerivation.mkStringNoCopy("derivation");
BindingsBuilder builder(state, state.allocBindings(10));
builder.insert(state.sType, &vDerivation);
builder.insert(state.sDrvPath, &vError);
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.s.type, &vDerivation);
builder.insert(state.s.drvPath, &vError);
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
@@ -553,12 +553,12 @@ TEST_F(ValuePrintingTests, ansiColorsBlackhole)
TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
{
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
BindingsBuilder emptyBuilder = state.buildBindings(1);
Value vEmpty;
vEmpty.mkAttrs(emptyBuilder.finish());
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("a"), &vEmpty);
builder.insert(state.symbols.create("b"), &vEmpty);
@@ -570,7 +570,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
TEST_F(ValuePrintingTests, ansiColorsListRepeated)
{
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
BindingsBuilder emptyBuilder = state.buildBindings(1);
Value vEmpty;
vEmpty.mkAttrs(emptyBuilder.finish());
@@ -586,7 +586,7 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
TEST_F(ValuePrintingTests, listRepeated)
{
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
BindingsBuilder emptyBuilder = state.buildBindings(1);
Value vEmpty;
vEmpty.mkAttrs(emptyBuilder.finish());
@@ -609,7 +609,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
Value vTwo;
vTwo.mkInt(2);
BindingsBuilder builder(state, state.allocBindings(10));
BindingsBuilder builder = state.buildBindings(10);
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
@@ -635,8 +635,6 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
TEST_F(ValuePrintingTests, ansiColorsListElided)
{
BindingsBuilder emptyBuilder(state, state.allocBindings(1));
Value vOne;
vOne.mkInt(1);

View File

@@ -110,8 +110,8 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
{
Value * v2;
try {
auto dummyArgs = state.allocBindings(0);
v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
auto & dummyArgs = Bindings::emptyBindings;
v2 = findAlongAttrPath(state, "meta.position", dummyArgs, v).first;
} catch (Error &) {
throw NoPositionInfo("package '%s' has no source location information", what);
}

View File

@@ -5,36 +5,37 @@
namespace nix {
Bindings Bindings::emptyBindings;
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
Bindings * EvalState::allocBindings(size_t capacity)
Bindings * EvalMemory::allocBindings(size_t capacity)
{
if (capacity == 0)
return &emptyBindings;
if (capacity > std::numeric_limits<Bindings::size_t>::max())
return &Bindings::emptyBindings;
if (capacity > std::numeric_limits<Bindings::size_type>::max())
throw Error("attribute set of size %d is too big", capacity);
nrAttrsets++;
nrAttrsInAttrsets += capacity;
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings((Bindings::size_t) capacity);
stats.nrAttrsets++;
stats.nrAttrsInAttrsets += capacity;
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings();
}
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
{
auto value = state.allocValue();
auto value = mem.get().allocValue();
bindings->push_back(Attr(name, value, pos));
return *value;
}
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
{
return alloc(state.symbols.create(name), pos);
return alloc(symbols.get().create(name), pos);
}
void Bindings::sort()
{
if (size_)
std::sort(begin(), end());
std::sort(attrs, attrs + numAttrs);
}
Value & Value::mkAttrs(BindingsBuilder & bindings)

View File

@@ -330,7 +330,7 @@ AttrCursor::AttrCursor(
AttrKey AttrCursor::getKey()
{
if (!parent)
return {0, root->state.sEpsilon};
return {0, root->state.s.epsilon};
if (!parent->first->cachedValue) {
parent->first->cachedValue = root->db->getAttr(parent->first->getKey());
assert(parent->first->cachedValue);
@@ -702,7 +702,7 @@ bool AttrCursor::isDerivation()
StorePath AttrCursor::forceDerivation()
{
auto aDrvPath = getAttr(root->state.sDrvPath);
auto aDrvPath = getAttr(root->state.s.drvPath);
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
drvPath.requireDerivation();
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {

View File

@@ -16,6 +16,7 @@
# endif
# include <gc/gc_allocator.h>
# include <gc/gc_tiny_fl.h> // For GC_GRANULE_BYTES
# include <boost/coroutine2/coroutine.hpp>
# include <boost/coroutine2/protected_fixedsize_stack.hpp>
@@ -26,6 +27,18 @@
namespace nix {
#if NIX_USE_BOEHMGC
/*
* Ensure that Boehm satisfies our alignment requirements. This is the default configuration [^]
* and this assertion should never break for any platform. Let's assert it just in case.
*
* This alignment is particularly useful to be able to use aligned
* load/store instructions for loading/writing Values.
*
* [^]: https://github.com/bdwgc/bdwgc/blob/54ac18ccbc5a833dd7edaff94a10ab9b65044d61/include/gc/gc_tiny_fl.h#L31-L33
*/
static_assert(sizeof(void *) * 2 == GC_GRANULE_BYTES, "Boehm GC must use GC_GRANULE_WORDS = 2");
/* Called when the Boehm GC runs out of memory. */
static void * oomHandler(size_t requested)
{

View File

@@ -185,7 +185,7 @@ FrameInfo SampleStack::getPrimOpFrameInfo(const PrimOp & primOp, std::span<Value
/* Error context strings don't actually matter, since we ignore all eval errors. */
state.forceAttrs(*args[0], pos, "");
auto attrs = args[0]->attrs();
auto nameAttr = state.getAttr(state.sName, attrs, "");
auto nameAttr = state.getAttr(state.s.name, attrs, "");
auto drvName = std::string(state.forceStringNoCtx(*nameAttr->value, pos, ""));
return DerivationStrictFrameInfo{.callPos = pos, .drvName = std::move(drvName)};
} catch (...) {
@@ -211,7 +211,7 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, std::span<Va
/* Resolve primOp eagerly. Must not hold on to a reference to a Value. */
return PrimOpFrameInfo{.expr = v.primOpAppPrimOp(), .callPos = pos};
else if (state.isFunctor(v)) {
const auto functor = v.attrs()->get(state.sFunctor);
const auto functor = v.attrs()->get(state.s.functor);
if (auto pos_ = posCache.lookup(pos); std::holds_alternative<std::monostate>(pos_.origin))
/* HACK: In case callsite position is unresolved. */
return FunctorFrameInfo{.pos = functor->pos};
@@ -324,7 +324,7 @@ void SampleStack::saveProfile()
std::visit([&](auto && info) { info.symbolize(state, os, posCache); }, pos);
}
os << " " << count;
writeLine(profileFd.get(), std::move(os).str());
writeLine(profileFd.get(), os.str());
/* Clear ostringstream. */
os.str("");
os.clear();

View File

@@ -17,11 +17,13 @@
#include "nix/expr/print.hh"
#include "nix/fetchers/filtering-source-accessor.hh"
#include "nix/util/memory-source-accessor.hh"
#include "nix/util/mounted-source-accessor.hh"
#include "nix/expr/gc-small-vector.hh"
#include "nix/util/url.hh"
#include "nix/fetchers/fetch-to-store.hh"
#include "nix/fetchers/tarball.hh"
#include "nix/fetchers/input-cache.hh"
#include "nix/util/current-process.hh"
#include "parser-tab.hh"
@@ -37,10 +39,7 @@
#include <nlohmann/json.hpp>
#include <boost/container/small_vector.hpp>
#ifndef _WIN32 // TODO use portable implementation
# include <sys/resource.h>
#endif
#include <boost/unordered/concurrent_flat_map.hpp>
#include "nix/util/strings-inline.hh"
@@ -195,6 +194,15 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
static constexpr size_t BASE_ENV_SIZE = 128;
EvalMemory::EvalMemory()
#if NIX_USE_BOEHMGC
: valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
, env1AllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
#endif
{
assertGCInitialized();
}
EvalState::EvalState(
const LookupPath & lookupPathFromArguments,
ref<Store> store,
@@ -203,138 +211,75 @@ EvalState::EvalState(
std::shared_ptr<Store> buildStore)
: fetchSettings{fetchSettings}
, settings{settings}
, sWith(symbols.create("<with>"))
, sOutPath(symbols.create("outPath"))
, sDrvPath(symbols.create("drvPath"))
, sType(symbols.create("type"))
, sMeta(symbols.create("meta"))
, sName(symbols.create("name"))
, sValue(symbols.create("value"))
, sSystem(symbols.create("system"))
, sOverrides(symbols.create("__overrides"))
, sOutputs(symbols.create("outputs"))
, sOutputName(symbols.create("outputName"))
, sIgnoreNulls(symbols.create("__ignoreNulls"))
, sFile(symbols.create("file"))
, sLine(symbols.create("line"))
, sColumn(symbols.create("column"))
, sFunctor(symbols.create("__functor"))
, sToString(symbols.create("__toString"))
, sRight(symbols.create("right"))
, sWrong(symbols.create("wrong"))
, sStructuredAttrs(symbols.create("__structuredAttrs"))
, sJson(symbols.create("__json"))
, sAllowedReferences(symbols.create("allowedReferences"))
, sAllowedRequisites(symbols.create("allowedRequisites"))
, sDisallowedReferences(symbols.create("disallowedReferences"))
, sDisallowedRequisites(symbols.create("disallowedRequisites"))
, sMaxSize(symbols.create("maxSize"))
, sMaxClosureSize(symbols.create("maxClosureSize"))
, sBuilder(symbols.create("builder"))
, sArgs(symbols.create("args"))
, sContentAddressed(symbols.create("__contentAddressed"))
, sImpure(symbols.create("__impure"))
, sOutputHash(symbols.create("outputHash"))
, sOutputHashAlgo(symbols.create("outputHashAlgo"))
, sOutputHashMode(symbols.create("outputHashMode"))
, sRecurseForDerivations(symbols.create("recurseForDerivations"))
, sDescription(symbols.create("description"))
, sSelf(symbols.create("self"))
, sEpsilon(symbols.create(""))
, sStartSet(symbols.create("startSet"))
, sOperator(symbols.create("operator"))
, sKey(symbols.create("key"))
, sPath(symbols.create("path"))
, sPrefix(symbols.create("prefix"))
, sOutputSpecified(symbols.create("outputSpecified"))
, exprSymbols{
.sub = symbols.create("__sub"),
.lessThan = symbols.create("__lessThan"),
.mul = symbols.create("__mul"),
.div = symbols.create("__div"),
.or_ = symbols.create("or"),
.findFile = symbols.create("__findFile"),
.nixPath = symbols.create("__nixPath"),
.body = symbols.create("body"),
}
, symbols(StaticEvalSymbols::staticSymbolTable())
, repair(NoRepair)
, emptyBindings(0)
, storeFS(
makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
/* In the pure eval case, we can simply require
valid paths. However, in the *impure* eval
case this gets in the way of the union
mechanism, because an invalid access in the
upper layer will *not* be caught by the union
source accessor, but instead abort the entire
lookup.
, storeFS(makeMountedSourceAccessor({
{CanonPath::root, makeEmptySourceAccessor()},
/* In the pure eval case, we can simply require
valid paths. However, in the *impure* eval
case this gets in the way of the union
mechanism, because an invalid access in the
upper layer will *not* be caught by the union
source accessor, but instead abort the entire
lookup.
This happens when the store dir in the
ambient file system has a path (e.g. because
another Nix store there), but the relocated
store does not.
This happens when the store dir in the
ambient file system has a path (e.g. because
another Nix store there), but the relocated
store does not.
TODO make the various source accessors doing
access control all throw the same type of
exception, and make union source accessor
catch it, so we don't need to do this hack.
*/
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
}))
, rootFS(
({
/* In pure eval mode, we provide a filesystem that only
contains the Nix store.
TODO make the various source accessors doing
access control all throw the same type of
exception, and make union source accessor
catch it, so we don't need to do this hack.
*/
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
}))
, rootFS([&] {
/* In pure eval mode, we provide a filesystem that only
contains the Nix store.
If we have a chroot store and pure eval is not enabled,
use a union accessor to make the chroot store available
at its logical location while still having the
underlying directory available. This is necessary for
instance if we're evaluating a file from the physical
/nix/store while using a chroot store. */
auto accessor = getFSSourceAccessor();
Otherwise, use a union accessor to make the augmented store
available at its logical location while still having the
underlying directory available. This is necessary for
instance if we're evaluating a file from the physical
/nix/store while using a chroot store, and also for lazy
mounted fetchTree. */
auto accessor = settings.pureEval ? storeFS.cast<SourceAccessor>()
: makeUnionSourceAccessor({getFSSourceAccessor(), storeFS});
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
if (settings.pureEval || store->storeDir != realStoreDir) {
accessor = settings.pureEval
? storeFS
: makeUnionSourceAccessor({accessor, storeFS});
}
/* Apply access control if needed. */
if (settings.restrictEval || settings.pureEval)
accessor = AllowListSourceAccessor::create(
accessor, {}, {}, [&settings](const CanonPath & path) -> RestrictedPathError {
auto modeInformation = settings.pureEval ? "in pure evaluation mode (use '--impure' to override)"
: "in restricted mode";
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
});
/* Apply access control if needed. */
if (settings.restrictEval || settings.pureEval)
accessor = AllowListSourceAccessor::create(accessor, {}, {},
[&settings](const CanonPath & path) -> RestrictedPathError {
auto modeInformation = settings.pureEval
? "in pure evaluation mode (use '--impure' to override)"
: "in restricted mode";
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
});
accessor;
}))
return accessor;
}())
, corepkgsFS(make_ref<MemorySourceAccessor>())
, internalFS(make_ref<MemorySourceAccessor>())
, derivationInternal{corepkgsFS->addFile(
CanonPath("derivation-internal.nix"),
, derivationInternal{internalFS->addFile(
CanonPath("derivation-internal.nix"),
#include "primops/derivation.nix.gen.hh"
)}
)}
, store(store)
, buildStore(buildStore ? buildStore : store)
, inputCache(fetchers::InputCache::create())
, debugRepl(nullptr)
, debugStop(false)
, trylevel(0)
, srcToStore(make_ref<decltype(srcToStore)::element_type>())
, importResolutionCache(make_ref<decltype(importResolutionCache)::element_type>())
, fileEvalCache(make_ref<decltype(fileEvalCache)::element_type>())
, regexCache(makeRegexCache())
#if NIX_USE_BOEHMGC
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
, env1AllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
, baseEnvP(std::allocate_shared<Env *>(traceable_allocator<Env *>(), &allocEnv(BASE_ENV_SIZE)))
, baseEnvP(std::allocate_shared<Env *>(traceable_allocator<Env *>(), &mem.allocEnv(BASE_ENV_SIZE)))
, baseEnv(**baseEnvP)
#else
, baseEnv(allocEnv(BASE_ENV_SIZE))
, baseEnv(mem.allocEnv(BASE_ENV_SIZE))
#endif
, staticBaseEnv{std::make_shared<StaticEnv>(nullptr, nullptr)}
{
@@ -343,18 +288,8 @@ EvalState::EvalState(
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
assertGCInitialized();
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
vEmptyList.mkList(buildList(0));
vNull.mkNull();
vTrue.mkBool(true);
vFalse.mkBool(false);
vStringRegular.mkString("regular");
vStringDirectory.mkString("directory");
vStringSymlink.mkString("symlink");
vStringUnknown.mkString("unknown");
static_assert(sizeof(Counter) == 64, "counters must be 64 bytes");
/* Construct the Nix expression search path. */
assert(lookupPath.elements.empty());
@@ -401,7 +336,7 @@ EvalState::EvalState(
EvalState::~EvalState() {}
void EvalState::allowPath(const Path & path)
void EvalState::allowPathLegacy(const Path & path)
{
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>())
rootFS2->allowPrefix(CanonPath(path));
@@ -649,12 +584,12 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
.name = name,
.arity = 0, // FIXME: figure out how deep by syntax only? It's not semantically useful though...
.args = {},
.doc = makeImmutableString(toView(s)), // NOTE: memory leak when compiled without GC
.doc = makeImmutableString(s.view()), // NOTE: memory leak when compiled without GC
};
}
if (isFunctor(v)) {
try {
Value & functor = *v.attrs()->find(sFunctor)->value;
Value & functor = *v.attrs()->get(s.functor)->value;
Value * vp[] = {&v};
Value partiallyApplied;
// The first parameter is not user-provided, and may be
@@ -883,7 +818,7 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t)
void Value::mkString(std::string_view s)
{
mkString(makeImmutableString(s));
mkStringNoCopy(makeImmutableString(s));
}
static const char ** encodeContext(const NixStringContext & context)
@@ -902,12 +837,12 @@ static const char ** encodeContext(const NixStringContext & context)
void Value::mkString(std::string_view s, const NixStringContext & context)
{
mkString(makeImmutableString(s), encodeContext(context));
mkStringNoCopy(makeImmutableString(s), encodeContext(context));
}
void Value::mkStringMove(const char * s, const NixStringContext & context)
{
mkString(s, encodeContext(context));
mkStringNoCopy(s, encodeContext(context));
}
void Value::mkPath(const SourcePath & path)
@@ -948,19 +883,18 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
}
ListBuilder::ListBuilder(EvalState & state, size_t size)
ListBuilder::ListBuilder(size_t size)
: size(size)
, elems(size <= 2 ? inlineElems : (Value **) allocBytes(size * sizeof(Value *)))
{
state.nrListElems += size;
}
Value * EvalState::getBool(bool b)
{
return b ? &vTrue : &vFalse;
return b ? &Value::vTrue : &Value::vFalse;
}
unsigned long nrThunks = 0;
static Counter nrThunks;
static inline void mkThunk(Value & v, Env & env, Expr * expr)
{
@@ -978,8 +912,8 @@ void EvalState::mkPos(Value & v, PosIdx p)
auto origin = positions.originOf(p);
if (auto path = std::get_if<SourcePath>(&origin)) {
auto attrs = buildBindings(3);
attrs.alloc(sFile).mkString(path->path.abs());
makePositionThunks(*this, p, attrs.alloc(sLine), attrs.alloc(sColumn));
attrs.alloc(s.file).mkString(path->path.abs());
makePositionThunks(*this, p, attrs.alloc(s.line), attrs.alloc(s.column));
v.mkAttrs(attrs);
} else
v.mkNull();
@@ -1051,10 +985,6 @@ void EvalState::mkSingleDerivedPathString(const SingleDerivedPath & p, Value & v
});
}
/* Create a thunk for the delayed computation of the given expression
in the given environment. But if the expression is a variable,
then look it up right away. This significantly reduces the number
of thunks allocated. */
Value * Expr::maybeThunk(EvalState & state, Env & env)
{
Value * v = state.allocValue();
@@ -1098,61 +1028,90 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
return &v;
}
/**
* A helper `Expr` class to lets us parse and evaluate Nix expressions
* from a thunk, ensuring that every file is parsed/evaluated only
* once (via the thunk stored in `EvalState::fileEvalCache`).
*/
struct ExprParseFile : Expr, gc
{
// FIXME: make this a reference (see below).
SourcePath path;
bool mustBeTrivial;
ExprParseFile(SourcePath & path, bool mustBeTrivial)
: path(path)
, mustBeTrivial(mustBeTrivial)
{
}
void eval(EvalState & state, Env & env, Value & v) override
{
printTalkative("evaluating file '%s'", path);
auto e = state.parseExprFromFile(path);
try {
auto dts =
state.debugRepl
? makeDebugTraceStacker(
state, *e, state.baseEnv, e->getPos(), "while evaluating the file '%s':", path.to_string())
: nullptr;
// Enforce that 'flake.nix' is a direct attrset, not a
// computation.
if (mustBeTrivial && !(dynamic_cast<ExprAttrs *>(e)))
state.error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
state.eval(e, v);
} catch (Error & e) {
state.addErrorTrace(e, "while evaluating the file '%s':", path.to_string());
throw;
}
}
};
void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
{
FileEvalCache::iterator i;
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
v = i->second;
auto resolvedPath = getConcurrent(*importResolutionCache, path);
if (!resolvedPath) {
resolvedPath = resolveExprPath(path);
importResolutionCache->emplace(path, *resolvedPath);
}
if (auto v2 = getConcurrent(*fileEvalCache, *resolvedPath)) {
forceValue(**v2, noPos);
v = **v2;
return;
}
auto resolvedPath = resolveExprPath(path);
if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) {
v = i->second;
return;
}
Value * vExpr;
// FIXME: put ExprParseFile on the stack instead of the heap once
// https://github.com/NixOS/nix/pull/13930 is merged. That will ensure
// the post-condition that `expr` is unreachable after
// `forceValue()` returns.
auto expr = new ExprParseFile{*resolvedPath, mustBeTrivial};
printTalkative("evaluating file '%1%'", resolvedPath);
Expr * e = nullptr;
fileEvalCache->try_emplace_and_cvisit(
*resolvedPath,
nullptr,
[&](auto & i) {
vExpr = allocValue();
vExpr->mkThunk(&baseEnv, expr);
i.second = vExpr;
},
[&](auto & i) { vExpr = i.second; });
auto j = fileParseCache.find(resolvedPath);
if (j != fileParseCache.end())
e = j->second;
forceValue(*vExpr, noPos);
if (!e)
e = parseExprFromFile(resolvedPath);
fileParseCache.emplace(resolvedPath, e);
try {
auto dts = debugRepl ? makeDebugTraceStacker(
*this,
*e,
this->baseEnv,
e->getPos(),
"while evaluating the file '%1%':",
resolvedPath.to_string())
: nullptr;
// Enforce that 'flake.nix' is a direct attrset, not a
// computation.
if (mustBeTrivial && !(dynamic_cast<ExprAttrs *>(e)))
error<EvalError>("file '%s' must be an attribute set", path).debugThrow();
eval(e, v);
} catch (Error & e) {
addErrorTrace(e, "while evaluating the file '%1%':", resolvedPath.to_string());
throw;
}
fileEvalCache.emplace(resolvedPath, v);
if (path != resolvedPath)
fileEvalCache.emplace(path, v);
v = *vExpr;
}
void EvalState::resetFileCache()
{
fileEvalCache.clear();
fileParseCache.clear();
importResolutionCache->clear();
fileEvalCache->clear();
inputCache->clear();
}
@@ -1221,7 +1180,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
{
Env & inheritEnv = state.allocEnv(inheritFromExprs->size());
Env & inheritEnv = state.mem.allocEnv(inheritFromExprs->size());
inheritEnv.up = &up;
Displacement displ = 0;
@@ -1240,12 +1199,12 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
if (recursive) {
/* Create a new environment that contains the attributes in
this `rec'. */
Env & env2(state.allocEnv(attrs.size()));
Env & env2(state.mem.allocEnv(attrs.size()));
env2.up = &env;
dynamicEnv = &env2;
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env2) : nullptr;
AttrDefs::iterator overrides = attrs.find(state.sOverrides);
AttrDefs::iterator overrides = attrs.find(state.s.overrides);
bool hasOverrides = overrides != attrs.end();
/* The recursive attributes are evaluated in the new
@@ -1277,7 +1236,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
*vOverrides,
[&]() { return vOverrides->determinePos(noPos); },
"while evaluating the `__overrides` attribute");
bindings.grow(state.allocBindings(bindings.capacity() + vOverrides->attrs()->size()));
bindings.grow(state.buildBindings(bindings.capacity() + vOverrides->attrs()->size()));
for (auto & i : *vOverrides->attrs()) {
AttrDefs::iterator j = attrs.find(i.name);
if (j != attrs.end()) {
@@ -1332,7 +1291,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
{
/* Create a new environment that contains the attributes in this
`let'. */
Env & env2(state.allocEnv(attrs->attrs.size()));
Env & env2(state.mem.allocEnv(attrs->attrs.size()));
env2.up = &env;
Env * inheritEnv = attrs->inheritFromExprs ? attrs->buildInheritFromEnv(state, env2) : nullptr;
@@ -1363,7 +1322,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
Value * ExprList::maybeThunk(EvalState & state, Env & env)
{
if (elems.empty()) {
return &state.vEmptyList;
return &Value::vEmptyList;
}
return Expr::maybeThunk(state, env);
}
@@ -1375,7 +1334,7 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
v = *v2;
}
static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath)
static std::string showAttrPath(EvalState & state, Env & env, std::span<const AttrName> attrPath)
{
std::ostringstream out;
bool first = true;
@@ -1411,10 +1370,10 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
env,
getPos(),
"while evaluating the attribute '%1%'",
showAttrPath(state, env, attrPath))
showAttrPath(state, env, getAttrPath()))
: nullptr;
for (auto & i : attrPath) {
for (auto & i : getAttrPath()) {
state.nrLookups++;
const Attr * j;
auto name = getName(i, state, env);
@@ -1452,7 +1411,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
auto origin = std::get_if<SourcePath>(&pos2r.origin);
if (!(origin && *origin == state.derivationInternal))
state.addErrorTrace(
e, pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath));
e, pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, getAttrPath()));
}
throw;
}
@@ -1463,13 +1422,13 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
Symbol ExprSelect::evalExceptFinalSelect(EvalState & state, Env & env, Value & attrs)
{
Value vTmp;
Symbol name = getName(attrPath[attrPath.size() - 1], state, env);
Symbol name = getName(attrPathStart[nAttrPath - 1], state, env);
if (attrPath.size() == 1) {
if (nAttrPath == 1) {
e->eval(state, env, vTmp);
} else {
ExprSelect init(*this);
init.attrPath.pop_back();
init.nAttrPath--;
init.eval(state, env, vTmp);
}
attrs = vTmp;
@@ -1538,7 +1497,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
ExprLambda & lambda(*vCur.lambda().fun);
auto size = (!lambda.arg ? 0 : 1) + (lambda.hasFormals() ? lambda.formals->formals.size() : 0);
Env & env2(allocEnv(size));
Env & env2(mem.allocEnv(size));
env2.up = vCur.lambda().env;
Displacement displ = 0;
@@ -1717,7 +1676,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
}
}
else if (vCur.type() == nAttrs && (functor = vCur.attrs()->get(sFunctor))) {
else if (vCur.type() == nAttrs && (functor = vCur.attrs()->get(s.functor))) {
/* 'vCur' may be allocated on the stack of the calling
function, but for functors we may keep a reference, so
heap-allocate a copy and use that instead. */
@@ -1779,8 +1738,8 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
forceValue(fun, pos);
if (fun.type() == nAttrs) {
auto found = fun.attrs()->find(sFunctor);
if (found != fun.attrs()->end()) {
auto found = fun.attrs()->get(s.functor);
if (found) {
Value * v = allocValue();
callFunction(*found->value, fun, *v, pos);
forceValue(*v, pos);
@@ -1827,7 +1786,7 @@ https://nix.dev/manual/nix/stable/language/syntax.html#functions.)",
void ExprWith::eval(EvalState & state, Env & env, Value & v)
{
Env & env2(state.allocEnv(1));
Env & env2(state.mem.allocEnv(1));
env2.up = &env;
env2.values[0] = attrs->maybeThunk(state, env);
@@ -1845,7 +1804,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
if (!state.evalBool(env, cond, pos, "in the condition of the assert statement")) {
std::ostringstream out;
cond->show(state.symbols, out);
auto exprStr = toView(out);
auto exprStr = out.view();
if (auto eq = dynamic_cast<ExprOpEq *>(cond)) {
try {
@@ -1909,51 +1868,113 @@ void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|| state.evalBool(env, e2, pos, "in the right operand of the IMPL (->) operator"));
}
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
void ExprOpUpdate::eval(EvalState & state, Value & v, Value & v1, Value & v2)
{
Value v1, v2;
state.evalAttrs(env, e1, v1, pos, "in the left operand of the update (//) operator");
state.evalAttrs(env, e2, v2, pos, "in the right operand of the update (//) operator");
state.nrOpUpdates++;
if (v1.attrs()->size() == 0) {
const Bindings & bindings1 = *v1.attrs();
if (bindings1.empty()) {
v = v2;
return;
}
if (v2.attrs()->size() == 0) {
const Bindings & bindings2 = *v2.attrs();
if (bindings2.empty()) {
v = v1;
return;
}
auto attrs = state.buildBindings(v1.attrs()->size() + v2.attrs()->size());
/* Simple heuristic for determining whether attrs2 should be "layered" on top of
attrs1 instead of copying to a new Bindings. */
bool shouldLayer = [&]() -> bool {
if (bindings1.isLayerListFull())
return false;
if (bindings2.size() > state.settings.bindingsUpdateLayerRhsSizeThreshold)
return false;
return true;
}();
if (shouldLayer) {
auto attrs = state.buildBindings(bindings2.size());
attrs.layerOnTopOf(bindings1);
std::ranges::copy(bindings2, std::back_inserter(attrs));
v.mkAttrs(attrs.alreadySorted());
state.nrOpUpdateValuesCopied += bindings2.size();
return;
}
auto attrs = state.buildBindings(bindings1.size() + bindings2.size());
/* Merge the sets, preferring values from the second set. Make
sure to keep the resulting vector in sorted order. */
auto i = v1.attrs()->begin();
auto j = v2.attrs()->begin();
auto i = bindings1.begin();
auto j = bindings2.begin();
while (i != v1.attrs()->end() && j != v2.attrs()->end()) {
while (i != bindings1.end() && j != bindings2.end()) {
if (i->name == j->name) {
attrs.insert(*j);
++i;
++j;
} else if (i->name < j->name)
attrs.insert(*i++);
else
attrs.insert(*j++);
} else if (i->name < j->name) {
attrs.insert(*i);
++i;
} else {
attrs.insert(*j);
++j;
}
}
while (i != v1.attrs()->end())
attrs.insert(*i++);
while (j != v2.attrs()->end())
attrs.insert(*j++);
while (i != bindings1.end()) {
attrs.insert(*i);
++i;
}
while (j != bindings2.end()) {
attrs.insert(*j);
++j;
}
v.mkAttrs(attrs.alreadySorted());
state.nrOpUpdateValuesCopied += v.attrs()->size();
}
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
{
UpdateQueue q;
evalForUpdate(state, env, q);
v.mkAttrs(&Bindings::emptyBindings);
for (auto & rhs : std::views::reverse(q)) {
/* Remember that queue is sorted rightmost attrset first. */
eval(state, /*v=*/v, /*v1=*/v, /*v2=*/rhs);
}
}
void Expr::evalForUpdate(EvalState & state, Env & env, UpdateQueue & q, std::string_view errorCtx)
{
Value v;
state.evalAttrs(env, this, v, getPos(), errorCtx);
q.push_back(v);
}
void ExprOpUpdate::evalForUpdate(EvalState & state, Env & env, UpdateQueue & q)
{
/* Output rightmost attrset first to the merge queue as the one
with the most priority. */
e2->evalForUpdate(state, env, q, "in the right operand of the update (//) operator");
e1->evalForUpdate(state, env, q, "in the left operand of the update (//) operator");
}
void ExprOpUpdate::evalForUpdate(EvalState & state, Env & env, UpdateQueue & q, std::string_view errorCtx)
{
evalForUpdate(state, env, q);
}
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
{
Value v1;
@@ -2230,10 +2251,10 @@ bool EvalState::forceBool(Value & v, const PosIdx pos, std::string_view errorCtx
return v.boolean();
}
Bindings::const_iterator EvalState::getAttr(Symbol attrSym, const Bindings * attrSet, std::string_view errorCtx)
const Attr * EvalState::getAttr(Symbol attrSym, const Bindings * attrSet, std::string_view errorCtx)
{
auto value = attrSet->find(attrSym);
if (value == attrSet->end()) {
auto value = attrSet->get(attrSym);
if (!value) {
error<TypeError>("attribute '%s' missing", symbols[attrSym]).withTrace(noPos, errorCtx).debugThrow();
}
return value;
@@ -2241,7 +2262,7 @@ Bindings::const_iterator EvalState::getAttr(Symbol attrSym, const Bindings * att
bool EvalState::isFunctor(const Value & fun) const
{
return fun.type() == nAttrs && fun.attrs()->find(sFunctor) != fun.attrs()->end();
return fun.type() == nAttrs && fun.attrs()->get(s.functor);
}
void EvalState::forceFunction(Value & v, const PosIdx pos, std::string_view errorCtx)
@@ -2310,7 +2331,7 @@ bool EvalState::isDerivation(Value & v)
{
if (v.type() != nAttrs)
return false;
auto i = v.attrs()->get(sType);
auto i = v.attrs()->get(s.type);
if (!i)
return false;
forceValue(*i->value, i->pos);
@@ -2322,8 +2343,8 @@ bool EvalState::isDerivation(Value & v)
std::optional<std::string>
EvalState::tryAttrsToString(const PosIdx pos, Value & v, NixStringContext & context, bool coerceMore, bool copyToStore)
{
auto i = v.attrs()->find(sToString);
if (i != v.attrs()->end()) {
auto i = v.attrs()->get(s.toString);
if (i) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(
@@ -2368,8 +2389,8 @@ BackedStringView EvalState::coerceToString(
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
if (maybeString)
return std::move(*maybeString);
auto i = v.attrs()->find(sOutPath);
if (i == v.attrs()->end()) {
auto i = v.attrs()->get(s.outPath);
if (!i) {
error<TypeError>(
"cannot coerce %1% to a string: %2%", showType(v), ValuePrinter(*this, v, errorPrintOptions))
.withTrace(pos, errorCtx)
@@ -2437,7 +2458,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
if (nix::isDerivation(path.path.abs()))
error<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
auto dstPathCached = get(*srcToStore.lock(), path);
auto dstPathCached = getConcurrent(*srcToStore, path);
auto dstPath = dstPathCached ? *dstPathCached : [&]() {
auto dstPath = fetchToStore(
@@ -2450,7 +2471,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
nullptr,
repair);
allowPath(dstPath);
srcToStore.lock()->try_emplace(path, dstPath);
srcToStore->try_emplace(path, dstPath);
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
return dstPath;
}();
@@ -2475,8 +2496,8 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
/* Similarly, handle __toString where the result may be a path
value. */
if (v.type() == nAttrs) {
auto i = v.attrs()->find(sToString);
if (i != v.attrs()->end()) {
auto i = v.attrs()->get(s.toString);
if (i) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToPath(pos, v1, context, errorCtx);
@@ -2665,8 +2686,8 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
case nAttrs: {
if (isDerivation(v1) && isDerivation(v2)) {
auto i = v1.attrs()->get(sOutPath);
auto j = v2.attrs()->get(sOutPath);
auto i = v1.attrs()->get(s.outPath);
auto j = v2.attrs()->get(s.outPath);
if (i && j) {
try {
assertEqValues(*i->value, *j->value, pos, errorCtx);
@@ -2819,8 +2840,8 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
/* If both sets denote a derivation (type = "derivation"),
then compare their outPaths. */
if (isDerivation(v1) && isDerivation(v2)) {
auto i = v1.attrs()->get(sOutPath);
auto j = v2.attrs()->get(sOutPath);
auto i = v1.attrs()->get(s.outPath);
auto j = v2.attrs()->get(s.outPath);
if (i && j)
return eqValues(*i->value, *j->value, pos, errorCtx);
}
@@ -2872,11 +2893,11 @@ bool EvalState::fullGC()
#endif
}
bool Counter::enabled = getEnv("NIX_SHOW_STATS").value_or("0") != "0";
void EvalState::maybePrintStats()
{
bool showStats = getEnv("NIX_SHOW_STATS").value_or("0") != "0";
if (showStats) {
if (Counter::enabled) {
// Make the final heap size more deterministic.
#if NIX_USE_BOEHMGC
if (!fullGC()) {
@@ -2889,16 +2910,15 @@ void EvalState::maybePrintStats()
void EvalState::printStatistics()
{
#ifndef _WIN32 // TODO use portable implementation
struct rusage buf;
getrusage(RUSAGE_SELF, &buf);
float cpuTime = buf.ru_utime.tv_sec + ((float) buf.ru_utime.tv_usec / 1000000);
#endif
std::chrono::microseconds cpuTimeDuration = getCpuUserTime();
float cpuTime = std::chrono::duration_cast<std::chrono::duration<float>>(cpuTimeDuration).count();
uint64_t bEnvs = nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *);
uint64_t bLists = nrListElems * sizeof(Value *);
uint64_t bValues = nrValues * sizeof(Value);
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
auto & memstats = mem.getStats();
uint64_t bEnvs = memstats.nrEnvs * sizeof(Env) + memstats.nrValuesInEnvs * sizeof(Value *);
uint64_t bLists = memstats.nrListElems * sizeof(Value *);
uint64_t bValues = memstats.nrValues * sizeof(Value);
uint64_t bAttrsets = memstats.nrAttrsets * sizeof(Bindings) + memstats.nrAttrsInAttrsets * sizeof(Attr);
#if NIX_USE_BOEHMGC
GC_word heapSize, totalBytes;
@@ -2915,33 +2935,27 @@ void EvalState::printStatistics()
if (outPath != "-")
fs.open(outPath, std::fstream::out);
json topObj = json::object();
#ifndef _WIN32 // TODO implement
topObj["cpuTime"] = cpuTime;
#endif
topObj["time"] = {
#ifndef _WIN32 // TODO implement
{"cpu", cpuTime},
#endif
#if NIX_USE_BOEHMGC
{GC_is_incremental_mode() ? "gcNonIncremental" : "gc", gcFullOnlyTime},
# ifndef _WIN32 // TODO implement
{GC_is_incremental_mode() ? "gcNonIncrementalFraction" : "gcFraction", gcFullOnlyTime / cpuTime},
# endif
#endif
};
topObj["envs"] = {
{"number", nrEnvs},
{"elements", nrValuesInEnvs},
{"number", memstats.nrEnvs.load()},
{"elements", memstats.nrValuesInEnvs.load()},
{"bytes", bEnvs},
};
topObj["nrExprs"] = Expr::nrExprs;
topObj["nrExprs"] = Expr::nrExprs.load();
topObj["list"] = {
{"elements", nrListElems},
{"elements", memstats.nrListElems.load()},
{"bytes", bLists},
{"concats", nrListConcats},
{"concats", nrListConcats.load()},
};
topObj["values"] = {
{"number", nrValues},
{"number", memstats.nrValues.load()},
{"bytes", bValues},
};
topObj["symbols"] = {
@@ -2949,9 +2963,9 @@ void EvalState::printStatistics()
{"bytes", symbols.totalSize()},
};
topObj["sets"] = {
{"number", nrAttrsets},
{"number", memstats.nrAttrsets.load()},
{"bytes", bAttrsets},
{"elements", nrAttrsInAttrsets},
{"elements", memstats.nrAttrsInAttrsets.load()},
};
topObj["sizes"] = {
{"Env", sizeof(Env)},
@@ -2959,13 +2973,13 @@ void EvalState::printStatistics()
{"Bindings", sizeof(Bindings)},
{"Attr", sizeof(Attr)},
};
topObj["nrOpUpdates"] = nrOpUpdates;
topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied;
topObj["nrThunks"] = nrThunks;
topObj["nrAvoided"] = nrAvoided;
topObj["nrLookups"] = nrLookups;
topObj["nrPrimOpCalls"] = nrPrimOpCalls;
topObj["nrFunctionCalls"] = nrFunctionCalls;
topObj["nrOpUpdates"] = nrOpUpdates.load();
topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied.load();
topObj["nrThunks"] = nrThunks.load();
topObj["nrAvoided"] = nrAvoided.load();
topObj["nrLookups"] = nrLookups.load();
topObj["nrPrimOpCalls"] = nrPrimOpCalls.load();
topObj["nrFunctionCalls"] = nrFunctionCalls.load();
#if NIX_USE_BOEHMGC
topObj["gc"] = {
{"heapSize", heapSize},
@@ -3112,6 +3126,11 @@ SourcePath EvalState::findFile(const LookupPath & lookupPath, const std::string_
auto res = (r / CanonPath(suffix)).resolveSymlinks();
if (res.pathExists())
return res;
// Backward compatibility hack: throw an exception if access
// to this path is not allowed.
if (auto accessor = res.accessor.dynamic_pointer_cast<FilteringSourceAccessor>())
accessor->checkAccess(res.path);
}
if (hasPrefix(path, "nix/"))
@@ -3166,7 +3185,7 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
/* Allow access to paths in the search path. */
if (initAccessControl) {
allowPath(path.path.abs());
allowPathLegacy(path.path.abs());
if (store->isInStore(path.path.abs())) {
try {
allowClosure(store->toStorePath(path.path.abs()).first);
@@ -3178,6 +3197,11 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
if (path.resolveSymlinks().pathExists())
return finish(std::move(path));
else {
// Backward compatibility hack: throw an exception if access
// to this path is not allowed.
if (auto accessor = path.accessor.dynamic_pointer_cast<FilteringSourceAccessor>())
accessor->checkAccess(path.path);
logWarning({.msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value)});
}
}
@@ -3197,7 +3221,7 @@ Expr * EvalState::parse(
}
auto result = parseExprFromBuf(
text, length, origin, basePath, symbols, settings, positions, *docComments, rootFS, exprSymbols);
text, length, origin, basePath, mem.exprs.alloc, symbols, settings, positions, *docComments, rootFS);
result->bindVars(*this, staticEnv);

View File

@@ -45,8 +45,8 @@ PackageInfo::PackageInfo(EvalState & state, ref<Store> store, const std::string
std::string PackageInfo::queryName() const
{
if (name == "" && attrs) {
auto i = attrs->find(state->sName);
if (i == attrs->end())
auto i = attrs->get(state->s.name);
if (!i)
state->error<TypeError>("derivation name missing").debugThrow();
name = state->forceStringNoCtx(*i->value, noPos, "while evaluating the 'name' attribute of a derivation");
}
@@ -56,11 +56,10 @@ std::string PackageInfo::queryName() const
std::string PackageInfo::querySystem() const
{
if (system == "" && attrs) {
auto i = attrs->find(state->sSystem);
auto i = attrs->get(state->s.system);
system =
i == attrs->end()
? "unknown"
: state->forceStringNoCtx(*i->value, i->pos, "while evaluating the 'system' attribute of a derivation");
!i ? "unknown"
: state->forceStringNoCtx(*i->value, i->pos, "while evaluating the 'system' attribute of a derivation");
}
return system;
}
@@ -68,7 +67,7 @@ std::string PackageInfo::querySystem() const
std::optional<StorePath> PackageInfo::queryDrvPath() const
{
if (!drvPath && attrs) {
if (auto i = attrs->get(state->sDrvPath)) {
if (auto i = attrs->get(state->s.drvPath)) {
NixStringContext context;
auto found = state->coerceToStorePath(
i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation");
@@ -95,9 +94,9 @@ StorePath PackageInfo::requireDrvPath() const
StorePath PackageInfo::queryOutPath() const
{
if (!outPath && attrs) {
auto i = attrs->find(state->sOutPath);
auto i = attrs->get(state->s.outPath);
NixStringContext context;
if (i != attrs->end())
if (i)
outPath = state->coerceToStorePath(
i->pos, *i->value, context, "while evaluating the output path of a derivation");
}
@@ -111,7 +110,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
if (outputs.empty()) {
/* Get the outputs list. */
const Attr * i;
if (attrs && (i = attrs->get(state->sOutputs))) {
if (attrs && (i = attrs->get(state->s.outputs))) {
state->forceList(*i->value, i->pos, "while evaluating the 'outputs' attribute of a derivation");
/* For each output... */
@@ -127,7 +126,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
state->forceAttrs(*out->value, i->pos, "while evaluating an output of a derivation");
/* And evaluate its outPath attribute. */
auto outPath = out->value->attrs()->get(state->sOutPath);
auto outPath = out->value->attrs()->get(state->s.outPath);
if (!outPath)
continue; // FIXME: throw error?
NixStringContext context;
@@ -146,7 +145,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
return outputs;
const Attr * i;
if (attrs && (i = attrs->get(state->sOutputSpecified))
if (attrs && (i = attrs->get(state->s.outputSpecified))
&& state->forceBool(*i->value, i->pos, "while evaluating the 'outputSpecified' attribute of a derivation")) {
Outputs result;
auto out = outputs.find(queryOutputName());
@@ -181,7 +180,7 @@ PackageInfo::Outputs PackageInfo::queryOutputs(bool withPaths, bool onlyOutputsT
std::string PackageInfo::queryOutputName() const
{
if (outputName == "" && attrs) {
auto i = attrs->get(state->sOutputName);
auto i = attrs->get(state->s.outputName);
outputName =
i ? state->forceStringNoCtx(*i->value, noPos, "while evaluating the output name of a derivation") : "";
}
@@ -194,7 +193,7 @@ const Bindings * PackageInfo::getMeta()
return meta;
if (!attrs)
return 0;
auto a = attrs->get(state->sMeta);
auto a = attrs->get(state->s.meta);
if (!a)
return 0;
state->forceAttrs(*a->value, a->pos, "while evaluating the 'meta' attribute of a derivation");
@@ -221,7 +220,7 @@ bool PackageInfo::checkMeta(Value & v)
return false;
return true;
} else if (v.type() == nAttrs) {
if (v.attrs()->get(state->sOutPath))
if (v.attrs()->get(state->s.outPath))
return false;
for (auto & i : *v.attrs())
if (!checkMeta(*i.value))
@@ -411,7 +410,7 @@ static void getDerivations(
should we recurse into it? => Only if it has a
`recurseForDerivations = true' attribute. */
if (i->value->type() == nAttrs) {
auto j = i->value->attrs()->get(state.sRecurseForDerivations);
auto j = i->value->attrs()->get(state.s.recurseForDerivations);
if (j
&& state.forceBool(
*j->value, j->pos, "while evaluating the attribute `recurseForDerivations`"))

View File

@@ -4,11 +4,17 @@
#include "nix/expr/nixexpr.hh"
#include "nix/expr/symbol-table.hh"
#include <boost/container/static_vector.hpp>
#include <boost/iterator/function_output_iterator.hpp>
#include <algorithm>
#include <functional>
#include <ranges>
#include <optional>
namespace nix {
class EvalState;
class EvalMemory;
struct Value;
/**
@@ -46,141 +52,466 @@ static_assert(
* by its size and its capacity, the capacity being the number of Attr
* elements allocated after this structure, while the size corresponds to
* the number of elements already inserted in this structure.
*
* Bindings can be efficiently `//`-composed into an intrusive linked list of "layers"
* that saves on copies and allocations. Each lookup (@see Bindings::get) traverses
* this linked list until a matching attribute is found (thus overlays earlier in
* the list take precedence). For iteration over the whole Bindings, an on-the-fly
* k-way merge is performed by Bindings::iterator class.
*/
class Bindings
{
public:
typedef uint32_t size_t;
using size_type = uint32_t;
PosIdx pos;
/**
* An instance of bindings objects with 0 attributes.
* This object must never be modified.
*/
static Bindings emptyBindings;
private:
size_t size_, capacity_;
/**
* Number of attributes in the attrs FAM (Flexible Array Member).
*/
size_type numAttrs = 0;
/**
* Number of attributes with unique names in the layer chain.
*
* This is the *real* user-facing size of bindings, whereas @ref numAttrs is
* an implementation detail of the data structure.
*/
size_type numAttrsInChain = 0;
/**
* Length of the layers list.
*/
uint32_t numLayers = 1;
/**
* Bindings that this attrset is "layered" on top of.
*/
const Bindings * baseLayer = nullptr;
/**
* Flexible array member of attributes.
*/
Attr attrs[0];
Bindings(size_t capacity)
: size_(0)
, capacity_(capacity)
{
}
Bindings() = default;
Bindings(const Bindings &) = delete;
Bindings(Bindings &&) = delete;
Bindings & operator=(const Bindings &) = delete;
Bindings & operator=(Bindings &&) = delete;
Bindings(const Bindings & bindings) = delete;
friend class BindingsBuilder;
/**
* Maximum length of the Bindings layer chains.
*/
static constexpr unsigned maxLayers = 8;
public:
size_t size() const
size_type size() const
{
return size_;
return numAttrsInChain;
}
bool empty() const
{
return !size_;
return size() == 0;
}
typedef Attr * iterator;
class iterator
{
public:
using value_type = Attr;
using pointer = const value_type *;
using reference = const value_type &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
typedef const Attr * const_iterator;
friend class Bindings;
private:
struct BindingsCursor
{
/**
* Attr that the cursor currently points to.
*/
pointer current;
/**
* One past the end pointer to the contiguous buffer of Attrs.
*/
pointer end;
/**
* Priority of the value. Lesser values have more priority (i.e. they override
* attributes that appear later in the linked list of Bindings).
*/
uint32_t priority;
pointer operator->() const noexcept
{
return current;
}
reference get() const noexcept
{
return *current;
}
bool empty() const noexcept
{
return current == end;
}
void increment() noexcept
{
++current;
}
void consume(Symbol name) noexcept
{
while (!empty() && current->name <= name)
++current;
}
GENERATE_CMP(BindingsCursor, me->current->name, me->priority)
};
using QueueStorageType = boost::container::static_vector<BindingsCursor, maxLayers>;
/**
* Comparator implementing the override priority / name ordering
* for BindingsCursor.
*/
static constexpr auto comp = std::greater<BindingsCursor>();
/**
* A priority queue used to implement an on-the-fly k-way merge.
*/
QueueStorageType cursorHeap;
/**
* The attribute the iterator currently points to.
*/
pointer current = nullptr;
/**
* Whether iterating over a single attribute and not a merge chain.
*/
bool doMerge = true;
void push(BindingsCursor cursor) noexcept
{
cursorHeap.push_back(cursor);
std::ranges::make_heap(cursorHeap, comp);
}
[[nodiscard]] BindingsCursor pop() noexcept
{
std::ranges::pop_heap(cursorHeap, comp);
auto cursor = cursorHeap.back();
cursorHeap.pop_back();
return cursor;
}
iterator & finished() noexcept
{
current = nullptr;
return *this;
}
void next(BindingsCursor cursor) noexcept
{
current = &cursor.get();
cursor.increment();
if (!cursor.empty())
push(cursor);
}
std::optional<BindingsCursor> consumeAllUntilCurrentName() noexcept
{
auto cursor = pop();
Symbol lastHandledName = current->name;
while (cursor->name <= lastHandledName) {
cursor.consume(lastHandledName);
if (!cursor.empty())
push(cursor);
if (cursorHeap.empty())
return std::nullopt;
cursor = pop();
}
return cursor;
}
explicit iterator(const Bindings & attrs) noexcept
: doMerge(attrs.baseLayer)
{
auto pushBindings = [this, priority = unsigned{0}](const Bindings & layer) mutable {
auto first = layer.attrs;
push(
BindingsCursor{
.current = first,
.end = first + layer.numAttrs,
.priority = priority++,
});
};
if (!doMerge) {
if (attrs.empty())
return;
current = attrs.attrs;
pushBindings(attrs);
return;
}
const Bindings * layer = &attrs;
while (layer) {
if (layer->numAttrs != 0)
pushBindings(*layer);
layer = layer->baseLayer;
}
if (cursorHeap.empty())
return;
next(pop());
}
public:
iterator() = default;
reference operator*() const noexcept
{
return *current;
}
pointer operator->() const noexcept
{
return current;
}
iterator & operator++() noexcept
{
if (!doMerge) {
++current;
if (current == cursorHeap.front().end)
return finished();
return *this;
}
if (cursorHeap.empty())
return finished();
auto cursor = consumeAllUntilCurrentName();
if (!cursor)
return finished();
next(*cursor);
return *this;
}
iterator operator++(int) noexcept
{
iterator tmp = *this;
++*this;
return tmp;
}
bool operator==(const iterator & rhs) const noexcept
{
return current == rhs.current;
}
};
using const_iterator = iterator;
void push_back(const Attr & attr)
{
assert(size_ < capacity_);
attrs[size_++] = attr;
attrs[numAttrs++] = attr;
numAttrsInChain = numAttrs;
}
const_iterator find(Symbol name) const
/**
* Get attribute by name or nullptr if no such attribute exists.
*/
const Attr * get(Symbol name) const noexcept
{
Attr key(name, 0);
const_iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name)
return i;
return end();
}
auto getInChunk = [key = Attr{name, nullptr}](const Bindings & chunk) -> const Attr * {
auto first = chunk.attrs;
auto last = first + chunk.numAttrs;
const Attr * i = std::lower_bound(first, last, key);
if (i != last && i->name == key.name)
return i;
return nullptr;
};
const Bindings * currentChunk = this;
while (currentChunk) {
const Attr * maybeAttr = getInChunk(*currentChunk);
if (maybeAttr)
return maybeAttr;
currentChunk = currentChunk->baseLayer;
}
const Attr * get(Symbol name) const
{
Attr key(name, 0);
const_iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name)
return &*i;
return nullptr;
}
iterator begin()
/**
* Check if the layer chain is full.
*/
bool isLayerListFull() const noexcept
{
return &attrs[0];
return numLayers == Bindings::maxLayers;
}
iterator end()
/**
* Test if the length of the linked list of layers is greater than 1.
*/
bool isLayered() const noexcept
{
return &attrs[size_];
return numLayers > 1;
}
const_iterator begin() const
{
return &attrs[0];
return const_iterator(*this);
}
const_iterator end() const
{
return &attrs[size_];
return const_iterator();
}
Attr & operator[](size_t pos)
Attr & operator[](size_type pos)
{
if (isLayered()) [[unlikely]]
unreachable();
return attrs[pos];
}
const Attr & operator[](size_t pos) const
const Attr & operator[](size_type pos) const
{
if (isLayered()) [[unlikely]]
unreachable();
return attrs[pos];
}
void sort();
size_t capacity() const
{
return capacity_;
}
/**
* Returns the attributes in lexicographically sorted order.
*/
std::vector<const Attr *> lexicographicOrder(const SymbolTable & symbols) const
{
std::vector<const Attr *> res;
res.reserve(size_);
for (size_t n = 0; n < size_; n++)
res.emplace_back(&attrs[n]);
std::sort(res.begin(), res.end(), [&](const Attr * a, const Attr * b) {
res.reserve(size());
std::ranges::transform(*this, std::back_inserter(res), [](const Attr & a) { return &a; });
std::ranges::sort(res, [&](const Attr * a, const Attr * b) {
std::string_view sa = symbols[a->name], sb = symbols[b->name];
return sa < sb;
});
return res;
}
friend class EvalState;
friend class EvalMemory;
};
static_assert(std::forward_iterator<Bindings::iterator>);
static_assert(std::ranges::forward_range<Bindings>);
/**
* A wrapper around Bindings that ensures that its always in sorted
* order at the end. The only way to consume a BindingsBuilder is to
* call finish(), which sorts the bindings.
*/
class BindingsBuilder
class BindingsBuilder final
{
Bindings * bindings;
public:
// needed by std::back_inserter
using value_type = Attr;
using size_type = Bindings::size_type;
EvalState & state;
private:
Bindings * bindings;
Bindings::size_type capacity_;
BindingsBuilder(EvalState & state, Bindings * bindings)
friend class EvalMemory;
BindingsBuilder(EvalMemory & mem, SymbolTable & symbols, Bindings * bindings, size_type capacity)
: bindings(bindings)
, state(state)
, capacity_(capacity)
, mem(mem)
, symbols(symbols)
{
}
bool hasBaseLayer() const noexcept
{
return bindings->baseLayer;
}
/**
* If the bindings gets "layered" on top of another we need to recalculate
* the number of unique attributes in the chain.
*
* This is done by either iterating over the base "layer" and the newly added
* attributes and counting duplicates. If the base "layer" is big this approach
* is inefficient and we fall back to doing per-element binary search in the base
* "layer".
*/
void finishSizeIfNecessary()
{
if (!hasBaseLayer())
return;
auto & base = *bindings->baseLayer;
auto attrs = std::span(bindings->attrs, bindings->numAttrs);
Bindings::size_type duplicates = 0;
/* If the base bindings is smaller than the newly added attributes
iterate using std::set_intersection to run in O(|base| + |attrs|) =
O(|attrs|). Otherwise use an O(|attrs| * log(|base|)) per-attr binary
search to check for duplicates. Note that if we are in this code path then
|attrs| <= bindingsUpdateLayerRhsSizeThreshold, which 16 by default. We are
optimizing for the case when a small attribute set gets "layered" on top of
a much larger one. When attrsets are already small it's fine to do a linear
scan, but we should avoid expensive iterations over large "base" attrsets. */
if (attrs.size() > base.size()) {
std::set_intersection(
base.begin(),
base.end(),
attrs.begin(),
attrs.end(),
boost::make_function_output_iterator([&]([[maybe_unused]] auto && _) { ++duplicates; }));
} else {
for (const auto & attr : attrs) {
if (base.get(attr.name))
++duplicates;
}
}
bindings->numAttrsInChain = base.numAttrsInChain + attrs.size() - duplicates;
}
public:
std::reference_wrapper<EvalMemory> mem;
std::reference_wrapper<SymbolTable> symbols;
void insert(Symbol name, Value * value, PosIdx pos = noPos)
{
insert(Attr(name, value, pos));
@@ -193,9 +524,26 @@ public:
void push_back(const Attr & attr)
{
assert(bindings->numAttrs < capacity_);
bindings->push_back(attr);
}
/**
* "Layer" the newly constructured Bindings on top of another attribute set.
*
* This effectively performs an attribute set merge, while giving preference
* to attributes from the newly constructed Bindings in case of duplicate attribute
* names.
*
* This operation amortizes the need to copy over all attributes and allows
* for efficient implementation of attribute set merges (ExprOpUpdate::eval).
*/
void layerOnTopOf(const Bindings & base) noexcept
{
bindings->baseLayer = &base;
bindings->numLayers = base.numLayers + 1;
}
Value & alloc(Symbol name, PosIdx pos = noPos);
Value & alloc(std::string_view name, PosIdx pos = noPos);
@@ -203,24 +551,26 @@ public:
Bindings * finish()
{
bindings->sort();
finishSizeIfNecessary();
return bindings;
}
Bindings * alreadySorted()
{
finishSizeIfNecessary();
return bindings;
}
size_t capacity()
size_t capacity() const noexcept
{
return bindings->capacity();
return capacity_;
}
void grow(Bindings * newBindings)
void grow(BindingsBuilder newBindings)
{
for (auto & i : *bindings)
newBindings->push_back(i);
bindings = newBindings;
newBindings.push_back(i);
std::swap(*this, newBindings);
}
friend struct ExprAttrs;

View File

@@ -0,0 +1,70 @@
#pragma once
#include <atomic>
#include <cstdint>
namespace nix {
/**
* An atomic counter aligned on a cache line to prevent false sharing.
* The counter is only enabled when the `NIX_SHOW_STATS` environment
* variable is set. This is to prevent contention on these counters
* when multi-threaded evaluation is enabled.
*/
struct alignas(64) Counter
{
using value_type = uint64_t;
std::atomic<value_type> inner{0};
static bool enabled;
Counter() {}
operator value_type() const noexcept
{
return inner;
}
void operator=(value_type n) noexcept
{
inner = n;
}
value_type load() const noexcept
{
return inner;
}
value_type operator++() noexcept
{
return enabled ? ++inner : 0;
}
value_type operator++(int) noexcept
{
return enabled ? inner++ : 0;
}
value_type operator--() noexcept
{
return enabled ? --inner : 0;
}
value_type operator--(int) noexcept
{
return enabled ? inner-- : 0;
}
value_type operator+=(value_type n) noexcept
{
return enabled ? inner += n : 0;
}
value_type operator-=(value_type n) noexcept
{
return enabled ? inner -= n : 0;
}
};
} // namespace nix

View File

@@ -26,7 +26,7 @@ inline void * allocBytes(size_t n)
}
[[gnu::always_inline]]
Value * EvalState::allocValue()
Value * EvalMemory::allocValue()
{
#if NIX_USE_BOEHMGC
/* We use the boehm batch allocator to speed up allocations of Values (of which there are many).
@@ -48,15 +48,15 @@ Value * EvalState::allocValue()
void * p = allocBytes(sizeof(Value));
#endif
nrValues++;
stats.nrValues++;
return (Value *) p;
}
[[gnu::always_inline]]
Env & EvalState::allocEnv(size_t size)
Env & EvalMemory::allocEnv(size_t size)
{
nrEnvs++;
nrValuesInEnvs += size;
stats.nrEnvs++;
stats.nrValuesInEnvs += size;
Env * env;

View File

@@ -342,6 +342,25 @@ struct EvalSettings : Config
This is useful for improving code readability and making path literals
more explicit.
)"};
Setting<unsigned> bindingsUpdateLayerRhsSizeThreshold{
this,
sizeof(void *) == 4 ? 8192 : 16,
"eval-attrset-update-layer-rhs-threshold",
R"(
Tunes the maximum size of an attribute set that, when used
as a right operand in an [attribute set update expression](@docroot@/language/operators.md#update),
uses a more space-efficient linked-list representation of attribute sets.
Setting this to larger values generally leads to less memory allocations,
but may lead to worse evaluation performance.
A value of `0` disables this optimization completely.
This is an advanced performance tuning option and typically should not be changed.
The default value is chosen to balance performance and memory usage. On 32 bit systems
where memory is scarce, the default is a large value to reduce the amount of allocations.
)"};
};
/**

View File

@@ -16,10 +16,14 @@
#include "nix/expr/search-path.hh"
#include "nix/expr/repl-exit-status.hh"
#include "nix/util/ref.hh"
#include "nix/expr/counter.hh"
// For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS`
#include "nix/expr/config.hh"
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
#include <map>
#include <optional>
#include <functional>
@@ -38,6 +42,7 @@ class Store;
namespace fetchers {
struct Settings;
struct InputCache;
struct Input;
} // namespace fetchers
struct EvalSettings;
class EvalState;
@@ -45,6 +50,7 @@ class StorePath;
struct SingleDerivedPath;
enum RepairFlag : bool;
struct MemorySourceAccessor;
struct MountedSourceAccessor;
namespace eval_cache {
class EvalCache;
@@ -162,7 +168,7 @@ typedef std::
map<std::string, Value *, std::less<std::string>, traceable_allocator<std::pair<const std::string, Value *>>>
ValMap;
typedef std::unordered_map<PosIdx, DocComment> DocCommentMap;
typedef boost::unordered_flat_map<PosIdx, DocComment, std::hash<PosIdx>> DocCommentMap;
struct Env
{
@@ -213,22 +219,163 @@ struct DebugTrace
}
};
struct StaticEvalSymbols
{
Symbol with, outPath, drvPath, type, meta, name, value, system, overrides, outputs, outputName, ignoreNulls, file,
line, column, functor, toString, right, wrong, structuredAttrs, json, allowedReferences, allowedRequisites,
disallowedReferences, disallowedRequisites, maxSize, maxClosureSize, builder, args, contentAddressed, impure,
outputHash, outputHashAlgo, outputHashMode, recurseForDerivations, description, self, epsilon, startSet,
operator_, key, path, prefix, outputSpecified;
Expr::AstSymbols exprSymbols;
static constexpr auto preallocate()
{
StaticSymbolTable alloc;
StaticEvalSymbols staticSymbols = {
.with = alloc.create("<with>"),
.outPath = alloc.create("outPath"),
.drvPath = alloc.create("drvPath"),
.type = alloc.create("type"),
.meta = alloc.create("meta"),
.name = alloc.create("name"),
.value = alloc.create("value"),
.system = alloc.create("system"),
.overrides = alloc.create("__overrides"),
.outputs = alloc.create("outputs"),
.outputName = alloc.create("outputName"),
.ignoreNulls = alloc.create("__ignoreNulls"),
.file = alloc.create("file"),
.line = alloc.create("line"),
.column = alloc.create("column"),
.functor = alloc.create("__functor"),
.toString = alloc.create("__toString"),
.right = alloc.create("right"),
.wrong = alloc.create("wrong"),
.structuredAttrs = alloc.create("__structuredAttrs"),
.json = alloc.create("__json"),
.allowedReferences = alloc.create("allowedReferences"),
.allowedRequisites = alloc.create("allowedRequisites"),
.disallowedReferences = alloc.create("disallowedReferences"),
.disallowedRequisites = alloc.create("disallowedRequisites"),
.maxSize = alloc.create("maxSize"),
.maxClosureSize = alloc.create("maxClosureSize"),
.builder = alloc.create("builder"),
.args = alloc.create("args"),
.contentAddressed = alloc.create("__contentAddressed"),
.impure = alloc.create("__impure"),
.outputHash = alloc.create("outputHash"),
.outputHashAlgo = alloc.create("outputHashAlgo"),
.outputHashMode = alloc.create("outputHashMode"),
.recurseForDerivations = alloc.create("recurseForDerivations"),
.description = alloc.create("description"),
.self = alloc.create("self"),
.epsilon = alloc.create(""),
.startSet = alloc.create("startSet"),
.operator_ = alloc.create("operator"),
.key = alloc.create("key"),
.path = alloc.create("path"),
.prefix = alloc.create("prefix"),
.outputSpecified = alloc.create("outputSpecified"),
.exprSymbols = {
.sub = alloc.create("__sub"),
.lessThan = alloc.create("__lessThan"),
.mul = alloc.create("__mul"),
.div = alloc.create("__div"),
.or_ = alloc.create("or"),
.findFile = alloc.create("__findFile"),
.nixPath = alloc.create("__nixPath"),
.body = alloc.create("body"),
}};
return std::pair{staticSymbols, alloc};
}
static consteval StaticEvalSymbols create()
{
return preallocate().first;
}
static constexpr StaticSymbolTable staticSymbolTable()
{
return preallocate().second;
}
};
class EvalMemory
{
#if NIX_USE_BOEHMGC
/**
* Allocation cache for GC'd Value objects.
*/
std::shared_ptr<void *> valueAllocCache;
/**
* Allocation cache for size-1 Env objects.
*/
std::shared_ptr<void *> env1AllocCache;
#endif
public:
struct Statistics
{
Counter nrEnvs;
Counter nrValuesInEnvs;
Counter nrValues;
Counter nrAttrsets;
Counter nrAttrsInAttrsets;
Counter nrListElems;
};
EvalMemory();
EvalMemory(const EvalMemory &) = delete;
EvalMemory(EvalMemory &&) = delete;
EvalMemory & operator=(const EvalMemory &) = delete;
EvalMemory & operator=(EvalMemory &&) = delete;
inline Value * allocValue();
inline Env & allocEnv(size_t size);
Bindings * allocBindings(size_t capacity);
BindingsBuilder buildBindings(SymbolTable & symbols, size_t capacity)
{
return BindingsBuilder(*this, symbols, allocBindings(capacity), capacity);
}
ListBuilder buildList(size_t size)
{
stats.nrListElems += size;
return ListBuilder(size);
}
const Statistics & getStats() const &
{
return stats;
}
/**
* Storage for the AST nodes
*/
Exprs exprs;
private:
Statistics stats;
};
class EvalState : public std::enable_shared_from_this<EvalState>
{
public:
static constexpr StaticEvalSymbols s = StaticEvalSymbols::create();
const fetchers::Settings & fetchSettings;
const EvalSettings & settings;
SymbolTable symbols;
PosTable positions;
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName,
sIgnoreNulls, sFile, sLine, sColumn, sFunctor, sToString, sRight, sWrong, sStructuredAttrs, sJson,
sAllowedReferences, sAllowedRequisites, sDisallowedReferences, sDisallowedRequisites, sMaxSize, sMaxClosureSize,
sBuilder, sArgs, sContentAddressed, sImpure, sOutputHash, sOutputHashAlgo, sOutputHashMode,
sRecurseForDerivations, sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, sPrefix,
sOutputSpecified;
const Expr::AstSymbols exprSymbols;
EvalMemory mem;
/**
* If set, force copying files to the Nix store even if they
@@ -236,47 +383,10 @@ public:
*/
RepairFlag repair;
Bindings emptyBindings;
/**
* Empty list constant.
*/
Value vEmptyList;
/**
* `null` constant.
*
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
*/
Value vNull;
/**
* `true` constant.
*
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
*/
Value vTrue;
/**
* `true` constant.
*
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
*/
Value vFalse;
/** `"regular"` */
Value vStringRegular;
/** `"directory"` */
Value vStringDirectory;
/** `"symlink"` */
Value vStringSymlink;
/** `"unknown"` */
Value vStringUnknown;
/**
* The accessor corresponding to `store`.
*/
const ref<SourceAccessor> storeFS;
const ref<MountedSourceAccessor> storeFS;
/**
* The accessor for the root filesystem.
@@ -318,7 +428,7 @@ public:
bool inDebugger = false;
int trylevel;
std::list<DebugTrace> debugTraces;
std::map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
boost::unordered_flat_map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
const std::shared_ptr<const StaticEnv> getStaticEnv(const Expr & expr) const
{
@@ -361,59 +471,41 @@ private:
/* Cache for calls to addToStore(); maps source paths to the store
paths. */
Sync<std::unordered_map<SourcePath, StorePath>> srcToStore;
ref<boost::concurrent_flat_map<SourcePath, StorePath>> srcToStore;
/**
* A cache from path names to parse trees.
* A cache that maps paths to "resolved" paths for importing Nix
* expressions, i.e. `/foo` to `/foo/default.nix`.
*/
typedef std::unordered_map<
SourcePath,
Expr *,
std::hash<SourcePath>,
std::equal_to<SourcePath>,
traceable_allocator<std::pair<const SourcePath, Expr *>>>
FileParseCache;
FileParseCache fileParseCache;
ref<boost::concurrent_flat_map<SourcePath, SourcePath>> importResolutionCache;
/**
* A cache from path names to values.
* A cache from resolved paths to values.
*/
typedef std::unordered_map<
ref<boost::concurrent_flat_map<
SourcePath,
Value,
Value *,
std::hash<SourcePath>,
std::equal_to<SourcePath>,
traceable_allocator<std::pair<const SourcePath, Value>>>
FileEvalCache;
FileEvalCache fileEvalCache;
traceable_allocator<std::pair<const SourcePath, Value *>>>>
fileEvalCache;
/**
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
* Grouped by file.
*/
std::unordered_map<SourcePath, DocCommentMap> positionToDocComment;
boost::unordered_flat_map<SourcePath, DocCommentMap> positionToDocComment;
LookupPath lookupPath;
std::map<std::string, std::optional<SourcePath>> lookupPathResolved;
boost::unordered_flat_map<std::string, std::optional<SourcePath>, StringViewHash, std::equal_to<>>
lookupPathResolved;
/**
* Cache used by prim_match().
*/
std::shared_ptr<RegexCache> regexCache;
#if NIX_USE_BOEHMGC
/**
* Allocation cache for GC'd Value objects.
*/
std::shared_ptr<void *> valueAllocCache;
/**
* Allocation cache for size-1 Env objects.
*/
std::shared_ptr<void *> env1AllocCache;
#endif
public:
EvalState(
@@ -424,6 +516,15 @@ public:
std::shared_ptr<Store> buildStore = nullptr);
~EvalState();
/**
* A wrapper around EvalMemory::allocValue() to avoid code churn when it
* was introduced.
*/
inline Value * allocValue()
{
return mem.allocValue();
}
LookupPath getLookupPath()
{
return lookupPath;
@@ -451,8 +552,11 @@ public:
/**
* Allow access to a path.
*
* Only for restrict eval: pure eval just whitelist store paths,
* never arbitrary paths.
*/
void allowPath(const Path & path);
void allowPathLegacy(const Path & path);
/**
* Allow access to a store path. Note that this gets remapped to
@@ -472,6 +576,11 @@ public:
void checkURI(const std::string & uri);
/**
* Mount an input on the Nix store.
*/
StorePath mountInput(fetchers::Input & input, const fetchers::Input & originalInput, ref<SourceAccessor> accessor);
/**
* Parse a Nix expression from the specified file.
*/
@@ -570,7 +679,7 @@ public:
/**
* Get attribute from an attribute set and throw an error if it doesn't exist.
*/
Bindings::const_iterator getAttr(Symbol attrSym, const Bindings * attrSet, std::string_view errorCtx);
const Attr * getAttr(Symbol attrSym, const Bindings * attrSet, std::string_view errorCtx);
template<typename... Args>
[[gnu::noinline]]
@@ -669,11 +778,11 @@ public:
/**
* Internal primops not exposed to the user.
*/
std::unordered_map<
boost::unordered_flat_map<
std::string,
Value *,
std::hash<std::string>,
std::equal_to<std::string>,
StringViewHash,
std::equal_to<>,
traceable_allocator<std::pair<const std::string, Value *>>>
internalPrimOps;
@@ -792,22 +901,14 @@ public:
*/
void autoCallFunction(const Bindings & args, Value & fun, Value & res);
/**
* Allocation primitives.
*/
inline Value * allocValue();
inline Env & allocEnv(size_t size);
Bindings * allocBindings(size_t capacity);
BindingsBuilder buildBindings(size_t capacity)
{
return BindingsBuilder(*this, allocBindings(capacity));
return mem.buildBindings(symbols, capacity);
}
ListBuilder buildList(size_t size)
{
return ListBuilder(*this, size);
return mem.buildList(size);
}
/**
@@ -924,26 +1025,20 @@ private:
*/
std::string mkSingleDerivedPathStringRaw(const SingleDerivedPath & p);
unsigned long nrEnvs = 0;
unsigned long nrValuesInEnvs = 0;
unsigned long nrValues = 0;
unsigned long nrListElems = 0;
unsigned long nrLookups = 0;
unsigned long nrAttrsets = 0;
unsigned long nrAttrsInAttrsets = 0;
unsigned long nrAvoided = 0;
unsigned long nrOpUpdates = 0;
unsigned long nrOpUpdateValuesCopied = 0;
unsigned long nrListConcats = 0;
unsigned long nrPrimOpCalls = 0;
unsigned long nrFunctionCalls = 0;
Counter nrLookups;
Counter nrAvoided;
Counter nrOpUpdates;
Counter nrOpUpdateValuesCopied;
Counter nrListConcats;
Counter nrPrimOpCalls;
Counter nrFunctionCalls;
bool countCalls;
typedef std::map<std::string, size_t> PrimOpCalls;
typedef boost::unordered_flat_map<std::string, size_t, StringViewHash, std::equal_to<>> PrimOpCalls;
PrimOpCalls primOpCalls;
typedef std::map<ExprLambda *, size_t> FunctionCalls;
typedef boost::unordered_flat_map<ExprLambda *, size_t> FunctionCalls;
FunctionCalls functionCalls;
/** Evaluation/call profiler. */
@@ -951,7 +1046,7 @@ private:
void incrFunctionCall(ExprLambda * fun);
typedef std::map<PosIdx, size_t> AttrSelects;
typedef boost::unordered_flat_map<PosIdx, size_t, std::hash<PosIdx>> AttrSelects;
AttrSelects attrSelects;
friend struct ExprOpUpdate;

View File

@@ -26,4 +26,20 @@ using SmallValueVector = SmallVector<Value *, nItems>;
template<size_t nItems>
using SmallTemporaryValueVector = SmallVector<Value, nItems>;
/**
* For functions where we do not expect deep recursion, we can use a sizable
* part of the stack a free allocation space.
*
* Note: this is expected to be multiplied by sizeof(Value), or about 24 bytes.
*/
constexpr size_t nonRecursiveStackReservation = 128;
/**
* Functions that maybe applied to self-similar inputs, such as concatMap on a
* tree, should reserve a smaller part of the stack for allocation.
*
* Note: this is expected to be multiplied by sizeof(Value), or about 24 bytes.
*/
constexpr size_t conservativeStackReservation = 16;
} // namespace nix

View File

@@ -10,6 +10,7 @@ config_pub_h = configure_file(
headers = [ config_pub_h ] + files(
'attr-path.hh',
'attr-set.hh',
'counter.hh',
'eval-cache.hh',
'eval-error.hh',
'eval-gc.hh',

View File

@@ -2,12 +2,17 @@
///@file
#include <map>
#include <span>
#include <vector>
#include <memory_resource>
#include <algorithm>
#include "nix/expr/gc-small-vector.hh"
#include "nix/expr/value.hh"
#include "nix/expr/symbol-table.hh"
#include "nix/expr/eval-error.hh"
#include "nix/util/pos-idx.hh"
#include "nix/expr/counter.hh"
namespace nix {
@@ -76,9 +81,20 @@ struct AttrName
: expr(e) {};
};
static_assert(std::is_trivially_copy_constructible_v<AttrName>);
typedef std::vector<AttrName> AttrPath;
std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath);
std::string showAttrPath(const SymbolTable & symbols, std::span<const AttrName> attrPath);
using UpdateQueue = SmallTemporaryValueVector<conservativeStackReservation>;
class Exprs
{
std::pmr::monotonic_buffer_resource buffer;
public:
std::pmr::polymorphic_allocator<char> alloc{&buffer};
};
/* Abstract syntax of Nix expressions. */
@@ -89,7 +105,7 @@ struct Expr
Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
};
static unsigned long nrExprs;
static Counter nrExprs;
Expr()
{
@@ -99,8 +115,25 @@ struct Expr
virtual ~Expr() {};
virtual void show(const SymbolTable & symbols, std::ostream & str) const;
virtual void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env);
/** Normal evaluation, implemented directly by all subclasses. */
virtual void eval(EvalState & state, Env & env, Value & v);
/**
* Create a thunk for the delayed computation of the given expression
* in the given environment. But if the expression is a variable,
* then look it up right away. This significantly reduces the number
* of thunks allocated.
*/
virtual Value * maybeThunk(EvalState & state, Env & env);
/**
* Only called when performing an attrset update: `//` or similar.
* Instead of writing to a Value &, this function writes to an UpdateQueue.
* This allows the expression to perform multiple updates in a delayed manner, gathering up all the updates before
* applying them.
*/
virtual void evalForUpdate(EvalState & state, Env & env, UpdateQueue & q, std::string_view errorCtx);
virtual void setName(Symbol name);
virtual void setDocComment(DocComment docComment) {};
@@ -158,7 +191,7 @@ struct ExprString : Expr
ExprString(std::string && s)
: s(std::move(s))
{
v.mkString(this->s.data());
v.mkStringNoCopy(this->s.data());
};
Value * maybeThunk(EvalState & state, Env & env) override;
@@ -168,14 +201,16 @@ struct ExprString : Expr
struct ExprPath : Expr
{
ref<SourceAccessor> accessor;
std::string s;
Value v;
ExprPath(ref<SourceAccessor> accessor, std::string s)
ExprPath(std::pmr::polymorphic_allocator<char> & alloc, ref<SourceAccessor> accessor, std::string_view sv)
: accessor(accessor)
, s(std::move(s))
{
v.mkPath(&*accessor, this->s.c_str());
auto len = sv.length();
char * s = alloc.allocate(len + 1);
sv.copy(s, len);
s[len] = '\0';
v.mkPath(&*accessor, s);
}
Value * maybeThunk(EvalState & state, Env & env) override;
@@ -242,20 +277,33 @@ struct ExprInheritFrom : ExprVar
struct ExprSelect : Expr
{
PosIdx pos;
uint32_t nAttrPath;
Expr *e, *def;
AttrPath attrPath;
ExprSelect(const PosIdx & pos, Expr * e, AttrPath attrPath, Expr * def)
AttrName * attrPathStart;
ExprSelect(
std::pmr::polymorphic_allocator<char> & alloc,
const PosIdx & pos,
Expr * e,
std::span<const AttrName> attrPath,
Expr * def)
: pos(pos)
, nAttrPath(attrPath.size())
, e(e)
, def(def)
, attrPath(std::move(attrPath)) {};
, attrPathStart(alloc.allocate_object<AttrName>(nAttrPath))
{
std::ranges::copy(attrPath, attrPathStart);
};
ExprSelect(const PosIdx & pos, Expr * e, Symbol name)
ExprSelect(std::pmr::polymorphic_allocator<char> & alloc, const PosIdx & pos, Expr * e, Symbol name)
: pos(pos)
, nAttrPath(1)
, e(e)
, def(0)
, attrPathStart((alloc.allocate_object<AttrName>()))
{
attrPath.push_back(AttrName(name));
*attrPathStart = AttrName(name);
};
PosIdx getPos() const override
@@ -263,6 +311,11 @@ struct ExprSelect : Expr
return pos;
}
std::span<const AttrName> getAttrPath() const
{
return {attrPathStart, nAttrPath};
}
/**
* Evaluate the `a.b.c` part of `a.b.c.d`. This exists mostly for the purpose of :doc in the repl.
*
@@ -280,10 +333,14 @@ struct ExprSelect : Expr
struct ExprOpHasAttr : Expr
{
Expr * e;
AttrPath attrPath;
ExprOpHasAttr(Expr * e, AttrPath attrPath)
std::span<AttrName> attrPath;
ExprOpHasAttr(std::pmr::polymorphic_allocator<char> & alloc, Expr * e, std::vector<AttrName> attrPath)
: e(e)
, attrPath(std::move(attrPath)) {};
, attrPath({alloc.allocate_object<AttrName>(attrPath.size()), attrPath.size()})
{
std::ranges::copy(attrPath, this->attrPath.begin());
};
PosIdx getPos() const override
{
@@ -565,42 +622,61 @@ struct ExprOpNot : Expr
COMMON_METHODS
};
#define MakeBinOp(name, s) \
struct name : Expr \
{ \
PosIdx pos; \
Expr *e1, *e2; \
name(Expr * e1, Expr * e2) \
: e1(e1) \
, e2(e2) {}; \
name(const PosIdx & pos, Expr * e1, Expr * e2) \
: pos(pos) \
, e1(e1) \
, e2(e2) {}; \
void show(const SymbolTable & symbols, std::ostream & str) const override \
{ \
str << "("; \
e1->show(symbols, str); \
str << " " s " "; \
e2->show(symbols, str); \
str << ")"; \
} \
void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override \
{ \
e1->bindVars(es, env); \
e2->bindVars(es, env); \
} \
void eval(EvalState & state, Env & env, Value & v) override; \
PosIdx getPos() const override \
{ \
return pos; \
} \
};
#define MakeBinOpMembers(name, s) \
PosIdx pos; \
Expr *e1, *e2; \
name(Expr * e1, Expr * e2) \
: e1(e1) \
, e2(e2){}; \
name(const PosIdx & pos, Expr * e1, Expr * e2) \
: pos(pos) \
, e1(e1) \
, e2(e2){}; \
void show(const SymbolTable & symbols, std::ostream & str) const override \
{ \
str << "("; \
e1->show(symbols, str); \
str << " " s " "; \
e2->show(symbols, str); \
str << ")"; \
} \
void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override \
{ \
e1->bindVars(es, env); \
e2->bindVars(es, env); \
} \
void eval(EvalState & state, Env & env, Value & v) override; \
PosIdx getPos() const override \
{ \
return pos; \
}
MakeBinOp(ExprOpEq, "==") MakeBinOp(ExprOpNEq, "!=") MakeBinOp(ExprOpAnd, "&&") MakeBinOp(ExprOpOr, "||")
MakeBinOp(ExprOpImpl, "->") MakeBinOp(ExprOpUpdate, "//") MakeBinOp(ExprOpConcatLists, "++")
#define MakeBinOp(name, s) \
struct name : Expr \
{ \
MakeBinOpMembers(name, s) \
}
struct ExprConcatStrings : Expr
MakeBinOp(ExprOpEq, "==");
MakeBinOp(ExprOpNEq, "!=");
MakeBinOp(ExprOpAnd, "&&");
MakeBinOp(ExprOpOr, "||");
MakeBinOp(ExprOpImpl, "->");
MakeBinOp(ExprOpConcatLists, "++");
struct ExprOpUpdate : Expr
{
private:
/** Special case for merging of two attrsets. */
void eval(EvalState & state, Value & v, Value & v1, Value & v2);
void evalForUpdate(EvalState & state, Env & env, UpdateQueue & q);
public:
MakeBinOpMembers(ExprOpUpdate, "//");
virtual void evalForUpdate(EvalState & state, Env & env, UpdateQueue & q, std::string_view errorCtx) override;
};
struct ExprConcatStrings : Expr
{
PosIdx pos;
bool forceString;

View File

@@ -24,7 +24,6 @@ struct StringToken
}
};
// This type must be trivially copyable; see YYLTYPE_IS_TRIVIAL in parser.y.
struct ParserLocation
{
int beginOffset;
@@ -44,9 +43,6 @@ struct ParserLocation
beginOffset = stashedBeginOffset;
endOffset = stashedEndOffset;
}
/** Latest doc comment position, or 0. */
int doc_comment_first_column, doc_comment_last_column;
};
struct LexerState
@@ -71,7 +67,7 @@ struct LexerState
/**
* @brief Maps some positions to a DocComment, where the comment is relevant to the location.
*/
std::unordered_map<PosIdx, DocComment> & positionToDocComment;
DocCommentMap & positionToDocComment;
PosTable & positions;
PosTable::Origin origin;
@@ -82,13 +78,14 @@ struct LexerState
struct ParserState
{
const LexerState & lexerState;
std::pmr::polymorphic_allocator<char> & alloc;
SymbolTable & symbols;
PosTable & positions;
Expr * result;
SourcePath basePath;
PosTable::Origin origin;
const ref<SourceAccessor> rootFS;
const Expr::AstSymbols & s;
static constexpr Expr::AstSymbols s = StaticEvalSymbols::create().exprSymbols;
const EvalSettings & settings;
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);

View File

@@ -8,31 +8,11 @@
namespace nix {
/**
* For functions where we do not expect deep recursion, we can use a sizable
* part of the stack a free allocation space.
*
* Note: this is expected to be multiplied by sizeof(Value), or about 24 bytes.
*/
constexpr size_t nonRecursiveStackReservation = 128;
/**
* Functions that maybe applied to self-similar inputs, such as concatMap on a
* tree, should reserve a smaller part of the stack for allocation.
*
* Note: this is expected to be multiplied by sizeof(Value), or about 24 bytes.
*/
constexpr size_t conservativeStackReservation = 16;
struct RegisterPrimOp
{
typedef std::vector<PrimOp> PrimOps;
static PrimOps & primOps()
{
static PrimOps primOps;
return primOps;
}
static PrimOps & primOps();
/**
* You can register a constant by passing an arity of 0. fun

View File

@@ -110,7 +110,7 @@ struct PrintOptions
* `PrintOptions` for unknown and therefore potentially large values in error messages,
* to avoid printing "too much" output.
*/
static PrintOptions errorPrintOptions = PrintOptions{
static constexpr PrintOptions errorPrintOptions = PrintOptions{
.ansiColors = true,
.maxDepth = 10,
.maxAttrs = 10,

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