Compare commits

..

292 Commits

Author SHA1 Message Date
Eelco Dolstra
3f53a435cb Factor out the local NAR cache into its own class 2026-01-14 22:22:44 +01:00
Eelco Dolstra
0a632cbc3a Merge pull request #14989 from NixOS/querySubstitutablePaths
Move LocalStore::querySubstitutablePaths() to Store
2026-01-14 19:38:28 +00:00
Eelco Dolstra
8c2021989e Merge pull request #14993 from NixOS/curl-scalability
Limit the number of active curl handles
2026-01-14 19:02:21 +00:00
Eelco Dolstra
92344a31fa LegacySSHStore: Override querySubstitutablePaths() 2026-01-14 19:48:14 +01:00
Eelco Dolstra
ee64ffcd75 curlFileTransfer: Lazily create activity and set startTime
There can be a long time between the creation of `TransferItem` and
the start of the curl download, which can lead to misleading download
durations and progress bar status. So now we create the `Activity` and
update `startTime` when curl actually starts the download.
2026-01-14 19:19:01 +01:00
Eelco Dolstra
8012b584c3 Limit the number of active curl handles
Previously, calling queryValidPaths() with a large number (e.g. 100K)
of store paths failed because Nix immediately creates a `TransferItem`
for each .narinfo, which is then registered as a handle with
curl. However curl appears to scale poorly internally: even though
only a few downloads are actually started (up to the
connections/streams limits), it spends a lot of CPU time dealing with
the inactive handles. So the curl thread is sitting at 100% CPU, the
active downloads stall and time out, and everything grind to a halt.

So now we limit the number of curl handles to http-connections *
5. With this, fetching 100K .narinfo files from localhost succeeds in
~15 seconds.
2026-01-14 18:38:59 +01:00
John Ericson
609a4e999f Merge pull request #14988 from NixOS/remove-has-substitutes
Remove WorkerProto::Op::HasSubstitutes
2026-01-14 17:17:39 +00:00
Eelco Dolstra
6fd36553b9 Merge pull request #14990 from NixOS/nar-cache-cleanup
More NAR accessor / listing cleanup
2026-01-14 12:53:36 +00:00
John Ericson
ce28cb32e9 BinaryCacheStore: Avoid recreating NAR listing
We already have it, so let's just use it!
2026-01-13 14:01:25 -05:00
John Ericson
3d18d73003 Remove redundant NarAccessor::nar 2026-01-13 13:32:29 -05:00
John Ericson
8089af3bb0 Better type for NarMemberConstructor::regular
This makes some invariants clearer and more local.
2026-01-13 13:12:15 -05:00
John Ericson
b49ea8b246 Factor out parseNarListing, move to nar-listing.{cc,hh}
Now we have less of a maze of implementation structs.

Review with
```
git show --color-moved --patience --color-moved-ws=ignore-all-space
```
2026-01-13 13:10:04 -05:00
John Ericson
af821ba647 Split out nar-listing.{cc,hh}
I like the separation of concerns from NAR accessing.
2026-01-13 12:10:54 -05:00
Eelco Dolstra
1b1c949d0c Merge pull request #14981 from roberth/fix-git-relative-url-crash
`fixGitURL`: fix crash for "relative" `file:` paths and reject unsupported SCP URLs
2026-01-13 12:59:59 +00:00
Eelco Dolstra
fb70a45b9e Move LocalStore::querySubstitutablePaths() to Store
Nothing in this method depends on LocalStore, so we can use it as the
default implementation. (It's only overriden in RemoteStore.)
2026-01-13 13:55:08 +01:00
Eelco Dolstra
53e942bfcc Merge pull request #14983 from roberth/fetchTree-relative-file
fetchTree: reject relative `file:` paths for tarballs
2026-01-13 12:46:08 +00:00
Eelco Dolstra
4f5172ba21 Remove WorkerProto::Op::HasSubstitutes
This operation has been deprecated since
09a6321aeb (July 2012). It was used by
client versions <= 11, which is below `MINIMUM_PROTOCOL_VERSION`
(currently 18).
2026-01-13 12:26:10 +01:00
Jörg Thalheim
1bddbff3a6 Merge pull request #14986 from NixOS/nar-cache-cleanup
Two NAR accessor / listing cleanups
2026-01-13 07:31:29 +00:00
John Ericson
4991defc44 Make reading in a nar listing all well typed
We can get rid of `NarMember`, because it is just `NarListing` in
disguise! The use of `std::variant` makes clear that certain stat fields
we don't care about in the non-regular-file case too.
2026-01-13 01:33:53 -05:00
John Ericson
8f829e478f Inline RemoteFSAccessor::makeCacheFile into lambda
It's just easier to avoid headers.
2026-01-13 01:33:53 -05:00
John Ericson
7ac5a61208 Merge pull request #14948 from NixOS/ca-nar-cache
RemoteFSAccessor: Make the local NAR cache content-addressed
2026-01-13 04:56:31 +00:00
John Ericson
2af5792cc2 Inline RemoteFSAccessor::addToCache
It was not pulling its weight. (Only used once, optional paths are
confusing, we already have an `if` / branch fit-for-purpose.)
2026-01-12 23:09:45 -05:00
Eelco Dolstra
e251ffdd46 RemoteFSAccessor: Make the local NAR cache content-addressed
Use double-indirection for better NAR accessor caching

Co-authored-by: John Ericson <John.Ericson@Obsidian.Systems>
2026-01-12 23:00:20 -05:00
John Ericson
a8087ebf52 Merge pull request #14984 from NixOS/more-windows-fixes
More windows fixes
2026-01-12 23:19:38 +00:00
Sergei Zimmerman
66fefcd795 libutil: Better implementation of createAnonymousTempFile on windows 2026-01-13 01:28:17 +03:00
Sergei Zimmerman
1ea3a841bb libstore/local-binary-cache-store: Use portable error_code in getFile 2026-01-13 00:56:03 +03:00
Sergei Zimmerman
fd0bcd97e8 libutil: Include std::error_code in the base class SystemError 2026-01-13 00:50:42 +03:00
Robert Hensing
b19bfc6373 fetchTree: improve relative path error wording
Avoid implying that relative paths could work if a base directory
were defined. The file: scheme fundamentally does not support them.
2026-01-12 20:16:26 +01:00
Robert Hensing
3b028edbf7 fixGitURL: fix crash for relative paths and reject unsupported SCP URLs
Relative paths (e.g., "relative/repo") would crash in renderAuthorityAndPath()
because an empty authority was set, violating RFC 3986 section 3.3 which
requires paths to start with "/" when an authority is present.

Fix by only setting authority for absolute paths:
- Absolute paths: file:///path (empty authority)
- Relative paths: file:path (no authority)

Also reject SCP-like URLs without a user (e.g., "github.com:path") with a
clear error message, since proper support requires careful implementation,
which is not something I can do right now.
2026-01-12 13:03:57 +01:00
Robert Hensing
23a7178eb4 fetchTree: reject relative file: paths for tarballs
Relative paths like `file:./foo.tar.gz` have never worked for tarballs
because curl rejects relative file: URLs. Previously this resulted in
cryptic curl errors. Now we reject them early with a clear message
explaining that relative paths are not supported because there is no
defined base directory to resolve them against.

See https://github.com/NixOS/nix/issues/12281
2026-01-12 03:31:42 +01:00
John Ericson
252aff5c8f Merge pull request #14971 from obsidiansystems/misc-builder-fixes
Misc builder fixes
2026-01-11 21:02:14 +00:00
Sergei Zimmerman
920c5ceb0c Merge pull request #14961 from NixOS/readdir-nonexistent-fix
libutil/union-source-accessor: Barf on non-existent directories
2026-01-11 18:15:22 +00:00
John Ericson
de76cb681d Make sure we reliably call Worker::childTerminated
When a goal with an active child process is destroyed (e.g., during
failure cascades without `--keep-going`), the child process gets killed
but `childTerminated` was never called. This left stale entries in the
worker's `children` list.

Fix this by ensuring `childTerminated` is called from destructors:

- `DerivationBuilderImpl::killChild` now calls `childTerminated` via
  the `miscMethods` callback.

- `HookInstance` gains an `onKillChild` callback that is invoked from
  its destructor when killing the process. `buildWithHook` sets this
  callback to call `childTerminated`.

To make these calls safe from destructors (where the goal object may be
partially destroyed), add a new overload of `Worker::childTerminated`
that takes an explicit `JobCategory` parameter instead of calling the
virtual method `Goal::jobCategory`. The original overload still exists
for convenience for normal (non-destructor) call sites.
2026-01-10 20:24:05 -05:00
John Ericson
d19bfb0045 Avoid short circuiting in Worker::removeGoal
We have to call into both branches no matter what.
2026-01-10 20:23:50 -05:00
John Ericson
160822858a Merge pull request #14788 from NixOS/coroutine-child-output
Way more RAII for `DerivationBuildingGoal`
2026-01-11 00:09:53 +00:00
John Ericson
25998fcd1e Merge pull request #14970 from NixOS/more-openfile-readonly
Use openFileReadonly in more places
2026-01-11 00:07:15 +00:00
John Ericson
7ba09399cc Merge pull request #14968 from NixOS/fs-sink-restore-regular-file-fd
libutil: RestoreRegularFile is an FdSink
2026-01-11 00:05:20 +00:00
Sergei Zimmerman
f8a92564f7 More std::filesystem::path for nix {cat,ls}
Also fixes a double quoting issue I accidentally introduced ccdd1f1c65
in seekableGetNarBytes.
2026-01-11 01:44:16 +03:00
Sergei Zimmerman
2ae4121c1d libutil/file-system: Use openFileReadonly in more places 2026-01-11 01:44:15 +03:00
John Ericson
38c755f168 Merge pull request #14966 from drupol/push-ozvunuqvxrvw
chore: replace `edolstra/flake-compat` with `NixOS/flake-compat`
2026-01-10 15:59:07 +00:00
Sergei Zimmerman
08887caa1a libutil: RestoreRegularFile is an FdSink
It correctly models the is-a relation. This will be useful for doing a dynamic_cast in
downstream code that wants to copy from a file descriptor to a file descriptor.
2026-01-10 16:31:05 +03:00
Pol Dellaiera
8d588ad471 chore: replace edolstra/flake-compat with NixOS/flake-compat 2026-01-10 10:10:55 +01:00
Sergei Zimmerman
6970efe2e1 Merge pull request #14962 from NixOS/fix-mingw
Fix mingw build (once again), add openFileReadonly and clean up error.hh to include WinError
2026-01-10 00:39:46 +00:00
Sergei Zimmerman
3b95b7c9aa Merge pull request #14963 from corngood/test-leak
libflake-tests: fix leak in nix_api_store_test.nix_api_load_flake_with_flags
2026-01-09 23:44:30 +00:00
David McFarland
4289e2f9e6 libflake-tests: fix leak in nix_api_store_test.nix_api_load_flake_with_flags 2026-01-09 16:51:15 -04:00
Eelco Dolstra
d1dc2d53b1 Merge pull request #14960 from NixOS/path-cleanup
PathInputScheme::getAccessor(): Drop unnecessary call to queryPathInfo()
2026-01-09 18:47:03 +00:00
Sergei Zimmerman
ccdd1f1c65 libstore: Fix mingw build
This also adds a utility for opening a file descriptor from a path in readonly mode.
Previous commit helps a bit with error handling, since now we just throw a NativeSysError.
2026-01-09 21:06:34 +03:00
Sergei Zimmerman
b7fd471f84 libutil: Inline windows-error.hh into error.hh
This way each consumer of NativeSysError doesn't have to
also conditionally include the windows-error.hh, which is very cumbersome.
And we can't include windows-error.hh in error.hh because of a circular import.
2026-01-09 20:59:35 +03:00
Sergei Zimmerman
4ab2cdacfc 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.
2026-01-09 20:19:32 +03:00
Eelco Dolstra
21534baa89 PathInputScheme::getAccessor(): Drop unnecessary call to queryPathInfo() 2026-01-09 15:33:24 +01:00
Eelco Dolstra
477aa250d4 Merge pull request #14959 from NixOS/git-repo-tests
Move {init,create}GitRepo to tests/functional/common/functions.sh
2026-01-09 14:24:21 +00:00
Eelco Dolstra
2417ee4732 Move {init,create}GitRepo to tests/functional/common/functions.sh 2026-01-09 14:57:21 +01:00
John Ericson
36a6247a0b Merge pull request #14953 from corngood/cygwin-symlink-test
libutil-tests: fix openFileEnsureBeneathNoSymlinks.works on cygwin
2026-01-09 03:55:52 +00:00
David McFarland
ac24ef84fa libutil-tests: fix openFileEnsureBeneathNoSymlinks.works on cygwin 2026-01-08 18:59:46 -04:00
John Ericson
5a65b1f131 Merge pull request #14947 from NixOS/local-nar-cache
BinaryCacheStoreConfig: Change localNarCache to std::filesystem::path
2026-01-07 20:56:29 +00:00
Eelco Dolstra
24da83853a BinaryCacheStoreConfig: Change localNarCache to std::filesystem::path 2026-01-07 21:15:19 +01:00
Eelco Dolstra
6f7190bdae Merge pull request #14946 from NixOS/fix-structured-attrs-test
Fix structured-attrs test failure in dev shell
2026-01-07 18:36:52 +00:00
Eelco Dolstra
7ce871ee86 Fix structured-attrs test failure in dev shell
Fixes "error: cannot create symlink '.../tests/functional/result';
already exists".
2026-01-07 18:00:27 +01:00
Sergei Zimmerman
b474e8d249 Merge pull request #14935 from NixOS/delete-path-fchmod
libutil: Implement unix::fchmodatTryNoFollow, use in deletePath
2026-01-07 13:12:18 +00:00
Sergei Zimmerman
9a63752317 libutil: Implement unix::fchmodatTryNoFollow
Using fchmodat after a fstatat in deletePath has a slight TOCTOU
window. We can plug it by using fchmodat (the libc wrapper with
AT_SYMLINK_NOFOLLOW), but it tries fchmodat2 and falls back to the
O_PATH trick while failing when procfs isn't mounted. We can do a bit
better than that and also cache whether syscalls are unsupported to
avoid the repeated context switching that glibc would impose.

Also tests the fallback path. It's only for kernels older than 6.6 and
when procfs isn't accessible that we fall back to the racy fchmodat
without AT_SYMLINK_NOFOLLOW.

What previously used to be:

openat(AT_FDCWD, "/tmp/store-race/nix/var/nix/builds", O_RDONLY) = 11
newfstatat(11, "nix-2704212-84654554", {st_mode=S_IFDIR|000, st_size=3, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(11, "nix-2704212-84654554", 040700) = 0

Is now a TOCTOU-free sequence of syscalls:

openat(AT_FDCWD, "/tmp/store-race/nix/var/nix/builds", O_RDONLY) = 11
newfstatat(11, "nix-2704953-1733606057", {st_mode=S_IFDIR|000, st_size=3, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat2(11, "nix-2704953-1733606057", 040700, AT_SYMLINK_NOFOLLOW) = 0

Or if the fchmodat2 is not supported:

openat(11, "nix-2705443-3010460784", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 12
fstat(12, {st_mode=S_IFDIR|000, st_size=3, ...}) = 0
chmod("/proc/self/fd/12", 040700)       = 0
openat(11, "nix-2705443-3010460784", O_RDONLY|O_NOFOLLOW|O_DIRECTORY) = 12

This prevents a potentially arbitrary chmod that follows symlinks,
though the race window is very small. Also in the case that fchmodat2
isn't supported we could instead open the /proc/self/fd/N path instead
of using openat, but that's pretty much equivalent. We only care
about ensuring that the thing we chmodded wasn't a symlink since
fchmodat follows symlinks and the support for AT_SYMLINK_NOFOLLOW
in libc for that is pretty spotty on Linux. E.g. glibc fails if the
AT_SYMLINK_NOFOLLOW is specified and procfs isn't available even on
regular files. The patch also includes a test that uses a user namespace
on Linux to test this exact scenario (though it's rather exotic).
2026-01-07 14:59:05 +03:00
Eelco Dolstra
afc6c24d68 Merge pull request #14928 from Zaczero/zaczero/nixmain
Remove regex from isNixCommand
2026-01-06 17:56:41 +00:00
Eelco Dolstra
a3043d991f Merge pull request #14925 from Zaczero/zaczero/trycat
Remove redundant try/catch
2026-01-06 17:42:51 +00:00
Kamil Monicz
7c3b4f72b8 Remove regex from isNixCommand 2026-01-06 18:04:59 +01:00
Eelco Dolstra
7a5f49323d Merge pull request #14923 from NixOS/remove-store-hashes
Get rid of real store paths in docs/tests
2026-01-06 17:00:10 +00:00
Kamil Monicz
1176d59c8a Remove redundant try/catch 2026-01-06 17:51:14 +01:00
Graham Christensen
05df7d716a Auto-replace actually existing store path hashes 2026-01-06 17:26:20 +01:00
Sergei Zimmerman
75da37f792 libutil-tests: Move unix-specific tests for file descriptors to unix/file-descriptor.cc 2026-01-06 18:46:34 +03:00
Graham Christensen
07a260ca18 Invalidation script 2026-01-06 15:55:08 +01:00
Graham Christensen
8ba7ebca3b Replace hashes that appear in cache.nixos.org with hashes which are unlikely to do so (for the diff from 3.14.0 to 3.15.0) 2026-01-06 15:54:22 +01:00
Sergei Zimmerman
931f84b720 Merge pull request #14921 from qowoz/lowdown
packaging: fix lowdown with overridden nixpkgs
2026-01-06 03:41:10 +00:00
zowoq
ec12953822 packaging: fix lowdown with overridden nixpkgs
unstable has a patch that doesn't apply to 2.0.2
2026-01-06 13:15:55 +10:00
Sergei Zimmerman
22e46fb0ef Merge pull request #14920 from NixOS/fix-ci-oom
tests/functional: Reduce max-call-depth for stack overflow tests
2026-01-06 02:39:46 +00:00
Sergei Zimmerman
9859068689 tests/functional: Reduce max-call-depth for stack overflow tests
This OOMs VM tests in CI and it's just wasteful.
2026-01-06 02:34:48 +03:00
Sergei Zimmerman
cc5a403bc4 Merge pull request #14919 from artemist/cgroup-fix
Fix creation of cgroups
2026-01-05 20:57:03 +00:00
Artemis Tosini
357a45253c Fix creation of cgroups
A commit in #14800 broke tests around creating cgroups due to incorrect
path handling logic.
(See https://hydra.nixos.org/build/318367985/nixlog/11)

Fix that logic and represent cgroups as CanonPath.

Co-authored-by: John Ericson <John.Ericson@Obsidian.Systems>
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2026-01-05 19:48:08 +00:00
John Ericson
1807dc78d6 Split out separate coroutine functions for with/without hook
This makes the logic much easier to follow. Unlike before, the use of
separate functions is not making us pass a gazillion arguments or use
the crutch of class variables.
2026-01-05 14:38:25 -05:00
John Ericson
cf5644ce99 DerivationBuildingGoal Make some fields constant
These are immutable parameters, not state, set in the constructor.
2026-01-05 14:38:25 -05:00
John Ericson
47ccf201fb Make DerivationBuildingGoal::inputPaths local variable 2026-01-05 14:38:25 -05:00
John Ericson
ec65132ab9 Shrink DerivationBuildingGoal::tryBuildHook
There was a bunch of logic in there which was, effectively, using the
build hook, rather than deciding *whether* to use the build hook. We
want it to only be the latter.
2026-01-05 14:38:25 -05:00
John Ericson
bde0b22dc8 Factor out LogFile, do more RAII
It is weird that `LogFile` and `BuildLog` are basically unrelated, but
the does currently reflect the logic that exists.
2026-01-05 14:38:24 -05:00
John Ericson
a8e8614fd3 BuildLog owns activities
Now it does more, using the logging.hh functionality as needed.
2026-01-05 14:29:42 -05:00
John Ericson
6a32b754a9 Inline DerivationBuildingGoal::logSize
Separate state for each loop.
2026-01-05 14:29:42 -05:00
John Ericson
43a472631b Factor out BuildLog
This gets some trickier pure logic out of `DerivationBuilderGoal`.
2026-01-05 14:29:42 -05:00
John Ericson
eff403b5ab Inline DerivationBuildingGoal::builder 2026-01-05 14:29:42 -05:00
John Ericson
6e6dda9f67 Inline DerivationBuildingGoal::hook
Also remove uneeded arguments from `processChildOutput`.
2026-01-05 14:29:42 -05:00
John Ericson
ee1383f75f Get cleanup logic out of DerivationBuildingGoal::processChildOutput
This will allow for making `hook` and `builder` local variables.
2026-01-05 14:29:42 -05:00
John Ericson
5be07abf6d Inline DerivationBuildingGoal::killChild 2026-01-05 14:29:42 -05:00
John Ericson
469212bd38 Inline DerivationBuildingGoal::currentHookLine
That's easy to do now.
2026-01-05 14:29:42 -05:00
John Ericson
4a1a562461 Inline the hook-only part of processChildOutput to that caller 2026-01-05 14:29:42 -05:00
John Ericson
6c884fff0c Merge pull request #14802 from NixOS/improve-timeouts-test
Improve the timeouts test
2026-01-05 19:29:16 +00:00
Eelco Dolstra
bf3638376f Merge pull request #14918 from NixOS/rename-realPathInSandbox
Rename realPathInSandbox() -> realPathInHost()
2026-01-05 18:03:21 +00:00
Eelco Dolstra
d022cb61f2 Rename realPathInSandbox() -> realPathInHost()
This function was named incorrectly. It denotes the path in the host
filesystem, not in the sandbox.
2026-01-05 18:18:46 +01:00
John Ericson
31bffd3c78 Merge pull request #14897 from NixOS/drop-kaitai
Drop kaitai checks
2026-01-05 15:14:13 +00:00
Sergei Zimmerman
7610d07601 Merge pull request #14911 from tomfitzhenry/set-extract-unused-result
fix: replace unused-result of set::extract with erase
2026-01-05 14:24:37 +00:00
Sergei Zimmerman
ab7c0ae4a3 Drop kaitai checks
Pulling in the java into the tests closure for just testing a piece of code
for the docs (and the tests actually are wrong, since a correct parser must *reject*
those NARs). This is too much of an ask to maintain for zero benefit. I already had
to disable it basically everywhere, because it works only on linux.

It can be revisited in the future, but considering that it's not exercised anywhere and
shouldn't be used anywhere other than a toy example for the docs I think it's best to drop
it.
2026-01-04 21:45:34 -05:00
John Ericson
fef2e2e314 Merge pull request #14800 from obsidiansystems/std-file-system-path-in-builder
Use `std::filesystem::path` in `DerivationBuilder`
2026-01-04 22:39:09 +00:00
Jörg Thalheim
644be074e1 Merge pull request #14916 from NixOS/drop-docker-push-on-master
ci: Stop uploading docker images for pre-release versions
2026-01-02 16:23:54 +00:00
Sergei Zimmerman
b75403f15b ci: Stop uploading docker images for pre-release versions
This is no longer needed (best I can tell), since nix docker
images now get uploaded to GHCR as part of the release process too
and they contain both aarch64 and x86_64 instead of only x86_64.
2026-01-02 18:36:38 +03:00
Sergei Zimmerman
28c7e42ab5 Merge pull request #14624 from roberth/deepSeq-stack-overflow
Fix most remaining stack overflows
2026-01-02 14:53:07 +00:00
Tom Fitzhenry
401fbe3981 fix: replace unused set::extract with erase
As of https://github.com/llvm/llvm-project/pull/169982 this will be
caught by LLVM, and it's the only such example.
2026-01-02 11:37:15 +11:00
Jörg Thalheim
e44e1cc99c Merge pull request #14903 from NixOS/release-github-actions-workflow
upload-release.pl: Fix up nix-channels bucket location, use awscli2
2026-01-01 20:47:33 +00:00
Sergei Zimmerman
0900638f1d 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.
2026-01-01 22:21:15 +03:00
John Ericson
df74624754 Merge pull request #14896 from NixOS/fix-freebsd
libutil: Fix on freebsd
2026-01-01 14:20:48 +00:00
John Ericson
73a7962073 Merge pull request #14888 from NixOS/release-github-actions-workflow
ci: GitHub releng for release automation
2026-01-01 14:19:44 +00:00
Sergei Zimmerman
f129bbb9e9 libutil: Fix on freebsd
Also remove the redundant ifdef. I forgot to add the necessary includes
while moving the code around.
2026-01-01 16:25:41 +03:00
Sergei Zimmerman
4b8991256a dev-shell: Fix on freebsd 2026-01-01 15:26:54 +03:00
tomberek
843395a2c8 Merge pull request #14821 from obsidiansystems/local-binary-cache-store-upsert
`LocalBinaryCacheStore::upsertFile` support slash in path
2025-12-31 20:17:11 +00:00
tomberek
fc52891b44 Merge pull request #14892 from roberth/flake-compat-44-builtins-path-hash
Improve builtins.path docs wrt recursive, sha256
2025-12-31 02:20:56 +00:00
John Ericson
04c0e3432a Use std::filesystem::path in DerivationBuilder
Since it is currently unix-only, we can use `.native()` not `.string()`
for perf, and we don't have to worry about platform-specific
conversions.
2025-12-30 14:39:54 -05:00
Eelco Dolstra
dd75397f73 Merge pull request #14894 from NixOS/undo-push
Undo accidental push to master
2025-12-30 18:45:40 +00:00
Eelco Dolstra
2c55c4aae4 Revert "Add builtins.imap function"
This reverts commit 4db99ea955.
2025-12-30 19:09:59 +01:00
Eelco Dolstra
80c9ad7de4 Revert "Pre-allocate small integers in builtins.{genList,imap}"
This reverts commit 24610d51f4.
2025-12-30 19:09:55 +01:00
Eelco Dolstra
24610d51f4 Pre-allocate small integers in builtins.{genList,imap} 2025-12-30 18:56:34 +01:00
Eelco Dolstra
4db99ea955 Add builtins.imap function
This allows the `imap0` and `imap1` functions (which are called
hundreds of thousands of times during NixOS evaluation) to be done
more efficiently.
2025-12-30 18:56:34 +01:00
Sergei Zimmerman
84ff2ef347 release-process: Document usage of upload-release.yml workflow 2025-12-30 02:28:04 +03:00
Sergei Zimmerman
3933e45d52 upload-release: Only upload the newly created tag 2025-12-30 02:28:02 +03:00
Sergei Zimmerman
a1569458cc upload-release: Also push to GHCR as part of the release process 2025-12-30 02:00:21 +03:00
Sergei Zimmerman
4599daa10e 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.
2025-12-30 02:00:20 +03:00
Sergei Zimmerman
6cb8b58a47 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/
2025-12-30 02:00:19 +03:00
Sergei Zimmerman
d19b8d5f99 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
2025-12-30 02:00:17 +03:00
Robert Hensing
0068d58b18 tests: builtins.path: add explicit directory hash test
Add a test case that explicitly demonstrates NAR hashing of a directory
without using a filter. Add comments to clarify what each test case is
testing (NAR vs flat hashing).
2025-12-29 22:16:54 +01:00
Robert Hensing
08bcd70ecb doc: builtins.path: link to content-address docs for hash methods
The sha256 parameter documentation said "file at the path" but it
works with directories too (using NAR hashing). Link to the
content-address documentation instead of duplicating information.
2025-12-29 22:15:45 +01:00
tomberek
b5e039b7c1 Merge pull request #14879 from ConnorBaker/fix/eval-cache-parsing-of-contexts
eval-cache: fix parsing of contexts
2025-12-29 20:35:49 +00:00
tomberek
e8080379ee Merge pull request #14887 from steelman/xdg-state-home-manual
docs: fix typos
2025-12-29 20:29:48 +00:00
tomberek
56ab28c1ad Merge pull request #14890 from Mic92/clang-tidy
clang-tidy cleanups
2025-12-29 20:29:08 +00:00
Jörg Thalheim
b066db6011 libutil: break circular include between signals.hh and signals-impl.hh
Remove include of signals.hh from signals-impl.hh to fix
misc-header-include-cycle warning. The impl header is only included
from signals.hh which already provides the necessary declarations.
2025-12-29 15:25:52 +00:00
Jörg Thalheim
8aa02c19b6 libutil: add missing pos field initializer in BaseError constructors
When using designated initializers, clang-tidy warns about skipped
fields. Explicitly initialize pos to {} to silence the
clang-diagnostic-missing-designated-field-initializers warning.
2025-12-29 15:25:46 +00:00
Łukasz Stelmach
b2fdacd36c docs: fix typos 2025-12-29 01:07:47 +01:00
Connor Baker
edebabe9bf eval-cache: fix parsing of contexts
The members of the context were serialized with a space as the delimiter, not a semicolon.

Signed-off-by: Connor Baker <ConnorBaker01@gmail.com>
2025-12-28 15:38:31 +00:00
Sergei Zimmerman
b17034ba59 Merge pull request #14874 from xokdvium/flake-regression-reuse-nix-closure
ci: Run flake-regressions also with the newly built daemon
2025-12-28 14:46:15 +00:00
Sergei Zimmerman
5aa2af1354 Merge pull request #14872 from xokdvium/docker-push-image-separate-workflow
ci: Move docker_push_image into a separate workflow
2025-12-28 13:07:59 +00:00
Sergei Zimmerman
c54af23b41 ci: Pin download-artifact actions sha 2025-12-28 05:36:20 +03:00
Sergei Zimmerman
6eebfe6274 ci: Run flake-regressions also with the newly built daemon
Runs the tests against the new daemon as well as the cli.

This more reliably shares the artifact (not relying directly on github
actions cache). We've seen github evict our caches super fast, so it would
be nice to move away from it entirely if possible.
2025-12-28 05:18:43 +03:00
Sergei Zimmerman
c867ed6726 ci: Make docker-push workflow more configurable
This should allow reusing this workflow (with more tweaks)
in the releng workflow.
2025-12-28 03:35:40 +03:00
Sergei Zimmerman
fb05f6de0d ci: Pin actions in docker-push reusable workflow 2025-12-28 03:35:39 +03:00
Sergei Zimmerman
745983dfc0 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.
2025-12-28 03:35:36 +03:00
Sergei Zimmerman
8093df5255 Merge pull request #14845 from Zaczero/zaczero/BufferedSource--readLine
Add buffered line reads to BufferedSource
2025-12-27 20:55:43 +00:00
Kamil Monicz
b813ed2602 Add buffered line reads to BufferedSource
Provide BufferedSource::readLine for opt-in buffered line reading. Migrate applicable call sites.
2025-12-27 23:10:10 +03:00
Jörg Thalheim
f6ca5dc5cb Merge pull request #14865 from Mic92/daemon-deadlock
daemon: fix deadlock when SSH client disconnects during remote builds
2025-12-26 14:31:31 +00:00
Jörg Thalheim
cfe5fc6a4a Merge pull request #14855 from NoRePercussions/norepercussions/push-ymokollxlmvw
fix: make --rebuild failures actionable
2025-12-26 12:11:51 +00:00
Jörg Thalheim
0b5773d1d0 Merge pull request #14838 from NixOS/double-callback-filetransfer
libstore/filetransfer: Fix double callback on enqueueFileTransfer that is shutting down
2025-12-26 11:32:29 +00:00
Jörg Thalheim
212bf2b702 daemon: fix deadlock when SSH client disconnects during remote builds
When a remote SSH client disconnects during a long-running operation
like addToStore(), the nix-daemon can deadlock in a circular wait:

  - Process A (SSH daemon): blocked reading from downstream store socket,
    waiting for response from local daemon
  - Process B (local daemon): blocked reading from upstream socket,
    waiting for more NAR data from SSH daemon

The existing interrupt mechanism (ReceiveInterrupts + MonitorFdHup)
correctly detects the SSH disconnect and sets _isInterrupted, but the
daemon remains blocked in read() on the downstream store connection.
Even though SIGUSR1 causes read() to return EINTR, the circular
dependency prevents forward progress.

Fix this by adding shutdownConnections() to RemoteStore that calls
shutdown(fd, SHUT_RDWR) on all tracked connection file descriptors.
Register an interrupt callback in processConnection() that invokes
this method when the store is a RemoteStore. This causes any blocking
read() to return 0 (EOF), breaking the circular wait and allowing
both processes to exit cleanly.

The fix tracks connection FDs in a synchronized set, populated when
connections are created by the Pool factory. On interrupt, all FDs
are shut down regardless of whether they're idle or in-use.
2025-12-25 06:28:41 +00:00
Sergei Zimmerman
a3bcd2543e Merge pull request #14862 from NixOS/more-precise-exceptions-memory-source-accessor
libutil: Make MemorySourceAccessor throw more precise errors
2025-12-24 20:13:18 +00:00
Sergei Zimmerman
76c6f3cfd0 libutil: Make MemorySourceAccessor throw more precise errors
Makes the error messages render paths correctly, also introduces
a new hierarchy of error classes for SourceAccessor related errors
that we might want to handle differently (e.g. like when doing a readFile
on a directory and such). This should make it easier to implement better
UnionSourceAccessor and AllowListSourceAccessor by catching these errors
consistently.
2025-12-24 01:49:29 +03:00
Jörg Thalheim
3c3e5cbcdb Merge pull request #14792 from Enzime/push-roqmwvnknzqw
Fix `curl` with `c-ares` failing to resolve DNS inside sandbox on macOS
2025-12-23 09:07:29 +00:00
Sergei Zimmerman
130a656330 Merge pull request #14846 from roberth/issue-14816
Fix empty input path segfault (#14816)
2025-12-22 21:27:26 +00:00
Tucker Shea
396358dc08 fix: make --rebuild failures actionable
See #8188. Resolves issues about the error not
being actionable, but I am not marking it closing
yet because of further discussion about the naming
of these flags in the thread.

`nix build --rebuild` (and others)
will fail if the derivation has not been built
before, because it runs a check build and
confirms that the build was deterministic.

It may be unclear to users that --rebuild will fail
if the derivation has never been built before,
because the flag makes no indication that a
determinism check occurs.

The error message does
not help clear this up, or provide any actionable
steps, and at first glance seems to indicate that
the derivation being built is invalid, rather than
just not present in the store:

```
error: some outputs of '...' are not valid, so checking is not possible
```

We can suggest to the user the following (correct)
rewrites. This list of commands that may result in
the error is comprehensive.

- `nix build --rebuild` to `nix build` or `nix build --repair`
- `nix-build --check` to `nix-build` or `nix-build --repair`
- `nix-store --realise --check` to `nix-store --realise` or `nix-store --realise --repair`

Wording is based on that in the documentation:

```
(nix build)
--repair During evaluation, rewrite missing or
         corrupted files in the Nix store. During
         building, rebuild missing or corrupted
         store paths.

(nix-build)
--repair Fix corrupted or missing store paths by
         redownloading or rebuilding them. Note
         that this is slow because it requires
         computing a cryptographic hash of the
         contents of every path in the closure
         of the build. Also note the warning
         under nix-store --repair-path.

(nix-store --realise)
--repair Fix corrupted or missing store paths by
         redownloading or rebuilding them. (etc)
```
2025-12-22 11:23:08 -05:00
Jörg Thalheim
d85e5dfa60 Merge pull request #14843 from mdaniels5757/document-old-let-expression-syntax
docs: document older let expression syntax
2025-12-21 18:16:01 +00:00
Sergei Zimmerman
96204ea6bd Merge pull request #14785 from YawKar/master
libstore: include path in the world-writable error
2025-12-21 17:49:24 +00:00
Michael Daniels
c6ac52da70 docs: document older let expression syntax
I learned of this from reading Eelco Dolstra's PhD thesis (pp. 69, 73-74).

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2025-12-21 17:28:16 +00:00
John Ericson
b168ec2277 Merge pull request #14842 from mdaniels5757/docs-add-let-semicolon
docs: add missing semicolon to let-in grammar
2025-12-21 15:43:52 +00:00
Robert Hensing
cc88e1aa82 libflake-c: improve input override error message clarity
Make the C API error message more explicit about what went wrong and
why it's invalid. The new message explains that a zero-length path was
passed and clarifies that it would refer to the flake itself.

Updates the unit test to match the new error message.
2025-12-21 13:08:29 +01:00
John Ericson
f457245a9a Merge pull request #14844 from corngood/cygwin-cross
packaging: disable LTO on cygwin
2025-12-21 05:30:54 +00:00
David McFarland
ce16d6fdd3 packaging: disable LTO on cygwin
This was already done for windows, and it fails in the same way.
2025-12-20 22:52:44 -04:00
Sergei Zimmerman
b6dd17d6f2 Merge pull request #14841 from mdaniels5757/syntax-doc-fix-link
docs: fix string interpolation links on syntax page
2025-12-20 22:04:14 +00:00
Robert Hensing
b1a230de75 libcmd: improve --override-input error message clarity
Make the error message more explicit about what went wrong and why
it's invalid. The new message explains that a zero-length path was
passed and clarifies that it would refer to the flake itself.
2025-12-20 04:26:20 +01:00
Robert Hensing
bec436c0b1 libflake: reject empty paths in inputUpdates
An empty path refers to the flake itself, not an input. Apply the same
type safety to inputUpdates as inputOverrides.

The deprecated --update-input flag (deprecated since Nix 2.4) and the
modern 'nix flake update' command now properly reject empty paths.

Includes functional tests for both commands.
2025-12-20 04:26:20 +01:00
Robert Hensing
f7fc24c973 libflake: introduce NonEmptyInputAttrPath type
Wraps InputAttrPath with compile-time guarantee of non-emptiness.
Replaces obscure .back() calls with domain-specific inputName() method.

An empty path refers to the flake itself, making it nonsensical for
input override operations. The type system now prevents this.
2025-12-20 04:23:45 +01:00
Robert Hensing
63cfefd6cb libflake-c: reject empty input override paths
An empty attribute path refers to the flake itself, contradicting
the purpose of input overrides, which are for overriding inputs.

Related: #14816
2025-12-20 00:37:11 +01:00
Robert Hensing
fefcc4c7cc libcmd: reject empty --override-input paths
An empty attribute path refers to the flake itself, contradicting
the purpose of --override-input, which is for overriding inputs.

Fixes: #14816
2025-12-20 00:36:42 +01:00
Michael Daniels
a720cb0656 docs: add missing semicolon to let-in grammar 2025-12-19 17:57:48 -05:00
Michael Daniels
32a79fcbbf docs: fix string interpolation links on syntax page 2025-12-19 17:25:04 -05:00
Sergei Zimmerman
132a93625b Merge pull request #14827 from Zaczero/zaczero/libexpr
libexpr: add nix-expr-benchmarks, add regex optimizations
2025-12-19 21:24:05 +00:00
John Ericson
5cf1c0ebca Merge pull request #14837 from NixOS/fix-query-substitutable
libstore/store-api: Do not query all substituters for substitutable p…
2025-12-19 14:00:35 +00:00
Eelco Dolstra
6b52fa8360 Merge pull request #12087 from DeterminateSystems/multithreaded-git-sink
Make GitFileSystemObjectSink multi-threaded
2025-12-19 12:20:22 +00:00
Eelco Dolstra
19a2493132 Fix random missing re-throw 2025-12-19 12:14:29 +01:00
Eelco Dolstra
6bea8e0e08 GitFileSystemObjectSink: Fix crash during interrupt 2025-12-19 12:06:55 +01:00
Sergei Zimmerman
8104858643 libstore/filetransfer: Fix double callback on enqueueFileTransfer that is shutting down 2025-12-19 07:25:18 +03:00
Sergei Zimmerman
a6c1d5637a libstore/filetransfer: Remove unused using namespace 2025-12-19 05:20:45 +03:00
Sergei Zimmerman
f1f99b6598 Merge pull request #14835 from Zaczero/zaczero/reserve-perf
Fix reserve pitfall in printString
2025-12-19 02:06:07 +00:00
Sergei Zimmerman
2308f200c8 libstore/store-api: Do not query all substituters for substitutable path infos
This was broken in 11d7c80370.
2025-12-19 04:52:53 +03:00
Kamil Monicz
048d0b6781 libexpr: avoid regex engine in getDerivations attr filtering
- getDerivations() filters attribute names with std::regex_match, which runs the regex engine for every attribute visited during nixpkgs scanning.
- BM_GetDerivationsAttrScan/10000_mean: 3.338 ms → 1.506 ms (≈ -54.9%)
2025-12-19 02:10:11 +01:00
Kamil Monicz
0c8751d3f4 libexpr: avoid std::regex copies on RegexCache hits
- RegexCache::get() returned std::regex by value, copying the compiled regex on every cache hit.
- Store the compiled regex behind std::shared_ptr<const std::regex> and return the shared pointer instead, so callers reuse the same compiled object.
- BM_EvalManyBuiltinsMatchSameRegex_mean improved about 8%
2025-12-19 02:10:11 +01:00
Kamil Monicz
723c47550e libexpr-tests: add nix-expr-benchmarks
Provides focused microbenchmarks for expression evaluation hot paths (dynamic attrs, getDerivations attr scanning, and repeated builtins.match).
2025-12-19 02:10:05 +01:00
Kamil Monicz
66c867395f Fix reserve pitfall in printString
Remove the per-call reserve() inside printString to avoid linear-growth reallocations when called in loops (e.g. printStrings). Derivation::unparse already pre-reserves a large buffer, so this remains efficient while preserving amortized growth behavior when the initial estimate is exceeded.
2025-12-19 01:03:30 +00:00
Sergei Zimmerman
27006cc8a9 Merge pull request #14832 from NixOS/o-tmpfile-fallback
libutil: Gracefully fall back from unsupported O_TMPFILE
2025-12-18 20:39:56 +00:00
Sergei Zimmerman
06f21596a0 libutil: Gracefully fall back from unsupported O_TMPFILE
Some filesystems, notably most FUSE-based ones and some top-level overlaysfs
ones do not support this and we need a graceful fallback.
2025-12-18 22:12:14 +03:00
Jörg Thalheim
9254fab407 Merge pull request #14828 from Zaczero/zaczero/libstore-registerValidPaths
libstore: reuse parsed derivations in registerValidPaths
2025-12-18 12:59:43 +00:00
Michael Hoang
7541129f04 Fix curl with c-ares failing to resolve DNS inside sandbox on macOS 2025-12-18 11:45:18 +01:00
Jörg Thalheim
994324feda libstore-tests: reduce registerValidPaths benchmark to single test case
Testing with 10 derivations is sufficient to verify performance
characteristics. The larger test cases (50, 200) don't provide
additional insight and slow down the benchmark unnecessarily.
2025-12-18 09:46:03 +01:00
Jörg Thalheim
1f739961e5 libstore: simplify registerValidPaths by removing redundant checkInvariants loop
The separate checkInvariants loop after addValidPath was added in 2014
(d210cdc43) to work around an assertion failure:

  nix-store: derivations.cc:242: Assertion 'store.isValidPath(i->first)' failed.

At that time, hashDerivationModulo() contained assert(store.isValidPath(...))
which required input derivations to be registered as valid in the database
before computing their hash. The workaround was to:
1. Call addValidPath with checkOutputs=false
2. Add all references to the database
3. Run checkInvariants in a separate loop after paths were valid

In 2020 (bccff827d), the isValidPath assertion was removed to fix a
deadlock in IFD through the daemon (issue #4235). The fix changed
hashDerivationModulo to use readInvalidDerivation, which reads directly
from the filesystem without requiring database validity.

This made the separate checkInvariants loop unnecessary, but nobody
noticed the code could be simplified. The comment "We can't do this in
addValidPath() above, because the references might not be valid yet"
became stale.

Now we simply call addValidPath() with the default checkOutputs=true,
which runs checkInvariants internally using the already-parsed
derivation. This commit eliminates the separate loop over derivations.
2025-12-18 09:34:17 +01:00
Kamil Monicz
cccfa385e6 libstore: reuse parsed derivations in registerValidPaths
- LocalStore::registerValidPaths() parsed derivations twice: once in addValidPath() and again when calling checkInvariants(), despite already having loaded the derivation.
- Plumb the parsed Derivation out of addValidPath() and reuse it for the invariant check pass, falling back to re-parsing only when a derivation wasn’t newly registered in this call.
- BM_RegisterValidPathsDerivations/200_mean runs 32% faster
2025-12-18 06:00:38 +01:00
Kamil Monicz
9d2100a165 libstore-tests: benchmark registerValidPaths on derivations
- Add a focused nix-store-benchmarks benchmark that registers many derivation paths into a temporary local store root
2025-12-18 06:00:31 +01:00
John Ericson
4769f3c0b2 Merge pull request #14824 from roberth/issue-14776
doc: drop rsync dependency from manual build
2025-12-18 03:18:45 +00:00
Robert Hensing
ab354dc8f6 doc: drop rsync dependency from manual build
rsync was only used to copy source files while following symlinks.
Replace with tar --dereference, which serves the same purpose.
Tried plain cp but couldn't get it to work reliably. tar is already
a test dependency.

Add tests/functional/derivation to fileset to include the symlink
targets.

Fixes #14776
2025-12-18 03:41:45 +01:00
John Ericson
188cb798ad Merge pull request #14817 from NixOS/fix-socket-mingw
Windows fixes
2025-12-18 00:30:19 +00:00
John Ericson
3cc07ede73 LocalBinaryCacheStore::upsertFile support slash in path
While working on #12464, I realized this method was not correct in this
case. With the current binary cache format, it is harmless, since we
don't create arbitrary directories, but with my change, we started to.

Regardless of whether we need it or not, I think it is better if the
function just does the right thing.
2025-12-17 17:40:51 -05:00
John Ericson
1aa7ab0dcf Merge pull request #14819 from NixOS/mingw-fixes-more
Assorted windows fixes for libutil, HANDLEs and path handling
2025-12-17 22:28:27 +00:00
John Ericson
208ed3c538 Fix select / fdset usage on Windows
These functions use `SOCKET` not `int`, despite them being unix
functions.
2025-12-17 16:55:04 -05:00
John Ericson
b6add8dcc6 Merge pull request #14818 from NixOS/fix-windows-dev-shell
Fix up dev shell in a few ways
2025-12-17 21:52:56 +00:00
John Ericson
79750a3ccc Split out socket.hh from unix-domain-socket.hh
There are other types of sockets.
2025-12-17 16:51:01 -05:00
John Ericson
30cd9e43e1 Fix windows build of new source accessor test
We don't have the dirFd on window at this time.
2025-12-17 16:51:01 -05:00
Sergei Zimmerman
0695630eb5 libutil: Fix FdSource::read on Windows
We need to signal the EOF condition, otherwise the read never terminates.
2025-12-18 00:30:07 +03:00
Sergei Zimmerman
89dc57f6aa libutil: Implement HANDLE-based lseek for Windows
For windows we should live fully in the HANDLE land instead
of converting back-n-forth (which sometimes is destructive).
Using native API is much better for this.
2025-12-18 00:30:06 +03:00
Sergei Zimmerman
f274a7273a libutil: Implement deletePath on windows via std::filesystem::remove_all
It doesn't track the number of bytes deleted, but since this code is
security critical also we can split unix and windows implementations.
If the need arises we can implement a smarter recursive deletion function
ourselves in the future.

Review with --color-moved.
2025-12-18 00:30:05 +03:00
Sergei Zimmerman
675656ffba libutil: Fix canonPath, makeTempPath and createTempDir on windows
This at least makes canonPath not consider the drive letter as a path
component. There still some issues with it on windows, but at least
this gets us through some of the libutil-tests.

Also since we don't want to change which env variables nix considers
we don't use std::filesystem::temp_directory_path and implement the
windows version directly.
2025-12-18 00:30:04 +03:00
John Ericson
a5edc2d921 Fix up dev shell in a few ways
- Skip packages that don't build for Windows when building for windows
- Automatically disable kaitai / json schema, fixing todo
- Skip native build of Nix for manual
2025-12-17 15:41:47 -05:00
Eelco Dolstra
97e3816b24 Remove assertion 2025-12-17 12:54:29 +01:00
Eelco Dolstra
7998508a40 Apply suggestions from code review
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-12-17 12:54:29 +01:00
John Ericson
2f092870e4 Merge pull request #14648 from obsidiansystems/goal-division-of-labor
`DrvOutputSubstitutionGoal`: Don't actually fetch any store objects
2025-12-17 03:10:18 +00:00
John Ericson
b39da9c0c2 Merge pull request #14815 from NixOS/source-accessor-tests
libutil-tests: Add tests for makeFSSourceAccessor
2025-12-17 02:27:45 +00:00
John Ericson
f536b25367 Merge pull request #14247 from obsidiansystems/no-dependent-realisations
Remove dependent realisations
2025-12-17 02:14:22 +00:00
Sergei Zimmerman
017fae3f14 libutil-tests: Add tests for makeFSSourceAccessor
Should be pretty self-explanatory. We didn't really have unit tests
for the filesystem source accessor. Now we do and this will be immensely
useful for implementing a unix-only smarter accessor that doesn't suffer
from TOCTOU on symlinks.
2025-12-17 04:42:31 +03:00
John Ericson
018d6462de DrvOutputSubstitutionGoal: Don't actually fetch any store objects
We now have a nice separation of concerns: `DrvOutputSubstitutionGoal`
is *just* for getting realisations, and `PathSubstitutionGoal` is just
for fetching store objects.

The fetching of store objects that this used to do is now moved to the
caller.
2025-12-16 20:18:53 -05:00
John Ericson
4a5d960952 Remove dependent realisations
This progress on #11896. It introduces some issues temporarily which
will be fixed when #11928 is fixed.

The SQL tables are left in place because there is no point inducing a
migration now, when we will be immediately landing more changes after
this that also require schema changes. They will simply be ignored by in
this commit, and so all data will be preserved.
2025-12-16 19:56:19 -05:00
John Ericson
8cf8a9151a Merge pull request #14814 from NixOS/suggestions-compression-algo-enum
libutil: Add CompressionAlgo enum, add Suggestions to UnknownCompress…
2025-12-17 00:27:36 +00:00
Sergei Zimmerman
4060ec3a8c libutil: Add CompressionAlgo enum, add Suggestions to UnknownCompressionMethod exception
Error messages now include suggestions like:

error: unknown compression method 'bzip'
       Did you mean one of bzip2, gzip, lzip, grzip or lrzip?

Also a bit of progress on making the compression code use less stringly
typed compression type, which is good because it's easy to confuse
which strings are accepted where (e.g. Content-Encoding should be able
to accept x-gzip, but it shouldn't be exposed in NAR decompression and
so on). An enum cleanly separates the concerns of parsing strings / handling
libarchive write/read filters.
2025-12-17 02:39:44 +03:00
Sergei Zimmerman
e0830681e2 Merge pull request #14552 from hsjobeki/docs-sort
docs: add explanation to sort primop
2025-12-16 20:31:12 +00:00
Jörg Thalheim
9f2795e588 Merge pull request #14805 from NixOS/dependabot/github_actions/cachix/install-nix-action-31.9.0
build(deps): bump cachix/install-nix-action from 31.8.4 to 31.9.0
2025-12-16 19:58:01 +00:00
Jörg Thalheim
12cee327a0 Merge pull request #14806 from NixOS/dependabot/github_actions/korthout/backport-action-4.0.1
build(deps): bump korthout/backport-action from 3.4.1 to 4.0.1
2025-12-16 19:56:42 +00:00
Jörg Thalheim
3b73dcba39 Merge pull request #14807 from NixOS/dependabot/github_actions/actions/upload-artifact-6
build(deps): bump actions/upload-artifact from 5 to 6
2025-12-16 19:56:23 +00:00
Jörg Thalheim
dfad4b1403 Merge pull request #14808 from NixOS/dependabot/github_actions/actions/download-artifact-7
build(deps): bump actions/download-artifact from 6 to 7
2025-12-16 19:56:06 +00:00
yawkar
a1e24fa6ce 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.
2025-12-16 19:50:51 +03:00
Eelco Dolstra
21a251be5f Pool: Add clear() method 2025-12-16 15:50:02 +01:00
Eelco Dolstra
5694772794 Remove use of processGraph() 2025-12-16 15:50:02 +01:00
Eelco Dolstra
720027470d Make GitFileSystemObjectSink run in bounded memory
If the total number of file buffers exceeds maxBufSize, we switch to
writing synchronously.
2025-12-16 15:50:02 +01:00
Eelco Dolstra
18fece25cd Restore multi-threaded GitFileSystemObjectSink 2025-12-16 15:50:02 +01:00
John Ericson
5f69fd3e8d Merge pull request #14804 from Eveeifyeve/windows-symlink-issue-fix
manual: Add note on windows to use a git setting to avoid symlink issues in building
2025-12-16 04:21:52 +00:00
John Ericson
47416968d2 Merge pull request #14793 from obsidiansystems/test-11928
Create substitution unit tests
2025-12-16 03:30:40 +00:00
John Ericson
ce38abb697 Merge pull request #14755 from obsidiansystems/warn-non-object-exportReferencesGraph
Add warning for non-JSON-object `exportReferencesGraph`
2025-12-16 03:30:25 +00:00
Sergei Zimmerman
a38fc659cc Merge pull request #14791 from NixOS/fix-special-member-functions-a-lot
treewide: Follow rule of five
2025-12-16 00:09:06 +00:00
John Ericson
85bbfd4493 Merge pull request #14803 from Eveeifyeve/windows-work
nix: don't require ln to build libstore
2025-12-15 22:27:45 +00:00
eveeifyeve
d5d7594029 manual: Add note on windows to use a git setting to avoid symlink issues in building
Ref #14787

This really doesn't really fixes the problem of the symlink, but it
solves the progress of getting windows working.

TODO: find out if it's a bug from meason & make a feature request to
avoid symlinks or generate symlinks upon build and git ignore, but still
goes back to the issue of is this a bug or do we need to make a feature
requests.

Co-authored-by: John Ericson <git@JohnEricson.me>
2025-12-16 09:09:33 +11:00
dependabot[bot]
1fc5648204 build(deps): bump actions/download-artifact from 6 to 7
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 22:01:01 +00:00
dependabot[bot]
d7e0bcaa51 build(deps): bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 22:00:57 +00:00
dependabot[bot]
4227d24bc3 build(deps): bump korthout/backport-action from 3.4.1 to 4.0.1
Bumps [korthout/backport-action](https://github.com/korthout/backport-action) from 3.4.1 to 4.0.1.
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](d07416681c...c656f5d585)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: 4.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 22:00:53 +00:00
dependabot[bot]
7720dad11f build(deps): bump cachix/install-nix-action from 31.8.4 to 31.9.0
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.8.4 to 31.9.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](0b0e072294...4e002c8ec8)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-version: 31.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 22:00:48 +00:00
eveeifyeve
832b81761e nix: don't require ln to build libstore 2025-12-16 08:33:20 +11:00
John Ericson
cc1edfaf5b Improve the timeouts test
- More concise
- Also checks error messages
- Checks more error codes

The nature of that bug is that if the first command's exit status is
correctly 101 and not 1, the rest should be correctly 101, 100, etc.
too.
2025-12-15 16:21:01 -05:00
John Ericson
1c63cf4001 Add warning for non-JSON-object exportReferencesGraph
This will help users debug their mistakes.
2025-12-15 15:53:19 -05:00
John Ericson
df7542247e Merge pull request #14801 from NixOS/coroutine-child-output-0
Use coroutines for worker child I/O
2025-12-15 20:25:17 +00:00
Jörg Thalheim
49f666c64d Merge pull request #14799 from NixOS/tarball-cache-v2
libfetchers: Bump tarball-cache version to v2
2025-12-15 19:58:28 +00:00
Jörg Thalheim
11f5a3124b Merge pull request #14645 from lovesegfault/s3-sts
feat(libstore): add AWS SSO support for S3 authentication
2025-12-15 19:44:26 +00:00
John Ericson
92e698426b Use coroutines for worker child I/O
This will enable way more RAII going forward.
2025-12-15 14:28:07 -05:00
John Ericson
906334686c Make worker timeouts a bit more strongly typed
This tidies things up in general, but also prepares the way for the next
commit in particular.
2025-12-15 14:27:21 -05:00
Sergei Zimmerman
0ffe83aa14 libfetchers: Bump tarball-cache version to v2
Unfortunately previous tarball caches had loose objects written to
them and subsequent switch to thin packfiles. This results in possibly
broken thin packfiles when the loose objects backend is disabled. Thin
packfiles do not necessarily contain the whole closure of objects.
When packfilesOnly is true we end up with an inconsistent state where
a tree lives in a packfiles which refers to a blob in the loose objects
backend.

In the future we might want to nuke old cache directories and repack
the tarball cache.
2025-12-15 22:12:08 +03:00
John Ericson
8e044f1ed0 Merge pull request #14798 from NixOS/devshell-debug
dev-shell: Set mesonBuildType to debugoptimized
2025-12-15 19:01:45 +00:00
Jörg Thalheim
453dbab1e8 fix(libstore/aws-creds): respect AWS_PROFILE environment variable
The SSO provider was unconditionally setting profile_name_override to
the (potentially empty) profile string from the S3 URL. When profile
was empty, this prevented the AWS CRT SDK from falling back to the
AWS_PROFILE environment variable.

Only set profile_name_override when a profile is explicitly specified
in the URL, allowing the SDK's built-in AWS_PROFILE handling to work.
2025-12-15 19:40:34 +01:00
Eelco Dolstra
fc81840a8e dev-shell: Set mesonBuildType to debugoptimized
Previously, we got debug symbols implicitly because we were using
`separateDebugInfo = true`, which adds `-ggdb` to the compiler flags.
2025-12-15 19:09:37 +01:00
Bernardo Meurer
71bdb33a36 test(s3-binary-cache-store): test profiles and provider chain 2025-12-15 19:05:16 +01:00
Bernardo Meurer
0595c5f7ee test(s3-binary-cache-store): clear credential cache between tests 2025-12-15 19:05:16 +01:00
Bernardo Meurer
11f108d898 test(s3-binary-cache-store): add profile support for setup_for_s3 2025-12-15 19:05:16 +01:00
Bernardo Meurer
128b2b5c56 chore(libstore/aws-creds): remove unused includes 2025-12-15 19:05:16 +01:00
Bernardo Meurer
508d4463e5 fix(libstore/aws-creds): add STS support for default profile
The default (empty) profile case was using CreateCredentialsProviderChainDefault
which didn't properly support role_arn/source_profile based role assumption via
STS because TLS context wasn't being passed to the Profile provider.

This change unifies the credential chain for all profiles (default and named),
ensuring:
- Consistent behavior between default and named profiles
- Proper TLS context is passed for STS operations
- SSO support works for both cases
2025-12-15 19:05:16 +01:00
Bernardo Meurer
3c8e45c061 refactor(libstore/aws-creds): improve error handling and logging
Add validation for TLS context and client bootstrap initialization,
with appropriate error messages when these fail. The TLS context failure
is now a warning that gracefully disables SSO, while bootstrap failure
throws since it's required for all providers.
2025-12-15 19:05:16 +01:00
Jörg Thalheim
ec91479076 libstore: add AWS SSO support for S3 authentication
This enables seamless AWS SSO authentication for S3 binary caches
without requiring users to manually export credentials.

This adds SSO support by calling aws_credentials_provider_new_sso() from
the C library directly. It builds a custom credential chain: Env → SSO →
Profile → IMDS

The SSO provider requires a TLS context for HTTPS connections to SSO
endpoints, which is created once and shared across all providers.
2025-12-15 19:05:16 +01:00
Sergei Zimmerman
b398c14045 Merge pull request #14795 from NixOS/git-repo-options
Add GitRepo::Options type
2025-12-15 17:38:44 +00:00
Eelco Dolstra
9a6f1e6266 GitRepo: Implement create flag
This was ignored for some reason.
2025-12-15 14:36:04 +01:00
Eelco Dolstra
1c728ce0de Add GitRepo::Options type
This makes a bunch of bool parameters more explicit.
2025-12-15 14:35:19 +01:00
John Ericson
e145632aef Add unit test for double floating drv substitution
This test will be updated to track progress on #11928 --- it shows the
issue currently.
2025-12-15 01:49:58 -05:00
John Ericson
5cdf2a19bd Add basic floating CA drv output subst unit test 2025-12-15 01:37:05 -05:00
John Ericson
bb74677b08 Create basic substitution unit tests
- substitute single store object

- substitute single store object with single dep
2025-12-15 01:18:34 -05:00
John Ericson
3cfac9b079 Allow Worker instances to be locally configured with substituters
This will be useful for unit tests.
2025-12-15 00:53:45 -05:00
Sergei Zimmerman
198628790b libutil: Also fix AutoUnmount special member functions 2025-12-15 01:35:21 +03:00
Sergei Zimmerman
54d2268d84 treewide: Follow rule of five
Good to explicitly declare things to not accidentally do twice the work by
preventing that kind of misuse.
This is essentially just cppcoreguidelines-special-member-functions lint
in clang-tidy.
2025-12-15 01:35:20 +03:00
Sergei Zimmerman
8c74aadbf7 libutil: Fix AutoRemoveJail special member functions
These can't be copied and moving requires special logic too.
2025-12-15 01:07:22 +03:00
John Ericson
3a62be7227 Fix path locks move/assignment
No copying allowed

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-12-15 00:36:54 +03:00
Jörg Thalheim
a6eb2e91b7 Merge pull request #14774 from roberth/fix-getenv-segfault
Fix getenv segfault
2025-12-13 08:09:54 +00:00
Robert Hensing
76c09bf3d4 Fix nix-build.cc double getenv("TZ") race condition
This is mostly theoretical, but the code was calling getenv("TZ")
twice: once to check if it's non-null, and again to get its value.
This creates a potential race condition where the environment could
change between calls.
2025-12-13 08:34:27 +01:00
Robert Hensing
de6fdb7da5 Extract getUnitTestData() to test-data.hh and fix unsafe getenv calls
The nix_api_store.cc tests and derivation-parser-bench.cc were using raw
getenv() calls or unsafe .value() calls on optional, which would segfault
when passed to std::filesystem::path constructor if the
_NIX_TEST_UNIT_DATA environment variable was not set.
2025-12-13 08:34:27 +01:00
Robert Hensing
b54dfb66dd Fix segfault in getUnitTestData() when env var not set
The previous implementation called .value() on std::optional without
checking if it had a value. When _NIX_TEST_UNIT_DATA was not set, this
would throw std::bad_optional_access or cause a segfault in code that
used the raw getenv() result.

The new implementation checks the optional first and throws an Error
with a helpful message directing users to run tests via meson. The
example includes --gdb since this situation may arise when trying to
debug tests without knowing about meson's test infrastructure.
2025-12-13 08:34:27 +01:00
Sergei Zimmerman
bb718d20a2 Merge pull request #14778 from agucova/fix-macos-shebang-flakiness
test: add shebangs to shell.nix test scripts
2025-12-13 03:41:30 +00:00
John Ericson
3b3bd018a5 Merge pull request #14781 from NixOS/curl-cleanup
libstore: Clean up cruft from filetransfer
2025-12-13 03:40:01 +00:00
tomberek
26b86a02db Merge pull request #14780 from NixOS/tarfile-warning
libutil/tarfile: Mention pathname in warning
2025-12-13 03:06:09 +00:00
Sergei Zimmerman
8358409fd0 Merge pull request #14772 from GrahamDennis/gdennis/fix-heap-use-after-free
[libstore]: Fix a heap-use-after-free bug
2025-12-13 00:25:11 +00:00
Sergei Zimmerman
46670a7f46 libstore/filetransfer: Replace curl_multi_wait with curl_multi_poll and get rid of CPP
Since 7.68 libcurl already provides curl_multi_wakeup, so we can drop the hacky
pipe setup (libcurl does this internally).
2025-12-13 03:00:58 +03:00
Sergei Zimmerman
ea96e6d07c libstore/filetransfer: Factor out appendHeaders, use std::unique_ptr to simplify ownership
Pretty self-explanatory. More RAII is good and unclutters the already heavily overloaded
destructors from ownership logic. Not yet touching CURL *req because that would be too churny.
2025-12-13 02:59:18 +03:00
Sergei Zimmerman
7e3de5361a libutil/tarfile: Mention pathname in warning
Fetching gcc-15.2.0.tar.gz I get a warning about UTF8 archive names. This
now mentions problematic pathnames.

warning: getting archive member 'gcc-15.2.0/gcc/testsuite/go.test/test/fixedbugs/issue27836.dir/Äfoo.go': Pathname can't be converted from UTF-8 to current locale.
warning: getting archive member 'gcc-15.2.0/gcc/testsuite/go.test/test/fixedbugs/issue27836.dir/Ämain.go': Pathname can't be converted from UTF-8 to current locale.

Also apparently libarchive depends on locale (yikes). Fixing reproducibility issues
that stem from this is a separate issue. At least having the warning actually mention
the pathname should be useful enough even though it's not actionable.

At least using the default locale yields something sane:

builtins.readDir "${gcc}/gcc/testsuite/go.test/test/fixedbugs/issue27836.dir"
{
  "Äfoo.go" = "regular";
  "Ämain.go" = "regular";
}
2025-12-13 01:54:14 +03:00
Agustín Covarrubias
7b3d7eb634 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
2025-12-12 18:04:37 -03:00
Graham Dennis
819a61acae [libstore]: Fix a heap-use-after-free bug 2025-12-12 08:42:23 +11:00
John Ericson
ccba158780 Merge pull request #14767 from NixOS/bump-2.34.0
Bump version
2025-12-10 21:14:12 +00:00
John Ericson
4945c38b88 Merge pull request #14770 from NixOS/derivation-show-json-guidlines
Bring `nix derivation show` in compliance with JSON guidelines
2025-12-10 21:13:27 +00:00
John Ericson
0f18076f3a Bring nix derivation show in compliance with JSON guidelines
This matches what we just did for `nix path-info`, and I hope will allow
us to avoiding any more breaking changes to this command for the
foreseeable future.
2025-12-10 15:30:12 -05:00
Eelco Dolstra
c6ddc5cf1d Bump version 2025-12-10 17:35:28 +01:00
Eelco Dolstra
8b955d80c2 Merge pull request #14752 from NixOS/release-notes
2.33 release notes
2025-12-10 15:37:55 +00:00
Eelco Dolstra
3e832b61ec Merge pull request #14759 from NixOS/fix-netrc-path
globals: Fix netrc-file default value
2025-12-10 12:19:58 +00:00
Sergei Zimmerman
fd6c4614cf globals: Fix netrc-file default value
std::filesystem::path does quoting by default so it resulted in:

> netrc-file = "/etc/nix"/netrc
2025-12-10 03:34:10 +03:00
Sergei Zimmerman
99baaf7444 Add more release notes 2025-12-10 02:08:02 +03:00
Eelco Dolstra
46895edfce Fix issues found by Claude 2025-12-09 16:53:40 +01:00
Eelco Dolstra
17f07f6c04 Add more release notes 2025-12-09 16:48:02 +01:00
Eelco Dolstra
9c2be01285 Organize release notes 2025-12-09 16:17:36 +01:00
Eelco Dolstra
8493c541fa Update release credits 2025-12-09 15:36:45 +01:00
Eelco Dolstra
68a802d253 release notes: 2.33.0 2025-12-09 15:26:59 +01:00
Johannes Kirschbauer
af6326dfa4 docs: add explanation to sort primop 2025-12-05 10:03:43 +01:00
Robert Hensing
fd1ecfbfc8 libexpr: fix stack overflow in printAmbiguous on deeply nested structures
printAmbiguous (used by nix-instantiate --eval and nix-env) had a depth
parameter, but all callers passed INT_MAX, effectively disabling the
limit. The function relied on the C++ stack to eventually overflow,
which could cause uncontrolled SIGSEGV crashes on deeply nested
pre-forced structures.

Now printAmbiguous checks depth against max-call-depth (default 10000)
and throws StackOverflowError with a proper trace, consistent with
other recursive value traversal functions.

The function signature is updated to take EvalState& to access the
settings and throw proper errors. The depth parameter now counts up
from 0 instead of down from INT_MAX.
2025-11-22 23:29:31 +01:00
Robert Hensing
c2d2a0fe2d libexpr: fix stack overflow in checkMeta on deeply nested structures 2025-11-22 22:34:37 +01:00
Robert Hensing
4167686789 libexpr: fix stack overflow in coerceToString on deeply nested structures 2025-11-22 22:25:51 +01:00
Robert Hensing
075242b096 libexpr: fix stack overflow in eqValues on deeply nested structures
Also fix assertEqValues for consistency.
2025-11-22 22:21:08 +01:00
Robert Hensing
3965b6889a libexpr: fix stack overflow in printValueAsXML on deeply nested structures 2025-11-22 22:10:10 +01:00
Robert Hensing
03ca960c14 libexpr: fix stack overflow in Printer::print on deeply nested structures
Non-cyclic structures can be infinitely deep when values are lazily
produced (e.g., `let f = n: { inner = f (n + 1); }; in f 0`). Since f
returns immediately with a thunk, Nix call depth stays at 1, but
Printer::print recurses on the C++ stack when printing.

We check print depth against max-call-depth rather than incrementing
the callDepth counter, because accessing an attribute is not a call.

StackOverflowError is always re-thrown because stack overflow is a
serious condition that expressions should avoid, unlike say `throw`,
which can be part of legitimate expression patterns.
2025-11-22 22:04:22 +01:00
Robert Hensing
651dc72506 libexpr: Add subclass StackOverflowError
This way it can be handled reliably.
2025-11-22 21:47:00 +01:00
Robert Hensing
5166cee704 libexpr: fix stack overflow in getDerivations on deeply nested structures
nix-instantiate on deeply nested structures with recurseForDerivations
(e.g., `let x = { recurseForDerivations = true; more = x; }; in x`)
caused an uncontrolled OS-level stack overflow with no Nix stack trace.

Fix by adding call depth tracking to getDerivations, integrating with
Nix's existing max-call-depth mechanism. Now produces a controlled
"stack overflow; max-call-depth exceeded" error with a proper stack
trace.
2025-11-22 20:32:05 +01:00
322 changed files with 6989 additions and 3491 deletions

View File

@@ -26,7 +26,7 @@ jobs:
# required to find all branches
fetch-depth: 0
- name: Create backport PRs
uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1
uses: korthout/backport-action@c656f5d5851037b2b38fb5db2691a03fa229e3b2 # v4.0.1
id: backport
with:
# Config README: https://github.com/korthout/backport-action#backport-action

View File

@@ -125,13 +125,13 @@ jobs:
cat coverage-reports/index.txt >> $GITHUB_STEP_SUMMARY
if: ${{ matrix.instrumented }}
- name: Upload coverage reports
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: coverage-reports
path: coverage-reports/
if: ${{ matrix.instrumented }}
- name: Upload installer tarball
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: installer-${{matrix.os}}
path: out/*
@@ -164,7 +164,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Download installer tarball
uses: actions/download-artifact@v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: installer-${{matrix.os}}
path: out
@@ -174,7 +174,7 @@ jobs:
echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
TARBALL_PATH="$(find "$GITHUB_WORKSPACE/out" -name 'nix*.tar.xz' -print | head -n 1)"
echo "tarball-path=file://$TARBALL_PATH" >> "$GITHUB_OUTPUT"
- uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4
- uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0
if: ${{ !matrix.experimental-installer }}
with:
install_url: ${{ format('{0}/install', steps.installer-tarball-url.outputs.installer-url) }}
@@ -197,80 +197,6 @@ 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, check_secrets]
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@v6
with:
fetch-depth: 0
- 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
- 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
flake_regressions:
needs: tests
runs-on: ubuntu-24.04
@@ -287,13 +213,21 @@ jobs:
with:
repository: NixOS/flake-regressions-data
path: flake-regressions/tests
- uses: ./.github/actions/install-nix-action
- name: Download installer tarball
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
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: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh
name: installer-linux
path: out
- name: Looking up the installer tarball URL
id: installer-tarball-url
run: |
echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
- uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0
with:
install_url: ${{ format('{0}/install', steps.installer-tarball-url.outputs.installer-url) }}
install_options: ${{ format('--tarball-url-prefix {0}', steps.installer-tarball-url.outputs.installer-url) }}
- name: Run flake regressions tests
run: MAX_FLAKES=25 flake-regressions/eval-all.sh
profile_build:
needs: tests

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

@@ -0,0 +1,69 @@
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: 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

@@ -1 +1 @@
2.33.0
2.34.0

View File

@@ -26,7 +26,6 @@ bash = find_program('bash', native : true)
# HTML manual dependencies (conditional)
if get_option('html-manual')
mdbook = find_program('mdbook', native : true)
rsync = find_program('rsync', required : true, native : true)
endif
pymod = import('python')
@@ -126,7 +125,12 @@ if get_option('html-manual')
@0@ @INPUT0@ @CURRENT_SOURCE_DIR@ > @DEPFILE@
@0@ @INPUT1@ summary @2@ < @CURRENT_SOURCE_DIR@/source/SUMMARY.md.in > @2@/source/SUMMARY.md
sed -e 's|@version@|@3@|g' < @INPUT2@ > @2@/book.toml
@4@ -r -L --exclude='*.drv' --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/
# Copy source to build directory, excluding the build directory itself
# (which is present when built as an individual component).
# Use tar with --dereference to copy symlink targets (e.g., JSON examples from tests).
(cd @CURRENT_SOURCE_DIR@ && find . -mindepth 1 -maxdepth 1 ! -name build | tar -c --dereference -T - -f -) | (cd @2@ && tar -xf -)
chmod -R u+w @2@
find @2@ -name '*.drv' -delete
(cd @2@; RUST_LOG=warn @1@ build -d @2@ 3>&2 2>&1 1>&3) | { grep -Fv "because fragment resolution isn't implemented" || :; } 3>&2 2>&1 1>&3
rm -rf @2@/manual
mv @2@/html @2@/manual
@@ -138,7 +142,6 @@ if get_option('html-manual')
mdbook.full_path(),
meson.current_build_dir(),
meson.project_version(),
rsync.full_path(),
),
],
input : [

View File

@@ -10,7 +10,6 @@
mdbook,
jq,
python3,
rsync,
nix-cli,
changelog-d,
json-schema-for-humans,
@@ -54,6 +53,8 @@ mkMesonDerivation (finalAttrs: {
../../src/libstore-tests/data/nar-info
../../src/libstore-tests/data/build-result
../../src/libstore-tests/data/dummy-store
# For derivation examples referenced by symlinks in doc/manual/source/protocols/json/schema/
../../tests/functional/derivation
# Too many different types of files to filter for now
../../doc/manual
./.
@@ -90,7 +91,6 @@ mkMesonDerivation (finalAttrs: {
]
++ lib.optionals buildHtmlManual [
mdbook
rsync
json-schema-for-humans
]
++ lib.optionals (!officialRelease && buildHtmlManual) [

View File

@@ -1,9 +0,0 @@
---
synopsis: Channel URLs migrated to channels.nixos.org subdomain
prs: [14518]
issues: [14517]
---
Channel URLs have been updated from `https://nixos.org/channels/` to `https://channels.nixos.org/` throughout Nix.
The subdomain provides better reliability with IPv6 support and improved CDN distribution. The old domain apex (`nixos.org/channels/`) currently redirects to the new location but may be deprecated in the future.

View File

@@ -1,88 +0,0 @@
---
synopsis: "JSON format changes for store path info and derivations"
prs: []
issues: []
---
JSON formats for store path info and derivations have been updated with new versions and structured fields.
## Store Path Info JSON
`nix path-info --json` now requires a `--json-format` flag to specify the output format version.
Using `--json` without `--json-format` is deprecated and will become an error in a future release.
For now, it defaults to version 1 with a warning, for a smoother migration.
### Version 1 (`--json-format 1`)
This is the legacy format, preserved for backwards compatibility:
- String-based hash values (e.g., `"narHash": "sha256:FePFYIlM..."`)
- String-based content addresses (e.g., `"ca": "fixed:r:sha256:1abc..."`)
- Full store paths for map keys and references (e.g., `"/nix/store/abc...-foo"`)
- Now includes `"storeDir"` field at the top level
### Version 2 (`--json-format 2`)
The new structured format follows the [JSON guidelines](@docroot@/development/json-guideline.md) with the following changes:
- **Nested structure with top-level metadata**:
The output is now wrapped in an object with `version`, `storeDir`, and `info` fields:
```json
{
"version": 2,
"storeDir": "/nix/store",
"info": { ... }
}
```
The map from store bath base names to store object info is nested under the `info` field.
- **Store path base names instead of full paths**:
Map keys and references use store path base names (e.g., `"abc...-foo"`) instead of full absolute store paths.
Combined with `storeDir`, the full path can be reconstructed.
- **Structured `ca` field**:
Content address is now a structured JSON object instead of a string:
- Old: `"ca": "fixed:r:sha256:1abc..."`
- New: `"ca": {"method": "nar", "hash": "sha256-ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="}`
- Still `null` values for input-addressed store objects
The `hash` field uses the [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) format like other hashes.
Nix currently only produces, and doesn't consume this format.
Additionally the following field is added to both formats.
(The `version` tracks breaking changes, and adding fields to outputted JSON is not a breaking change.)
- **`version` field**:
All store path info JSON now includes `"version": <1|2>`.
- **`storeDir` field**:
Top-level `"storeDir"` field contains the store directory path (e.g., `"/nix/store"`).
## Derivation JSON (Version 4)
The derivation JSON format has been updated from version 3 to version 4:
- **Restructured inputs**:
Inputs are now nested under an `inputs` object:
- Old: `"inputSrcs": [...], "inputDrvs": {...}`
- New: `"inputs": {"srcs": [...], "drvs": {...}}`
- **Consistent content addresses**:
Fixed content-addressed outputs now use structured JSON format.
This is the same format as `ca` in store path info (after the new version).
Version 3 and earlier formats are *not* accepted when reading.
**Affected command**: `nix derivation`, namely its `show` and `add` sub-commands.

View File

@@ -1,12 +0,0 @@
---
synopsis: Fix "download buffer is full; consider increasing the 'download-buffer-size' setting" warning
prs: [14614]
issues: [11728]
---
The underlying issue that led to [#11728](https://github.com/NixOS/nix/issues/11728) has been resolved by utilizing
[libcurl write pausing functionality](https://curl.se/libcurl/c/curl_easy_pause.html) to control backpressure when unpacking to slow destinations like the git-backed tarball cache. The default value of `download-buffer-size` is now 1 MiB and it's no longer recommended to increase it, since the root cause has been fixed.
This is expected to improve download performance on fast connections, since previously a single slow download consumer would stall the thread and prevent any other transfers from progressing.
Many thanks go out to the [Lix project](https://lix.systems/) for the [implementation](https://git.lix.systems/lix-project/lix/commit/4ae6fb5a8f0d456b8d2ba2aaca3712b4e49057fc) that served as inspiration for this change and for triaging libcurl [issues with pausing](https://github.com/curl/curl/issues/19334).

View File

@@ -1,8 +0,0 @@
---
synopsis: Interrupting REPL commands works more than once
issues: [13481]
---
Previously, this only worked once per REPL session; further attempts would be ignored.
This issue is now fixed, so REPL commands such as `:b` or `:p` can be canceled consistently.
This is a cherry-pick of the change from the [Lix project](https://gerrit.lix.systems/c/lix/+/1097).

View File

@@ -1,40 +0,0 @@
---
synopsis: "Improved S3 binary cache support via HTTP"
prs: [13752, 13823, 14026, 14120, 14131, 14135, 14144, 14170, 14190, 14198, 14206, 14209, 14222, 14223, 14330, 14333, 14335, 14336, 14337, 14350, 14356, 14357, 14374, 14375, 14376, 14377, 14391, 14393, 14420, 14421]
issues: [13084, 12671, 11748, 12403]
---
S3 binary cache operations now happen via HTTP, leveraging `libcurl`'s native
AWS SigV4 authentication instead of the AWS C++ SDK, providing significant
improvements:
- **Reduced memory usage**: Eliminates memory buffering issues that caused
segfaults with large files
- **Fixed upload reliability**: Resolves AWS SDK chunking errors
(`InvalidChunkSizeError`)
- **Lighter dependencies**: Uses lightweight `aws-crt-cpp` instead of full
`aws-cpp-sdk`, reducing build complexity
The new implementation requires curl >= 7.75.0 and `aws-crt-cpp` for credential
management.
All existing S3 URL formats and parameters remain supported, however the store
settings for configuring multipart uploads have changed:
- **`multipart-upload`** (default: `false`): Enable multipart uploads for large
files. When enabled, files exceeding the multipart threshold will be uploaded
in multiple parts.
- **`multipart-threshold`** (default: `100 MiB`): Minimum file size for using
multipart uploads. Files smaller than this will use regular PUT requests.
Only takes effect when `multipart-upload` is enabled.
- **`multipart-chunk-size`** (default: `5 MiB`): Size of each part in multipart
uploads. Must be at least 5 MiB (AWS S3 requirement). Larger chunk sizes
reduce the number of requests but use more memory.
- **`buffer-size`**: Has been replaced by `multipart-chunk-size` and is now an alias to it.
Note that this change also means Nix now supports S3 binary cache stores even
if built without `aws-crt-cpp`, but only for public buckets which do not
require authentication.

View File

@@ -1,14 +0,0 @@
---
synopsis: "S3 URLs now support object versioning via versionId parameter"
prs: [14274]
issues: [13955]
---
S3 URLs now support a `versionId` query parameter to fetch specific versions
of objects from S3 buckets with versioning enabled. This allows pinning to
exact object versions for reproducibility and protection against unexpected
changes:
```
s3://bucket/key?region=us-east-1&versionId=abc123def456
```

View File

@@ -1,21 +0,0 @@
---
synopsis: "S3 binary cache stores now support storage class configuration"
prs: [14464]
issues: [7015]
---
S3 binary cache stores now support configuring the storage class for uploaded objects via the `storage-class` parameter. This allows users to optimize costs by selecting appropriate storage tiers based on access patterns.
Example usage:
```bash
# Use Glacier storage for long-term archival
nix copy --to 's3://my-bucket?storage-class=GLACIER' /nix/store/...
# Use Intelligent Tiering for automatic cost optimization
nix copy --to 's3://my-bucket?storage-class=INTELLIGENT_TIERING' /nix/store/...
```
The storage class applies to both regular uploads and multipart uploads. When not specified, objects use the bucket's default storage class.
See the [S3 storage classes documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html) for available storage classes and their characteristics.

View File

@@ -151,6 +151,7 @@
- [Contributing](development/contributing.md)
- [Releases](release-notes/index.md)
{{#include ./SUMMARY-rl-next.md}}
- [Release 2.33 (2025-12-09)](release-notes/rl-2.33.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)

View File

@@ -27,7 +27,7 @@ site](https://en.wikipedia.org/wiki/Call_site) position and the name of the
function being called (when available). For example:
```
/nix/store/x9wnkly3k1gkq580m90jjn32q9f05q2v-source/pkgs/top-level/default.nix:167:5:primop import
/nix/store/2q71fdvr4h33g9832hiriwnf20fn630l-source/pkgs/top-level/default.nix:167:5:primop import
```
Here `import` primop is called at `/nix/store/x9wnkly3k1gkq580m90jjn32q9f05q2v-source/pkgs/top-level/default.nix:167:5`.
Here `import` primop is called at `/nix/store/2q71fdvr4h33g9832hiriwnf20fn630l-source/pkgs/top-level/default.nix:167:5`.

View File

@@ -39,11 +39,11 @@ This makes all subscribed channels available as attributes in the default expres
A symlink that ensures that [`nix-env`] can find the current user's [channels]:
- `~/.nix-defexpr/channels`
- `$XDG_STATE_HOME/defexpr/channels` if [`use-xdg-base-directories`] is set to `true`.
- `$XDG_STATE_HOME/nix/defexpr/channels` if [`use-xdg-base-directories`] is set to `true`.
This symlink points to:
- `$XDG_STATE_HOME/profiles/channels` for regular users
- `$XDG_STATE_HOME/nix/profiles/channels` for regular users
- `$NIX_STATE_DIR/profiles/per-user/root/channels` for `root`
In a multi-user installation, you may also have `~/.nix-defexpr/channels_root`, which links to the channels of the root user.

View File

@@ -114,9 +114,9 @@ Here is an example of how this file might look like after installing `hello` fro
};
name = "hello-2.12.1";
out = {
outPath = "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1";
outPath = "/nix/store/src1vzij2z0slnakrsbpqpk20389z0k6-hello-2.12.1";
};
outPath = "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1";
outPath = "/nix/store/src1vzij2z0slnakrsbpqpk20389z0k6-hello-2.12.1";
outputs = [ "out" ];
system = "x86_64-linux";
type = "derivation";

View File

@@ -37,13 +37,13 @@ dr-xr-xr-x 4 root root 4096 Jan 1 1970 share
/home/eelco/.local/state/nix/profiles/profile-7-link/bin:
total 20
lrwxrwxrwx 5 root root 79 Jan 1 1970 chromium -> /nix/store/ijm5k0zqisvkdwjkc77mb9qzb35xfi4m-chromium-86.0.4240.111/bin/chromium
lrwxrwxrwx 5 root root 79 Jan 1 1970 chromium -> /nix/store/cyxny9d1zjb9l9103fr6j6kavp3bqjxf-chromium-86.0.4240.111/bin/chromium
lrwxrwxrwx 7 root root 87 Jan 1 1970 spotify -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/bin/spotify
lrwxrwxrwx 3 root root 79 Jan 1 1970 zoom-us -> /nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927/bin/zoom-us
/home/eelco/.local/state/nix/profiles/profile-7-link/share/applications:
total 12
lrwxrwxrwx 4 root root 120 Jan 1 1970 chromium-browser.desktop -> /nix/store/4cf803y4vzfm3gyk3vzhzb2327v0kl8a-chromium-unwrapped-86.0.4240.111/share/applications/chromium-browser.desktop
lrwxrwxrwx 4 root root 120 Jan 1 1970 chromium-browser.desktop -> /nix/store/sqzyx2l85i6j2a77pnyvglh3bvzwmjjp-chromium-unwrapped-86.0.4240.111/share/applications/chromium-browser.desktop
lrwxrwxrwx 7 root root 110 Jan 1 1970 spotify.desktop -> /nix/store/w9182874m1bl56smps3m5zjj36jhp3rn-spotify-1.1.26.501.gbe11e53b-15/share/applications/spotify.desktop
lrwxrwxrwx 3 root root 107 Jan 1 1970 us.zoom.Zoom.desktop -> /nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927/share/applications/us.zoom.Zoom.desktop

View File

@@ -72,11 +72,11 @@ When using public key authentication, you can avoid typing the passphrase with `
> $ storePath="$(nix-build '<nixpkgs>' -I nixpkgs=channel:nixpkgs-unstable -A hello --no-out-link)"
> $ nix-copy-closure --to alice@itchy.example.org "$storePath"
> copying 5 paths...
> copying path '/nix/store/nrwkk6ak3rgkrxbqhsscb01jpzmslf2r-xgcc-13.2.0-libgcc' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/gm61h1y42pqyl6178g90x8zm22n6pyy5-libunistring-1.1' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/ddfzjdykw67s20c35i7a6624by3iz5jv-libidn2-2.3.7' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/apab5i73dqa09wx0q27b6fbhd1r18ihl-glibc-2.39-31' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/g1n2vryg06amvcc1avb2mcq36faly0mh-hello-2.12.1' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/h6q8sqsqfbd3252f9gixqn3z282wds7m-xgcc-13.2.0-libgcc' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/imnwvn96lw355giswsk36hx105j4wnpj-libunistring-1.1' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/85301indj7scg34spnfczkz72jgv8wa9-libidn2-2.3.7' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/ypwfsaljwhzw9iffiysxmxnhjj8v7np0-glibc-2.39-31' to 'ssh://alice@itchy.example.org'...
> copying path '/nix/store/0dklv59zppdsqdvgf0qdvjgzcs5wbwxa-hello-2.12.1' to 'ssh://alice@itchy.example.org'...
> ```
> **Example**

View File

@@ -204,7 +204,7 @@ To install a specific [store derivation] (typically created by
`nix-instantiate`):
```console
$ nix-env --install /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
$ nix-env --install /nix/store/8la6y31fmm6i4wfmby6avly1wf718xnj-gcc-3.4.3.drv
```
To install a specific output path:
@@ -232,7 +232,7 @@ $ nix-env --file '<nixpkgs>' --install --attr hello --dry-run
(dry run; not doing anything)
installing hello-2.10
this path will be fetched (0.04 MiB download, 0.19 MiB unpacked):
/nix/store/wkhdf9jinag5750mqlax6z2zbwhqb76n-hello-2.10
/nix/store/ikwkxz4wwlp2g1428n7dy729cg1d9hin-hello-2.10
...
```

View File

@@ -76,7 +76,7 @@ $ nix-prefetch-url ftp://ftp.gnu.org/pub/gnu/hello/hello-2.10.tar.gz
```console
$ nix-prefetch-url --print-path mirror://gnu/hello/hello-2.10.tar.gz
0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i
/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz
/nix/store/8alrpdaasjd1x6g1fczchmzbpqm936a3-hello-2.10.tar.gz
```
```console

View File

@@ -34,6 +34,6 @@ This operation has the following options:
```console
$ nix-store --add-fixed sha256 ./hello-2.10.tar.gz
/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz
/nix/store/8alrpdaasjd1x6g1fczchmzbpqm936a3-hello-2.10.tar.gz
```

View File

@@ -27,7 +27,7 @@ paths in the store that refer to it (i.e., depend on it).
# Example
```console
$ nix-store --delete /nix/store/zq0h41l75vlb4z45kzgjjmsjxvcv1qk7-mesa-6.4
$ nix-store --delete /nix/store/gjak3al7lj61x4gj6rln4f5pc5v0f67n-mesa-6.4
0 bytes freed (0.00 MiB)
error: cannot delete path `/nix/store/zq0h41l75vlb4z45kzgjjmsjxvcv1qk7-mesa-6.4' since it is still alive
error: cannot delete path `/nix/store/gjak3al7lj61x4gj6rln4f5pc5v0f67n-mesa-6.4' since it is still alive
```

View File

@@ -184,9 +184,9 @@ Print the build-time dependencies of `svn`:
```console
$ nix-store --query --requisites $(nix-store --query --deriver $(which svn))
/nix/store/02iizgn86m42q905rddvg4ja975bk2i4-grep-2.5.1.tar.bz2.drv
/nix/store/07a2bzxmzwz5hp58nf03pahrv2ygwgs3-gcc-wrapper.sh
/nix/store/0ma7c9wsbaxahwwl04gbw3fcd806ski4-glibc-2.3.4.drv
/nix/store/y6qa66l9h0pw161crnlk6y16rdrcljx4-grep-2.5.1.tar.bz2.drv
/nix/store/z716h753s97jhnzvfank2srqbljswpgm-gcc-wrapper.sh
/nix/store/f39x0q73rjdyvzm93y9wrkfr6x39lb7f-glibc-2.3.4.drv
... lots of other paths ...
```
@@ -199,10 +199,10 @@ Show the build-time dependencies as a tree:
```console
$ nix-store --query --tree $(nix-store --query --deriver $(which svn))
/nix/store/7i5082kfb6yjbqdbiwdhhza0am2xvh6c-subversion-1.1.4.drv
+---/nix/store/d8afh10z72n8l1cr5w42366abiblgn54-builder.sh
+---/nix/store/fmzxmpjx2lh849ph0l36snfj9zdibw67-bash-3.0.drv
| +---/nix/store/570hmhmx3v57605cqg9yfvvyh0nnb8k8-bash
| +---/nix/store/p3srsbd8dx44v2pg6nbnszab5mcwx03v-builder.sh
+---/nix/store/vxnmkc8l8d2ijjha4xwhkfgx9vvc3q4c-builder.sh
+---/nix/store/rn9776dy82n5qrgz7xbcl1iw4vfkcrkk-bash-3.0.drv
| +---/nix/store/x9j20hz6bln1crzn55qifk0bbsm8v5ac-bash
| +---/nix/store/ajnn1mcm45wjvn0rlc22gvx2cwhjnazx-builder.sh
...
```

View File

@@ -76,7 +76,7 @@ This operation is typically used to build [store derivation]s produced by
```console
$ nix-store --realise $(nix-instantiate ./test.nix)
/nix/store/31axcgrlbfsxzmfff1gyj1bf62hvkby2-aterm-2.3.1
/nix/store/6gwmy5jcnwdlz6aqqhksz863f1l8xc2w-aterm-2.3.1
```
This is essentially what [`nix-build`](@docroot@/command-ref/nix-build.md) does.

View File

@@ -3,6 +3,10 @@
This section provides some notes on how to start hacking on Nix.
To get the latest version of Nix from GitHub:
> **Note**
>
> When checking out the repo on Windows, make sure you have the git setting `core.symlinks` enabled, before cloning, as there are symlinks in the repo.
```console
$ git clone https://github.com/NixOS/nix.git
$ cd nix

View File

@@ -6,14 +6,7 @@ Additionally, see [Testing Nix](./testing.md) for further instructions on how to
## Building Nix with Debug Symbols
In the development shell, set the `mesonBuildType` environment variable to `debug` before configuring the build:
```console
[nix-shell]$ export mesonBuildType=debugoptimized
```
Then, proceed to build Nix as described in [Building Nix](./building.md).
This will build Nix with debug symbols, which are essential for effective debugging.
In the development shell, `mesonBuildType` is set automatically to `debugoptimized`. This builds Nix with debug symbols, which are essential for effective debugging.
It is also possible to build without optimization for faster build:

View File

@@ -136,7 +136,7 @@
> **Example**
>
> `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
> `/nix/store/jf6gn2dzna4nmsfbdxsd7kwhsk6gnnlr-git-2.38.1`
See [Store Path](@docroot@/store/store-path.md) for details.

View File

@@ -8,7 +8,7 @@ stores packages in the _Nix store_, usually the directory
`/nix/store`, where each package has its own unique subdirectory such
as
/nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1/
/nix/store/q06x3jll2yfzckz2bzqak089p43ixkkq-firefox-33.1/
where `b6gvzjyb2pg0…` is a unique identifier for the package that
captures all its dependencies (its a cryptographic hash of the

View File

@@ -34,12 +34,12 @@ String context elements come in different forms:
> [`builtins.storePath`] creates a string with a single constant string context element:
>
> ```nix
> builtins.getContext (builtins.storePath "/nix/store/wkhdf9jinag5750mqlax6z2zbwhqb76n-hello-2.10")
> builtins.getContext (builtins.storePath "/nix/store/ikwkxz4wwlp2g1428n7dy729cg1d9hin-hello-2.10")
> ```
> evaluates to
> ```nix
> {
> "/nix/store/wkhdf9jinag5750mqlax6z2zbwhqb76n-hello-2.10" = {
> "/nix/store/ikwkxz4wwlp2g1428n7dy729cg1d9hin-hello-2.10" = {
> path = true;
> };
> }

View File

@@ -181,7 +181,7 @@ A derivation interpolates to the [store path] of its first [output](./derivation
> "${pkgs.hello}"
> ```
>
> "/nix/store/4xpfqf29z4m8vbhrqcz064wfmb46w5r7-hello-2.12.1"
> "/nix/store/qnlr7906z0mrl2syrkdbpicffq02nw07-hello-2.12.1"
An attribute set interpolates to the return value of the function in the `__toString` applied to the attribute set itself.

View File

@@ -51,6 +51,7 @@ See [String literals](string-literals.md).
Path literals can also include [string interpolation], besides being [interpolated into other expressions].
[string interpolation]: ./string-interpolation.md
[interpolated into other expressions]: ./string-interpolation.md#interpolated-expression
At least one slash (`/`) must appear *before* any interpolated expression for the result to be recognized as a path.
@@ -272,7 +273,7 @@ will crash with an `infinite recursion encountered` error message.
A let-expression allows you to define local variables for an expression.
> *let-in* = `let` [ *identifier* = *expr* ]... `in` *expr*
> *let-in* = `let` [ *identifier* = *expr* `;` ]... `in` *expr*
Example:
@@ -285,6 +286,27 @@ in x + y
This evaluates to `"foobar"`.
There is also another, older, syntax for let expressions that should not be used in new code:
> *let* = `let` `{` *identifier* = *expr* `;` [ *identifier* = *expr* `;`]... `}`
In this form, the attribute set between the `{` `}` is recursive.
One of the attributes must have the special name `body`,
which is the result of the expression.
Example:
```nix
let {
foo = bar;
bar = "baz";
body = foo;
}
```
This evaluates to "baz".
## Inheriting attributes
When defining an [attribute set](./types.md#type-attrs) or in a [let-expression](#let-expressions) it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes).

View File

@@ -1,27 +1,21 @@
{{#include build-trace-entry-v1-fixed.md}}
{{#include build-trace-entry-v2-fixed.md}}
## Examples
### Simple build trace entry
```json
{{#include schema/build-trace-entry-v1/simple.json}}
```
### Build trace entry with dependencies
```json
{{#include schema/build-trace-entry-v1/with-dependent-realisations.json}}
{{#include schema/build-trace-entry-v2/simple.json}}
```
### Build trace entry with signature
```json
{{#include schema/build-trace-entry-v1/with-signature.json}}
{{#include schema/build-trace-entry-v2/with-signature.json}}
```
<!--
## Raw Schema
[JSON Schema for Build Trace Entry v1](schema/build-trace-entry-v1.json)
-->
[JSON Schema for Build Trace Entry v1](schema/build-trace-entry-v2.json)
-->

View File

@@ -17,7 +17,7 @@ schemas = [
'derivation-v4',
'derivation-options-v1',
'deriving-path-v1',
'build-trace-entry-v1',
'build-trace-entry-v2',
'build-result-v1',
'store-v1',
]

View File

@@ -83,7 +83,7 @@ properties:
description: |
A mapping from output names to their build trace entries.
additionalProperties:
"$ref": "build-trace-entry-v1.yaml"
"$ref": "build-trace-entry-v2.yaml"
failure:
type: object

View File

@@ -1,5 +1,5 @@
"$schema": "http://json-schema.org/draft-04/schema"
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/build-trace-entry-v1.json"
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/build-trace-entry-v2.json"
title: Build Trace Entry
description: |
A record of a successful build outcome for a specific derivation output.
@@ -11,10 +11,17 @@ description: |
> This JSON format is currently
> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-ca-derivations)
> and subject to change.
Verision history:
- Version 1: Original format
- Version 2: Remove `dependentRealisations`
type: object
required:
- id
- outPath
- dependentRealisations
- signatures
allOf:
- "$ref": "#/$defs/key"
@@ -22,9 +29,11 @@ allOf:
properties:
id: {}
outPath: {}
dependentRealisations: {}
signatures: {}
additionalProperties: false
additionalProperties:
dependentRealisations:
description: deprecated field
type: object
"$defs":
key:
@@ -60,7 +69,6 @@ additionalProperties: false
type: object
required:
- outPath
- dependentRealisations
- signatures
properties:
outPath:
@@ -69,19 +77,6 @@ additionalProperties: false
description: |
The path to the store object that resulted from building this derivation for the given output name.
dependentRealisations:
type: object
title: Underlying Base Build Trace
description: |
This is for [*derived*](@docroot@/store/build-trace.md#derived) build trace entries to ensure coherence.
Keys are derivation output IDs (same format as the main `id` field).
Values are the store paths that those dependencies resolved to.
As described in the linked section on derived build trace traces, derived build trace entries must be kept in addition and not instead of the underlying base build entries.
This is the set of base build trace entries that this derived build trace is derived from.
(The set is also a map since this miniature base build trace must be coherent, mapping each key to a single value.)
patternProperties:
"^sha256:[0-9a-f]{64}![a-zA-Z_][a-zA-Z0-9_-]*$":
"$ref": "store-path-v1.yaml"

View File

@@ -94,8 +94,8 @@ properties:
>
> ```json
> "srcs": [
> "47y241wqdhac3jm5l7nv0x4975mb1975-separate-debug-info.sh",
> "56d0w71pjj9bdr363ym3wj1zkwyqq97j-fix-pop-var-context-error.patch"
> "b8nwz167km1yciqpwzjj24f8jcy8pq1h-separate-debug-info.sh",
> "ihzmilr413r8fb3ah30yjnhlb18c1laz-fix-pop-var-context-error.patch"
> ]
> ```
items:
@@ -140,7 +140,7 @@ properties:
description: |
Absolute path of the program used to perform the build.
Typically this is the `bash` shell
(e.g. `/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash`).
(e.g. `/nix/store/p4xlj4imjbnm4v0x5jf4qysvyjjlgq1d-bash-4.4-p23/bin/bash`).
args:
type: array

View File

@@ -70,7 +70,7 @@ properties:
"^[A-Za-z0-9+/]{43}=$":
type: object
additionalProperties:
"$ref": "./build-trace-entry-v1.yaml#/$defs/value"
"$ref": "./build-trace-entry-v2.yaml#/$defs/value"
additionalProperties: false
"$defs":

View File

@@ -80,7 +80,7 @@
...
the following paths will be downloaded/copied (30.02 MiB):
/nix/store/4m8pvgy2dcjgppf5b4cj5l6wyshjhalj-samba-3.2.4
/nix/store/7h1kwcj29ip8vk26rhmx6bfjraxp0g4l-libunwind-0.98.6
/nix/store/spc1m987vlibchdx369qwa391s738s7l-libunwind-0.98.6
...
- Language features:

View File

@@ -63,7 +63,7 @@ Nix 0.8 has the following improvements:
can query all paths that directly or indirectly use a certain Glibc:
$ nix-store -q --referrers-closure \
/nix/store/8lz9yc6zgmc0vlqmn2ipcpkjlmbi51vv-glibc-2.3.4
/nix/store/1a6mdrjz4wn7b9sfmcw5ggbk1mi281mh-glibc-2.3.4
- The concept of fixed-output derivations has been formalised.
Previously, functions such as `fetchurl` in Nixpkgs used a hack

View File

@@ -66,7 +66,7 @@ This release has the following new features:
nix copy --to ssh://machine nixpkgs.hello
nix copy --to ssh://machine /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
nix copy --to ssh://machine /nix/store/qbhyj3blxpw2i6pb7c6grc9185nbnpvy-hello-2.10
nix copy --to ssh://machine '(with import <nixpkgs> {}; hello)'
@@ -187,7 +187,7 @@ This release has the following new features:
former is primarily useful in conjunction with remote stores,
e.g.
nix ls-store --store https://cache.nixos.org/ -lR /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
nix ls-store --store https://cache.nixos.org/ -lR /nix/store/qbhyj3blxpw2i6pb7c6grc9185nbnpvy-hello-2.10
lists the contents of path in a binary cache.

View File

@@ -25,7 +25,7 @@
* Allow explicitly selecting outputs in a store derivation installable, just like we can do with other sorts of installables.
For example,
```shell-session
# nix build /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev
# nix build /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv^dev
```
now works just as
```shell-session

View File

@@ -18,13 +18,13 @@
For example,
```shell-session
$ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv
$ nix path-info /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv
```
now gives info about the derivation itself, while
```shell-session
$ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*
$ nix path-info /nix/store/fpq78s2h8ffh66v2iy0q1838mhff06y8-glibc-2.33-78.drv^*
```
provides information about each of its outputs.

View File

@@ -45,7 +45,7 @@
```json5
[
{
"path": "/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15",
"path": "/nix/store/fvqsvk65d38p8qqir371ii0hyqxvjcw6-bash-5.2-p15",
"valid": true,
// ...
},
@@ -60,7 +60,7 @@
```json5
{
"/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15": {
"/nix/store/fvqsvk65d38p8qqir371ii0hyqxvjcw6-bash-5.2-p15": {
// ...
},
"/nix/store/wffw7l0alvs3iw94cbgi1gmmbmw99sqb-home-manager-path": null,

View File

@@ -182,7 +182,7 @@
«partially applied primop map»
nix-repl> builtins.trace lib.id "my-value"
trace: «lambda id @ /nix/store/8rrzq23h2zq7sv5l2vhw44kls5w0f654-source/lib/trivial.nix:26:5»
trace: «lambda id @ /nix/store/kgr5lnaiiv08wb7k324yv1i1npjmrvjc-source/lib/trivial.nix:26:5»
"my-value"
```

View File

@@ -0,0 +1,281 @@
# Release 2.33.0 (2025-12-09)
## New features
- New command `nix registry resolve` [#14595](https://github.com/NixOS/nix/pull/14595)
This command looks up a flake registry input name and returns the flakeref it resolves to.
For example, looking up Nixpkgs:
```
$ nix registry resolve nixpkgs
github:NixOS/nixpkgs/nixpkgs-unstable
```
Upstreamed from [Determinate Nix 3.14.0](https://github.com/DeterminateSystems/nix-src/pull/273).
- `nix flake clone` supports all input types [#14581](https://github.com/NixOS/nix/pull/14581)
`nix flake clone` now supports arbitrary input types. In particular, this allows you to clone tarball flakes, such as flakes on FlakeHub.
Upstreamed from [Determinate Nix 3.12.0](https://github.com/DeterminateSystems/nix-src/pull/229).
## Performance improvements
- Git fetcher computes `revCount`s using multiple threads [#14462](https://github.com/NixOS/nix/pull/14462)
When using Git repositories with a long history, calculating the `revCount` attribute can take a long time. Nix now computes `revCount` using multiple threads, making it much faster (e.g. 9.1s to 3.7s for Nixpkgs).
Note that if you don't need `revCount`, you can disable it altogether by setting the flake input attribute `shallow = true`.
Upstreamed from [Determinate Nix 3.12.2](https://github.com/DeterminateSystems/nix-src/pull/245).
- `builtins.stringLength` now runs in constant time [#14442](https://github.com/NixOS/nix/pull/14442)
The internal representation of strings has been replaced with a size-prefixed Pascal style string. Previously Nix stored strings as a NUL-terminated array of bytes, necessitating a linear scan to calculate the length.
- Uploads to `http://` and `https://` binary cache stores now run in constant memory [#14390](https://github.com/NixOS/nix/pull/14390)
Nix used to buffer the whole compressed NAR contents in memory. It now reads it in a streaming fashion.
- Channel URLs migrated to channels.nixos.org subdomain [#14517](https://github.com/NixOS/nix/issues/14517) [#14518](https://github.com/NixOS/nix/pull/14518)
Channel URLs have been updated from `https://nixos.org/channels/` to `https://channels.nixos.org/` throughout Nix. This subdomain provides better reliability with IPv6 support and improved CDN distribution. The old domain apex (`nixos.org/channels/`) currently redirects to the new location but may be deprecated in the future.
- Fix `download buffer is full; consider increasing the 'download-buffer-size' setting` warning [#11728](https://github.com/NixOS/nix/issues/11728) [#14614](https://github.com/NixOS/nix/pull/14614)
The underlying issue that led to [#11728](https://github.com/NixOS/nix/issues/11728) has been resolved by utilizing
[libcurl write pausing functionality](https://curl.se/libcurl/c/curl_easy_pause.html) to control backpressure when unpacking to slow destinations like the git-backed tarball cache. The default value of `download-buffer-size` is now 1 MiB and it's no longer recommended to increase it, since the root cause has been fixed.
This is expected to improve download performance on fast connections, since previously a single slow download consumer would stall the thread and prevent any other transfers from progressing.
Many thanks go out to the [Lix project](https://lix.systems/) for the [implementation](https://git.lix.systems/lix-project/lix/commit/4ae6fb5a8f0d456b8d2ba2aaca3712b4e49057fc) that served as inspiration for this change and for triaging libcurl [issues with pausing](https://github.com/curl/curl/issues/19334).
- Significantly improve tarball unpacking performance [#14689](https://github.com/NixOS/nix/pull/14689) [#14696](https://github.com/NixOS/nix/pull/14696) [#10683](https://github.com/NixOS/nix/issues/10683) [#11098](https://github.com/NixOS/nix/issues/11098)
Nix uses a content-addressed cache backed by libgit2 for deduplicating files fetched via `fetchTarball` and `github`, `tarball` flake inputs. Its usage has been significantly optimised to reduce the amount of I/O operations that are performed. For a typical nixpkgs source tarball this results in 200 times fewer system calls on Linux. In combination with libcurl pausing this alleviates performance regressions stemming from the tarball cache.
- Already valid derivations are no longer copied to the store [#14219](https://github.com/NixOS/nix/pull/14219)
This results in a modest speedup when using the Nix daemon.
- `nix nar ls` and `nix nar cat` are significantly faster and no longer buffer the whole NAR in memory [#14273](https://github.com/NixOS/nix/pull/14273) [#14732](https://github.com/NixOS/nix/pull/14732)
## S3 improvements
- Improved S3 binary cache support via HTTP [#11748](https://github.com/NixOS/nix/issues/11748) [#12403](https://github.com/NixOS/nix/issues/12403) [#12671](https://github.com/NixOS/nix/issues/12671) [#13084](https://github.com/NixOS/nix/issues/13084) [#13752](https://github.com/NixOS/nix/pull/13752) [#13823](https://github.com/NixOS/nix/pull/13823) [#14026](https://github.com/NixOS/nix/pull/14026) [#14120](https://github.com/NixOS/nix/pull/14120) [#14131](https://github.com/NixOS/nix/pull/14131) [#14135](https://github.com/NixOS/nix/pull/14135) [#14144](https://github.com/NixOS/nix/pull/14144) [#14170](https://github.com/NixOS/nix/pull/14170) [#14190](https://github.com/NixOS/nix/pull/14190) [#14198](https://github.com/NixOS/nix/pull/14198) [#14206](https://github.com/NixOS/nix/pull/14206) [#14209](https://github.com/NixOS/nix/pull/14209) [#14222](https://github.com/NixOS/nix/pull/14222) [#14223](https://github.com/NixOS/nix/pull/14223) [#14330](https://github.com/NixOS/nix/pull/14330) [#14333](https://github.com/NixOS/nix/pull/14333) [#14335](https://github.com/NixOS/nix/pull/14335) [#14336](https://github.com/NixOS/nix/pull/14336) [#14337](https://github.com/NixOS/nix/pull/14337) [#14350](https://github.com/NixOS/nix/pull/14350) [#14356](https://github.com/NixOS/nix/pull/14356) [#14357](https://github.com/NixOS/nix/pull/14357) [#14374](https://github.com/NixOS/nix/pull/14374) [#14375](https://github.com/NixOS/nix/pull/14375) [#14376](https://github.com/NixOS/nix/pull/14376) [#14377](https://github.com/NixOS/nix/pull/14377) [#14391](https://github.com/NixOS/nix/pull/14391) [#14393](https://github.com/NixOS/nix/pull/14393) [#14420](https://github.com/NixOS/nix/pull/14420) [#14421](https://github.com/NixOS/nix/pull/14421)
S3 binary cache operations now happen via HTTP, leveraging `libcurl`'s native AWS SigV4 authentication instead of the AWS C++ SDK, providing significant improvements:
- **Reduced memory usage**: Eliminates memory buffering issues that caused segfaults with large files
- **Fixed upload reliability**: Resolves AWS SDK chunking errors (`InvalidChunkSizeError`)
- **Lighter dependencies**: Uses lightweight `aws-crt-cpp` instead of full `aws-cpp-sdk`, reducing build complexity
The new implementation requires curl >= 7.75.0 and `aws-crt-cpp` for credential management.
All existing S3 URL formats and parameters remain supported, however the store settings for configuring multipart uploads have changed:
- **`multipart-upload`** (default: `false`): Enable multipart uploads for large files. When enabled, files exceeding the multipart threshold will be uploaded in multiple parts.
- **`multipart-threshold`** (default: `100 MiB`): Minimum file size for using multipart uploads. Files smaller than this will use regular PUT requests. Only takes effect when `multipart-upload` is enabled.
- **`multipart-chunk-size`** (default: `5 MiB`): Size of each part in multipart uploads. Must be at least 5 MiB (AWS S3 requirement). Larger chunk sizes reduce the number of requests but use more memory.
- **`buffer-size`**: Has been replaced by `multipart-chunk-size` and is now an alias to it.
Note that this change also means Nix now supports S3 binary cache stores even if built without `aws-crt-cpp`, but only for public buckets which do not require authentication.
- S3 URLs now support object versioning via `versionId` parameter [#13955](https://github.com/NixOS/nix/issues/13955) [#14274](https://github.com/NixOS/nix/pull/14274)
S3 URLs now support a `versionId` query parameter to fetch specific versions
of objects from S3 buckets with versioning enabled. This allows pinning to
exact object versions for reproducibility and protection against unexpected
changes:
```
s3://bucket/key?region=us-east-1&versionId=abc123def456
```
- S3 binary cache stores now support storage class configuration [#7015](https://github.com/NixOS/nix/issues/7015) [#14464](https://github.com/NixOS/nix/pull/14464)
S3 binary cache stores now support configuring the storage class for uploaded objects via the `storage-class` parameter. This allows users to optimize costs by selecting appropriate storage tiers based on access patterns.
Example usage:
```bash
# Use Glacier storage for long-term archival
nix copy --to 's3://my-bucket?storage-class=GLACIER' /nix/store/...
# Use Intelligent Tiering for automatic cost optimization
nix copy --to 's3://my-bucket?storage-class=INTELLIGENT_TIERING' /nix/store/...
```
The storage class applies to both regular uploads and multipart uploads. When not specified, objects use the bucket's default storage class.
See the [S3 storage classes documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html) for available storage classes and their characteristics.
## Store path info JSON format changes
The JSON format emitted by `nix path-info --json` has been updated to a new version with improved structure.
To maintain compatibility, `nix path-info --json` now requires a `--json-format` flag to specify the output format version.
Using `--json` without `--json-format` is deprecated and will become an error in a future release.
For now, it defaults to version 1 with a warning, for a smoother migration.
### Version 1 (`--json-format 1`)
This is the legacy format, preserved for backwards compatibility:
- String-based hash values (e.g., `"narHash": "sha256:FePFYIlM..."`)
- String-based content addresses (e.g., `"ca": "fixed:r:sha256:1abc..."`)
- Full store paths for map keys and references (e.g., `"/nix/store/abc...-foo"`)
- Now includes `"storeDir"` field at the top level
### Version 2 (`--json-format 2`)
The new structured format follows the [JSON guidelines](@docroot@/development/json-guideline.md) with the following changes:
- **Nested structure with top-level metadata**:
The output is now wrapped in an object with `version`, `storeDir`, and `info` fields:
```json
{
"version": 2,
"storeDir": "/nix/store",
"info": { ... }
}
```
The map from store path base names to store object info is nested under the `info` field.
- **Store path base names instead of full paths**:
Map keys and references use store path base names (e.g., `"abc...-foo"`) instead of full absolute store paths.
Combined with `storeDir`, the full path can be reconstructed.
- **Structured `ca` field**:
Content address is now a structured JSON object instead of a string:
- Old: `"ca": "fixed:r:sha256:1abc..."`
- New: `"ca": {"method": "nar", "hash": "sha256-ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="}`
- Still `null` values for input-addressed store objects
The `hash` field uses the [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) format like other hashes.
Additionally the following fields are added to both formats:
- **`version` field**:
All store path info JSON now includes `"version": <1|2>`. The `version` tracks breaking changes, and adding fields to outputted JSON is not a breaking change.
- **`storeDir` field**:
Top-level `"storeDir"` field contains the store directory path (e.g., `"/nix/store"`).
## Derivation JSON format changes
The derivation JSON format has been updated from version 3 to version 4:
- **Nested structure with top-level metadata**:
The output of `nix derivation show` is now wrapped in an object with `version` and `derivations` fields:
```json
{
"version": 4,
"derivations": { ... }
}
```
The map from derivation paths to derivation info is nested under the `derivations` field.
This matches the structure used for `nix path-info --json --json-format 2`, and likewise brings this command into compliance with the JSON guidelines.
- **Restructured inputs**:
Inputs are now nested under an `inputs` object:
- Old: `"inputSrcs": [...], "inputDrvs": {...}`
- New: `"inputs": {"srcs": [...], "drvs": {...}}`
- **Consistent content addresses**:
Fixed content-addressed outputs now use structured JSON format.
This is the same format as `ca` in store path info (after the new version).
Version 3 and earlier formats are *not* accepted when reading.
**Affected command**: `nix derivation`, namely its `show` and `add` sub-commands.
## Miscellaneous changes
- Git fetcher: Restore progress indication [#14487](https://github.com/NixOS/nix/pull/14487)
Nix used to feel "stuck" while it was cloning large repositories. Nix now shows Git's native progress indicator while fetching.
Upstreamed from [Determinate Nix 3.13.0](https://github.com/DeterminateSystems/nix-src/pull/250).
- Interrupting REPL commands works more than once [#13481](https://github.com/NixOS/nix/issues/13481)
Previously, this only worked once per REPL session; further attempts would be ignored.
This issue is now fixed, so REPL commands such as `:b` or `:p` can be canceled consistently.
This is a cherry-pick of the change from the [Lix project](https://gerrit.lix.systems/c/lix/+/1097).
- NAR unpacking code has been rewritten to make use of dirfd-based `openat` and `openat2` system calls when available [#14597](https://github.com/NixOS/nix/pull/14597)
- Dynamic size unit rendering [#14423](https://github.com/NixOS/nix/pull/14423) [#14364](https://github.com/NixOS/nix/pull/14364)
Various commands and the progress bar now use dynamically determined size units instead
of always using `MiB`. For example, the progress bar now reports download status like:
```
[1/196/197 copied (773.7 MiB/2.1 GiB), 172.4/421.5 MiB DL]
```
Instead of:
```
[1/196/197 copied (773.7/2147.3 MiB), 172.4/421.5 MiB DL]
```
## Contributors
This release was made possible by the following 33 contributors:
- Adam Dinwoodie [**(@me-and)**](https://github.com/me-and)
- jonhermansen [**(@jonhermansen)**](https://github.com/jonhermansen)
- Arnout Engelen [**(@raboof)**](https://github.com/raboof)
- Jean-François Roche [**(@jfroche)**](https://github.com/jfroche)
- tomberek [**(@tomberek)**](https://github.com/tomberek)
- Eelco Dolstra [**(@edolstra)**](https://github.com/edolstra)
- Marcel [**(@MarcelCoding)**](https://github.com/MarcelCoding)
- David McFarland [**(@corngood)**](https://github.com/corngood)
- Soumyadip Sarkar [**(@neuralsorcerer)**](https://github.com/neuralsorcerer)
- Cole Helbling [**(@cole-h)**](https://github.com/cole-h)
- John Ericson [**(@Ericson2314)**](https://github.com/Ericson2314)
- Tristan Ross [**(@RossComputerGuy)**](https://github.com/RossComputerGuy)
- Alex Auvolat [**(@Alexis211)**](https://github.com/Alexis211)
- edef [**(@edef1c)**](https://github.com/edef1c)
- Sergei Zimmerman [**(@xokdvium)**](https://github.com/xokdvium)
- Vinayak Goyal [**(@vinayakankugoyal)**](https://github.com/vinayakankugoyal)
- Graham Dennis [**(@GrahamDennis)**](https://github.com/GrahamDennis)
- Aspen Smith [**(@glittershark)**](https://github.com/glittershark)
- Jens Petersen [**(@juhp)**](https://github.com/juhp)
- Bernardo Meurer [**(@lovesegfault)**](https://github.com/lovesegfault)
- Peter Bynum [**(@pkpbynum)**](https://github.com/pkpbynum)
- Jörg Thalheim [**(@Mic92)**](https://github.com/Mic92)
- Alex Decious [**(@adeci)**](https://github.com/adeci)
- Matthieu Coudron [**(@teto)**](https://github.com/teto)
- Domen Kožar [**(@domenkozar)**](https://github.com/domenkozar)
- Taeer Bar-Yam [**(@Radvendii)**](https://github.com/Radvendii)
- Seth Flynn [**(@getchoo)**](https://github.com/getchoo)
- Robert Hensing [**(@roberth)**](https://github.com/roberth)
- Vladimir Panteleev [**(@CyberShadow)**](https://github.com/CyberShadow)
- bryango [**(@bryango)**](https://github.com/bryango)
- Henry [**(@cootshk)**](https://github.com/cootshk)
- Martin Joerg [**(@mjoerg)**](https://github.com/mjoerg)
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)

View File

@@ -2,7 +2,7 @@
> **Example**
>
> `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
> `/nix/store/jf6gn2dzna4nmsfbdxsd7kwhsk6gnnlr-git-2.38.1`
>
> A rendered store path
@@ -22,7 +22,7 @@ Store paths are pairs of
> **Example**
>
> - Digest: `b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z`
> - Digest: `q06x3jll2yfzckz2bzqak089p43ixkkq`
> - Name: `firefox-33.1`
To make store objects accessible to operating system processes, stores have to expose store objects through the file system.
@@ -38,7 +38,7 @@ A store path is rendered to a file system path as the concatenation of
> **Example**
>
> ```
> /nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1
> /nix/store/q06x3jll2yfzckz2bzqak089p43ixkkq-firefox-33.1
> |--------| |------------------------------| |----------|
> store directory digest name
> ```

View File

@@ -8,7 +8,7 @@ Stores are specified using a URL-like syntax. For example, the command
```console
# nix path-info --store https://cache.nixos.org/ --json \
/nix/store/a7gvj343m05j2s32xcnwr35v31ynlypr-coreutils-9.1
/nix/store/1542dip9i7k4f24y6hqgd04hmvid9hr5-coreutils-9.1
```
fetches information about a store path in the HTTP binary cache

10
flake.lock generated
View File

@@ -3,15 +3,15 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}

View File

@@ -6,7 +6,7 @@
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
inputs.nixpkgs-23-11.url = "github:NixOS/nixpkgs/a62e6edd6d5e1fa0329b8653c801147986f8d446";
inputs.flake-compat = {
url = "github:edolstra/flake-compat";
url = "github:NixOS/flake-compat";
flake = false;
};
@@ -418,10 +418,6 @@
supportsCross = false;
};
"nix-kaitai-struct-checks" = {
supportsCross = false;
};
"nix-perl-bindings" = {
supportsCross = false;
};

View File

@@ -224,5 +224,25 @@
"42688647+netadr@users.noreply.github.com": "netadr",
"matej.urbas@gmail.com": "urbas",
"ethanalexevans@gmail.com": "ethanavatar",
"greg.marti@gmail.com": "gmarti"
"greg.marti@gmail.com": "gmarti",
"arnout@bzzt.net": "raboof",
"vinayakankugoyal@gmail.com": "vinayakankugoyal",
"Radvendii@users.noreply.github.com": "Radvendii",
"jon@jh86.org": "jonhermansen",
"edef@edef.eu": "edef1c",
"pkpbynum@gmail.com": "pkpbynum",
"886074+teto@users.noreply.github.com": "teto",
"alex@adnab.me": "Alexis211",
"root@gws.fyi": "glittershark",
"me@m4rc3l.de": "MarcelCoding",
"taeer.bar-yam@bevuta.com": "Radvendii",
"martin.joerg@gmail.com": "mjoerg",
"git@cy.md": "CyberShadow",
"cootshk@duck.com": "cootshk",
"adam@dinwoodie.org": "me-and",
"domen@cachix.org": "domenkozar",
"alex.decious@gmail.com": "adeci",
"soumya.papanvk18@gmail.com": "neuralsorcerer",
"gdennis@anduril.com": null,
"graham.dennis@gmail.com": "GrahamDennis"
}

View File

@@ -196,5 +196,21 @@
"gmarti": "Gr\u00e9gory Marti",
"lovesegfault": "Bernardo Meurer",
"EphraimSiegfried": "Ephraim Siegfried",
"hgl": "Glen Huang"
"hgl": "Glen Huang",
"mjoerg": "Martin Joerg",
"Alexis211": "Alex Auvolat",
"domenkozar": "Domen Ko\u017ear",
"edef1c": "edef",
"cootshk": "Henry",
"raboof": "Arnout Engelen",
"pkpbynum": "Peter Bynum",
"glittershark": "Aspen Smith",
"MarcelCoding": "Marcel",
"teto": "Matthieu Coudron",
"jonhermansen": null,
"neuralsorcerer": "Soumyadip Sarkar",
"adeci": "Alex Decious",
"vinayakankugoyal": "Vinayak Goyal",
"me-and": "Adam Dinwoodie",
"GrahamDennis": "Graham Dennis"
}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
git ls-files -z \
| xargs -0 grep -o '[0123456789abcdfghijklmnpqrsvwxyz]\{32\}' 2> /dev/null \
| rev \
| cut -d: -f1 \
| rev \
| sort \
| uniq \
| while read -r oldhash; do
if ! curl --fail -I "https://cache.nixos.org/$oldhash.narinfo" > /dev/null 2>&1; then
continue
fi
newhash=$(
nix eval --expr "builtins.toFile \"006c6ssvddri1sg34wnw65mzd05pcp3qliylxlhv49binldajba5\" \"$oldhash\"" \
| cut -d- -f1 \
| cut -d/ -f4
)
msg=$(printf "bad: %s -> %s" "$oldhash" "$newhash")
echo "$msg"
git ls-files -z \
| xargs -0 grep -a -l "$oldhash" 2> /dev/null \
| while read -r file; do
[ -L "$file" ] && continue
perl -pi -e "s/$oldhash/$newhash/g" "$file" || true
done || true
git commit -am "$msg"
done

View File

@@ -0,0 +1,110 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
7w==
=mXYP
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,51 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=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 -->

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
@@ -104,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/
@@ -181,16 +177,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

@@ -63,6 +63,3 @@ subproject('nix-functional-tests')
if get_option('json-schema-checks')
subproject('json-schema-checks')
endif
if get_option('kaitai-struct-checks')
subproject('kaitai-struct-checks')
endif

View File

@@ -28,13 +28,6 @@ option(
description : 'Build benchmarks (requires gbenchmark)',
)
option(
'kaitai-struct-checks',
type : 'boolean',
value : true,
description : 'Check the Kaitai Struct specifications (requires Kaitai Struct)',
)
option(
'json-schema-checks',
type : 'boolean',

View File

@@ -133,7 +133,7 @@ let
+
lib.optionalString
(
!stdenv.hostPlatform.isWindows
!(stdenv.hostPlatform.isWindows || stdenv.hostPlatform.isCygwin)
# build failure
&& !stdenv.hostPlatform.isStatic
# LTO breaks exception handling on x86-64-darwin.
@@ -452,11 +452,6 @@ in
*/
nix-json-schema-checks = callPackage ../src/json-schema-checks/package.nix { };
/**
Kaitai struct schema validation checks
*/
nix-kaitai-struct-checks = callPackage ../src/kaitai-struct-checks/package.nix { };
nix-perl-bindings = callPackage ../src/perl/package.nix { };
/**

View File

@@ -40,6 +40,7 @@ scope: {
postInstall =
lib.replaceStrings [ "lowdown.so.1" "lowdown.1.dylib" ] [ "lowdown.so.2" "lowdown.2.dylib" ]
(prevAttrs.postInstall or "");
patches = [ ];
});
# TODO: Remove this when https://github.com/NixOS/nixpkgs/pull/442682 is included in a stable release

View File

@@ -142,12 +142,23 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
internalDrvs = byDrvPath (
# Drop the attr names (not present in buildInputs anyway)
lib.attrValues availableComponents
++ lib.concatMap (c: lib.attrValues c.tests or { }) (lib.attrValues availableComponents)
++ lib.concatMap (c: lib.filter (v: !v.meta.broken) (lib.attrValues (c.tests or { }))) (
lib.attrValues availableComponents
)
);
isInternal =
dep: internalDrvs ? ${builtins.unsafeDiscardStringContext dep.drvPath or "_non-existent_"};
activeComponentNames = lib.listToAttrs (
map (c: {
name = c.pname or c.name;
value = null;
}) activeComponents
);
isActiveComponent = name: activeComponentNames ? ${name};
in
{
pname = "shell-for-nix";
@@ -190,27 +201,19 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
}
);
small =
(finalAttrs.finalPackage.withActiveComponents (
c:
lib.intersectAttrs (lib.genAttrs [
"nix-cli"
"nix-util-tests"
"nix-store-tests"
"nix-expr-tests"
"nix-fetchers-tests"
"nix-flake-tests"
"nix-functional-tests"
"nix-perl-bindings"
] (_: null)) c
)).overrideAttrs
(o: {
mesonFlags = o.mesonFlags ++ [
# TODO: infer from activeComponents or vice versa
"-Dkaitai-struct-checks=false"
"-Djson-schema-checks=false"
];
});
small = finalAttrs.finalPackage.withActiveComponents (
c:
lib.intersectAttrs (lib.genAttrs [
"nix-cli"
"nix-util-tests"
"nix-store-tests"
"nix-expr-tests"
"nix-fetchers-tests"
"nix-flake-tests"
"nix-functional-tests"
"nix-perl-bindings"
] (_: null)) c
);
};
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
@@ -258,10 +261,13 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
# We use this shell with the local checkout, not unpackPhase.
src = null;
# Workaround https://sourceware.org/pipermail/gdb-patches/2025-October/221398.html
# Remove when gdb fix is rolled out everywhere.
separateDebugInfo = false;
mesonBuildType = "debugoptimized";
env = {
# For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
@@ -275,21 +281,32 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
dontUseCmakeConfigure = true;
mesonFlags =
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents2.nix-store.mesonFlags)
++ map (transformFlag "libfetchers") (ignoreCrossFile pkgs.nixComponents2.nix-fetchers.mesonFlags)
++ lib.optionals havePerl (
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
)
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
mesonFlags = [
(lib.mesonBool "json-schema-checks" (isActiveComponent "nix-json-schema-checks"))
]
++ map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents2.nix-store.mesonFlags)
++ map (transformFlag "libfetchers") (ignoreCrossFile pkgs.nixComponents2.nix-fetchers.mesonFlags)
++ lib.optionals havePerl (
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
)
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
nativeBuildInputs =
let
inputs =
dedupByString (v: "${v}") (
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.nativeBuildInputs) activeComponents)
lib.filter (x: !isInternal x) (
lib.lists.concatMap (
# Nix manual has a build-time dependency on nix, but we
# don't want to do a native build just to enter the ross
# dev shell.
#
# TODO: think of a more principled fix for this.
c: lib.filter (f: f.pname or null != "nix") c.nativeBuildInputs
) activeComponents
)
)
++ lib.optional (
!buildCanExecuteHost
@@ -305,8 +322,8 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
pkgs.buildPackages.nixfmt-rfc-style
pkgs.buildPackages.shellcheck
pkgs.buildPackages.include-what-you-use
pkgs.buildPackages.gdb
]
++ lib.optional pkgs.hostPlatform.isUnix pkgs.buildPackages.gdb
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
lib.hiPrio pkgs.buildPackages.clang-tools
)
@@ -322,13 +339,13 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
)
);
buildInputs = [
pkgs.gbenchmark
]
++ dedupByString (v: "${v}") (
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.buildInputs) activeComponents)
)
++ lib.optional havePerl pkgs.perl;
buildInputs =
# TODO change Nixpkgs to mark gbenchmark as building on Windows
lib.optional pkgs.hostPlatform.isUnix pkgs.gbenchmark
++ dedupByString (v: "${v}") (
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.buildInputs) activeComponents)
)
++ lib.optional havePerl pkgs.perl;
propagatedBuildInputs = dedupByString (v: "${v}") (
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.propagatedBuildInputs) activeComponents)

View File

@@ -72,7 +72,6 @@ let
"nix-manual-manpages-only"
"nix-internal-api-docs"
"nix-external-api-docs"
"nix-kaitai-struct-checks"
]
);
in

View File

@@ -53,8 +53,8 @@ readonly PROFILE_NIX_FILE_FISH="$NIX_ROOT/var/nix/profiles/default/etc/profile.d
readonly NIX_INSTALLED_NIX="@nix@"
readonly NIX_INSTALLED_CACERT="@cacert@"
#readonly NIX_INSTALLED_NIX="/nix/store/j8dbv5w6jl34caywh2ygdy88knx1mdf7-nix-2.3.6"
#readonly NIX_INSTALLED_CACERT="/nix/store/7dxhzymvy330i28ii676fl1pqwcahv2f-nss-cacert-3.49.2"
#readonly NIX_INSTALLED_NIX="/nix/store/byi37zv50wnfrpp4d81z3spswd5zva37-nix-2.3.6"
#readonly NIX_INSTALLED_CACERT="/nix/store/7pi45g541xa8ahwgpbpy7ggsl0xj1jj6-nss-cacert-3.49.2"
EXTRACTED_NIX_PATH="$(dirname "$0")"
readonly EXTRACTED_NIX_PATH

View File

@@ -62,9 +62,11 @@ schemas = [
},
{
'stem' : 'build-trace-entry',
'schema' : schema_dir / 'build-trace-entry-v1.yaml',
'schema' : schema_dir / 'build-trace-entry-v2.yaml',
'files' : [
'simple.json',
# The field is no longer supported, but we want to show that we
# ignore it during parsing.
'with-dependent-realisations.json',
'with-signature.json',
],

View File

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

View File

@@ -1,77 +0,0 @@
# Run with:
# meson test --suite kaitai-struct
# Run with: (without shell / configure)
# nix build .#nix-kaitai-struct-checks
project(
'nix-kaitai-struct-checks',
'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++23',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',
license : 'LGPL-2.1-or-later',
)
kaitai_runtime_dep = dependency('kaitai-struct-cpp-stl-runtime', required : true)
gtest_dep = dependency('gtest')
gtest_main_dep = dependency('gtest_main', required : true)
# Find the Kaitai Struct compiler
ksc = find_program('ksc', required : true)
kaitai_generated_srcs = custom_target(
'kaitai-generated-sources',
input : [ 'nar.ksy' ],
output : [ 'nix_nar.cpp', 'nix_nar.h' ],
command : [
ksc,
'@INPUT@',
'--target', 'cpp_stl',
'--outdir',
meson.current_build_dir(),
],
)
nar_kaitai_lib = library(
'nix-nar-kaitai-lib',
kaitai_generated_srcs,
dependencies : [ kaitai_runtime_dep ],
install : true,
)
nar_kaitai_dep = declare_dependency(
link_with : nar_kaitai_lib,
sources : kaitai_generated_srcs[1],
)
# The nar directory is a committed symlink to the actual nars location
nars_dir = meson.current_source_dir() / 'nars'
# Get all example files
nars = [
'dot.nar',
]
test_deps = [
nar_kaitai_dep,
kaitai_runtime_dep,
gtest_main_dep,
]
this_exe = executable(
meson.project_name(),
'test-parse-nar.cc',
dependencies : test_deps,
)
test(
meson.project_name(),
this_exe,
env : [ 'NIX_NARS_DIR=' + nars_dir ],
protocol : 'gtest',
)

View File

@@ -1 +0,0 @@
../../doc/manual/source/protocols/nix-archive/nar.ksy

View File

@@ -1 +0,0 @@
../libutil-tests/data/nars

View File

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

View File

@@ -1,70 +0,0 @@
# Run with: nix build .#nix-kaitai-struct-checks
# or: `nix develop .#nix-kaitai-struct-checks` to enter a dev shell
{
lib,
mkMesonDerivation,
gtest,
meson,
ninja,
pkg-config,
kaitai-struct-compiler,
fetchzip,
kaitai-struct-cpp-stl-runtime,
# Configuration Options
version,
}:
let
inherit (lib) fileset;
in
mkMesonDerivation (finalAttrs: {
pname = "nix-kaitai-struct-checks";
inherit version;
workDir = ./.;
fileset = lib.fileset.unions [
../../nix-meson-build-support
./nix-meson-build-support
./.version
../../.version
../../doc/manual/source/protocols/nix-archive/nar.ksy
./nars
../../src/libutil-tests/data
./meson.build
./nar.ksy
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
];
outputs = [ "out" ];
buildInputs = [
gtest
kaitai-struct-cpp-stl-runtime
];
nativeBuildInputs = [
meson
ninja
pkg-config
# This can go away when we bump up to 25.11
(kaitai-struct-compiler.overrideAttrs (finalAttrs: {
version = "0.11";
src = fetchzip {
url = "https://github.com/kaitai-io/kaitai_struct_compiler/releases/download/${version}/kaitai-struct-compiler-${version}.zip";
sha256 = "sha256-j9TEilijqgIiD0GbJfGKkU1FLio9aTopIi1v8QT1b+A=";
};
}))
];
doCheck = true;
mesonCheckFlags = [ "--print-errorlogs" ];
postInstall = ''
touch $out
'';
meta = {
platforms = lib.platforms.unix;
};
})

View File

@@ -1,48 +0,0 @@
#include <gtest/gtest.h>
#include <filesystem>
#include <fstream>
#include <vector>
#include <string>
#include <kaitai/kaitaistream.h>
#include <fstream>
#include <string>
#include <vector>
#include "nix_nar.h"
static const std::vector<std::string> NarFiles = {
"empty.nar",
"dot.nar",
"dotdot.nar",
"executable-after-contents.nar",
"invalid-tag-instead-of-contents.nar",
"name-after-node.nar",
"nul-character.nar",
"slash.nar",
};
class NarParseTest : public ::testing::TestWithParam<std::string>
{};
TEST_P(NarParseTest, ParseSucceeds)
{
const auto nar_file = GetParam();
const char * nars_dir_env = std::getenv("NIX_NARS_DIR");
if (nars_dir_env == nullptr) {
FAIL() << "NIX_NARS_DIR environment variable not set.";
}
const std::filesystem::path nar_file_path = std::filesystem::path(nars_dir_env) / "dot.nar";
ASSERT_TRUE(std::filesystem::exists(nar_file_path)) << "Missing test file: " << nar_file_path;
std::ifstream ifs(nar_file_path, std::ifstream::binary);
ASSERT_TRUE(ifs.is_open()) << "Failed to open file: " << nar_file;
kaitai::kstream ks(&ifs);
nix_nar_t nar(&ks);
ASSERT_TRUE(nar.root_node() != nullptr) << "Failed to parse NAR file: " << nar_file;
}
INSTANTIATE_TEST_SUITE_P(AllNarFiles, NarParseTest, ::testing::ValuesIn(NarFiles));

View File

@@ -116,7 +116,11 @@ MixFlakeOptions::MixFlakeOptions()
.labels = {"input-path"},
.handler = {[&](std::string s) {
warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version.");
lockFlags.inputUpdates.insert(flake::parseInputAttrPath(s));
auto path = flake::NonEmptyInputAttrPath::parse(s);
if (!path)
throw UsageError(
"--update-input was passed a zero-length input path, which would refer to the flake itself, not an input");
lockFlags.inputUpdates.insert(*path);
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
@@ -125,14 +129,18 @@ MixFlakeOptions::MixFlakeOptions()
addFlag({
.longName = "override-input",
.description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.",
.description =
"Override a specific flake input (e.g. `dwarffs/nixpkgs`). The input path must not be empty. This implies `--no-write-lock-file`.",
.category = category,
.labels = {"input-path", "flake-url"},
.handler = {[&](std::string inputAttrPath, std::string flakeRef) {
lockFlags.writeLockFile = false;
auto path = flake::NonEmptyInputAttrPath::parse(inputAttrPath);
if (!path)
throw UsageError(
"--override-input was passed a zero-length input path, which would refer to the flake itself, not an input");
lockFlags.inputOverrides.insert_or_assign(
flake::parseInputAttrPath(inputAttrPath),
parseFlakeRef(fetchSettings, flakeRef, absPath(getCommandBaseDir()).string(), true));
std::move(*path), parseFlakeRef(fetchSettings, flakeRef, absPath(getCommandBaseDir()).string(), true));
}},
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
if (n == 0) {

View File

@@ -0,0 +1,14 @@
#include <benchmark/benchmark.h>
#include "nix/expr/eval-gc.hh"
#include "nix/store/globals.hh"
int main(int argc, char ** argv)
{
nix::initLibStore(false);
nix::initGC();
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
return 0;
}

View File

@@ -0,0 +1,55 @@
#include <benchmark/benchmark.h>
#include "nix/expr/eval.hh"
#include "nix/expr/eval-settings.hh"
#include "nix/fetchers/fetch-settings.hh"
#include "nix/store/store-open.hh"
using namespace nix;
static std::string mkDynamicAttrsExpr(size_t attrCount)
{
std::string res;
res.reserve(attrCount * 24);
res += "{ ";
for (size_t i = 0; i < attrCount; ++i) {
res += "${\"a";
res += std::to_string(i);
res += "\"} = ";
res += std::to_string(i);
res += "; ";
}
res += "}";
return res;
}
static void BM_EvalDynamicAttrs(benchmark::State & state)
{
const auto attrCount = static_cast<size_t>(state.range(0));
const auto exprStr = mkDynamicAttrsExpr(attrCount);
for (auto _ : state) {
state.PauseTiming();
auto store = openStore("dummy://");
fetchers::Settings fetchSettings{};
bool readOnlyMode = true;
EvalSettings evalSettings{readOnlyMode};
evalSettings.nixPath = {};
EvalState st({}, store, fetchSettings, evalSettings, nullptr);
Expr * expr = st.parseExprFromString(exprStr, st.rootPath(CanonPath::root));
Value v;
state.ResumeTiming();
st.eval(expr, v);
st.forceValue(v, noPos);
benchmark::DoNotOptimize(v);
}
state.SetItemsProcessed(state.iterations() * attrCount);
}
BENCHMARK(BM_EvalDynamicAttrs)->Arg(100)->Arg(500)->Arg(2'000);

View File

@@ -0,0 +1,64 @@
#include <benchmark/benchmark.h>
#include "nix/expr/get-drvs.hh"
#include "nix/expr/eval-settings.hh"
#include "nix/fetchers/fetch-settings.hh"
#include "nix/store/store-open.hh"
#include "nix/util/fmt.hh"
using namespace nix;
namespace {
struct GetDerivationsEnv
{
ref<Store> store = openStore("dummy://");
fetchers::Settings fetchSettings{};
bool readOnlyMode = true;
EvalSettings evalSettings{readOnlyMode};
EvalState state;
Bindings * autoArgs = nullptr;
Value attrsValue;
explicit GetDerivationsEnv(size_t attrCount)
: evalSettings([&]() {
EvalSettings settings{readOnlyMode};
settings.nixPath = {};
return settings;
}())
, state({}, store, fetchSettings, evalSettings, nullptr)
{
autoArgs = state.buildBindings(0).finish();
auto attrs = state.buildBindings(attrCount);
for (size_t i = 0; i < attrCount; ++i) {
auto name = fmt("pkg%|1$06d|", i);
auto sym = state.symbols.create(name);
auto & v = attrs.alloc(sym);
v.mkInt(i);
}
attrsValue.mkAttrs(attrs.finish());
}
};
} // namespace
static void BM_GetDerivationsAttrScan(benchmark::State & state)
{
const auto attrCount = static_cast<size_t>(state.range(0));
GetDerivationsEnv env(attrCount);
for (auto _ : state) {
PackageInfos drvs;
getDerivations(
env.state, env.attrsValue, /*pathPrefix=*/"", *env.autoArgs, drvs, /*ignoreAssertionFailures=*/true);
benchmark::DoNotOptimize(drvs.size());
}
state.SetItemsProcessed(state.iterations() * attrCount);
}
BENCHMARK(BM_GetDerivationsAttrScan)->Arg(1'000)->Arg(5'000)->Arg(10'000);

View File

@@ -87,3 +87,33 @@ test(
},
protocol : 'gtest',
)
# Build benchmarks if enabled
if get_option('benchmarks')
gbenchmark = dependency('benchmark', required : true)
benchmark_sources = files(
'bench-main.cc',
'dynamic-attrs-bench.cc',
'get-drvs-bench.cc',
'regex-cache-bench.cc',
)
benchmark_exe = executable(
'nix-expr-benchmarks',
benchmark_sources,
config_priv_h,
dependencies : deps_private_subproject + deps_private + deps_other + [
gbenchmark,
],
include_directories : include_dirs,
link_args : linker_export_flags,
install : true,
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [],
)
benchmark(
'nix-expr-benchmarks',
benchmark_exe,
)
endif

View File

@@ -0,0 +1,9 @@
# vim: filetype=meson
option(
'benchmarks',
type : 'boolean',
value : false,
description : 'Build benchmarks (requires gbenchmark)',
yield : true,
)

View File

@@ -33,7 +33,7 @@ mkMesonExecutable (finalAttrs: {
../../.version
./.version
./meson.build
# ./meson.options
./meson.options
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
];

View File

@@ -0,0 +1,45 @@
#include <benchmark/benchmark.h>
#include "nix/expr/eval.hh"
#include "nix/expr/eval-settings.hh"
#include "nix/fetchers/fetch-settings.hh"
#include "nix/store/store-open.hh"
using namespace nix;
static void BM_EvalManyBuiltinsMatchSameRegex(benchmark::State & state)
{
static constexpr int iterations = 5'000;
static constexpr std::string_view exprStr =
"builtins.foldl' "
"(acc: _: acc + builtins.length (builtins.match \"a\" \"a\")) "
"0 "
"(builtins.genList (x: x) "
"5000)";
for (auto _ : state) {
state.PauseTiming();
auto store = openStore("dummy://");
fetchers::Settings fetchSettings{};
bool readOnlyMode = true;
EvalSettings evalSettings{readOnlyMode};
evalSettings.nixPath = {};
EvalState st({}, store, fetchSettings, evalSettings, nullptr);
Expr * expr = st.parseExprFromString(std::string(exprStr), st.rootPath(CanonPath::root));
Value v;
state.ResumeTiming();
st.eval(expr, v);
st.forceValue(v, noPos);
benchmark::DoNotOptimize(v);
}
state.SetItemsProcessed(state.iterations() * iterations);
}
BENCHMARK(BM_EvalManyBuiltinsMatchSameRegex);

View File

@@ -1,5 +1,6 @@
#include "nix/expr/attr-path.hh"
#include "nix/expr/eval-inline.hh"
#include "nix/util/util.hh"
#include "nix/util/strings-inline.hh"
namespace nix {
@@ -137,16 +138,15 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
auto fail = [fn]() { throw ParseError("cannot parse 'meta.position' attribute '%s'", fn); };
try {
auto colon = fn.rfind(':');
if (colon == std::string::npos)
fail();
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
} catch (std::invalid_argument & e) {
auto colon = fn.rfind(':');
if (colon == std::string::npos)
fail();
unreachable();
}
auto lineno = string2Int<uint32_t>(std::string_view(fn).substr(colon + 1));
if (!lineno)
fail();
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, *lineno};
}
} // namespace nix

View File

@@ -265,7 +265,7 @@ struct AttrDb
case AttrType::String: {
NixStringContext context;
if (!queryAttribute.isNull(3))
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), ";"))
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), " "))
context.insert(NixStringContextElem::parse(s));
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
}

View File

@@ -111,6 +111,7 @@ template class EvalErrorBuilder<TypeError>;
template class EvalErrorBuilder<UndefinedVarError>;
template class EvalErrorBuilder<MissingArgumentError>;
template class EvalErrorBuilder<InfiniteRecursionError>;
template class EvalErrorBuilder<StackOverflowError>;
template class EvalErrorBuilder<InvalidPathError>;
template class EvalErrorBuilder<IFDError>;

View File

@@ -741,6 +741,11 @@ public:
inDebugger = true;
}
DebuggerGuard(DebuggerGuard &&) = delete;
DebuggerGuard(const DebuggerGuard &) = delete;
DebuggerGuard & operator=(DebuggerGuard &&) = delete;
DebuggerGuard & operator=(const DebuggerGuard &) = delete;
~DebuggerGuard()
{
inDebugger = false;
@@ -2403,6 +2408,8 @@ BackedStringView EvalState::coerceToString(
bool copyToStore,
bool canonicalizePath)
{
auto _level = addCallDepth(pos);
forceValue(v, pos);
if (v.type() == nString) {
@@ -2622,6 +2629,8 @@ SingleDerivedPath EvalState::coerceToSingleDerivedPath(const PosIdx pos, Value &
// `assert a == b; x` are critical for our users' testing UX.
void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
{
auto _level = addCallDepth(pos);
// This implementation must match eqValues.
forceValue(v1, pos);
forceValue(v2, pos);
@@ -2828,6 +2837,8 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
// This implementation must match assertEqValues
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
{
auto _level = addCallDepth(pos);
forceValue(v1, pos);
forceValue(v2, pos);

View File

@@ -213,6 +213,8 @@ StringSet PackageInfo::queryMetaNames()
bool PackageInfo::checkMeta(Value & v)
{
auto _level = state->addCallDepth(v.determinePos(noPos));
state->forceValue(v, v.determinePos(noPos));
if (v.type() == nList) {
for (auto elem : v.listView())
@@ -367,7 +369,26 @@ static std::string addToPath(const std::string & s1, std::string_view s2)
return s1.empty() ? std::string(s2) : s1 + "." + s2;
}
static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*");
static bool isAttrPathComponent(std::string_view symbol)
{
if (symbol.empty())
return false;
/* [A-Za-z_] */
unsigned char first = symbol[0];
if (!((first >= 'A' && first <= 'Z') || (first >= 'a' && first <= 'z') || first == '_'))
return false;
/* [A-Za-z0-9-_+]* */
for (unsigned char c : symbol.substr(1)) {
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_'
|| c == '+')
continue;
return false;
}
return true;
}
static void getDerivations(
EvalState & state,
@@ -378,6 +399,8 @@ static void getDerivations(
Done & done,
bool ignoreAssertionFailures)
{
auto _level = state.addCallDepth(vIn.determinePos(noPos));
Value v;
state.autoCallFunction(autoArgs, vIn, v);
@@ -400,7 +423,7 @@ static void getDerivations(
std::string_view symbol{state.symbols[i->name]};
try {
debug("evaluating attribute '%1%'", symbol);
if (!std::regex_match(symbol.begin(), symbol.end(), attrRegex))
if (!isAttrPathComponent(symbol))
continue;
std::string pathPrefix2 = addToPath(pathPrefix, symbol);
if (combineChannels)

View File

@@ -107,6 +107,8 @@ private:
Bindings & operator=(const Bindings &) = delete;
Bindings & operator=(Bindings &&) = delete;
~Bindings() = default;
friend class BindingsBuilder;
/**

View File

@@ -54,6 +54,20 @@ MakeError(TypeError, EvalError);
MakeError(UndefinedVarError, EvalError);
MakeError(MissingArgumentError, EvalError);
MakeError(InfiniteRecursionError, EvalError);
/**
* Resource exhaustion error when evaluation exceeds max-call-depth.
* Inherits from EvalBaseError (not EvalError) because resource exhaustion
* should not be cached.
*/
struct StackOverflowError : public EvalBaseError
{
StackOverflowError(EvalState & state)
: EvalBaseError(state, "stack overflow; max-call-depth exceeded")
{
}
};
MakeError(IFDError, EvalBaseError);
struct InvalidPathError : public EvalError

View File

@@ -139,7 +139,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos, std::string_view e
inline CallDepth EvalState::addCallDepth(const PosIdx pos)
{
if (callDepth > settings.maxCallDepth)
error<EvalBaseError>("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow();
error<StackOverflowError>().atPos(pos).debugThrow();
return CallDepth(callDepth);
};

View File

@@ -5,6 +5,8 @@
namespace nix {
class EvalState;
/**
* Print a value in the deprecated format used by `nix-instantiate --eval` and
* `nix-env` (for manifests).
@@ -15,7 +17,6 @@ namespace nix {
*
* See: https://github.com/NixOS/nix/issues/9730
*/
void printAmbiguous(
Value & v, const SymbolTable & symbols, std::ostream & str, std::set<const void *> * seen, int depth);
void printAmbiguous(EvalState & state, Value & v, std::ostream & str, std::set<const void *> * seen, size_t depth = 0);
} // namespace nix

View File

@@ -164,8 +164,6 @@ public:
Value ** elems;
ListBuilder(EvalMemory & mem, size_t size);
// NOTE: Can be noexcept because we are just copying integral values and
// raw pointers.
ListBuilder(ListBuilder && x) noexcept
: size(x.size)
, inlineElems{x.inlineElems[0], x.inlineElems[1]}
@@ -173,6 +171,11 @@ public:
{
}
ListBuilder(const ListBuilder &) = delete;
ListBuilder & operator=(ListBuilder &&) = delete;
ListBuilder & operator=(const ListBuilder &) = delete;
~ListBuilder() = default;
Value *& operator[](size_t n)
{
return elems[n];

View File

@@ -3002,16 +3002,19 @@ static RegisterPrimOp primop_path({
- recursive\
When `false`, when `path` is added to the store it is with a
flat hash, rather than a hash of the NAR serialization of the
file. Thus, `path` must refer to a regular file, not a
[flat hash](@docroot@/store/file-system-object/content-address.md#serial-flat),
rather than a hash of the
[NAR serialization](@docroot@/store/file-system-object/content-address.md#serial-nix-archive)
of the file. Thus, `path` must refer to a regular file, not a
directory. This allows similar behavior to `fetchurl`. Defaults
to `true`.
- sha256\
When provided, this is the expected hash of the file at the
path. Evaluation fails if the hash is incorrect, and
providing a hash allows `builtins.path` to be used even when the
`pure-eval` nix config option is on.
When provided, this is the expected
[content hash](@docroot@/store/file-system-object/content-address.md)
of the path. Evaluation fails if the hash is incorrect,
and providing a hash allows `builtins.path` to be used even
when the `pure-eval` nix config option is on.
)",
.fun = prim_path,
});
@@ -4061,6 +4064,8 @@ static RegisterPrimOp primop_sort({
1. Transitivity
If a is less than b and b is less than c, then it follows that a is less than c.
```nix
comparator a b && comparator b c -> comparator a c
```
@@ -4073,9 +4078,23 @@ static RegisterPrimOp primop_sort({
1. Transitivity of equivalence
First, two values a and b are considered equivalent with respect to the comparator if:
```
!comparator a b && !comparator b a
```
In other words, neither is considered "less than" the other.
Transitivity of equivalence means:
If a is equivalent to b, and b is equivalent to c, then a must also be equivalent to c.
```nix
let equiv = a: b: (!comparator a b && !comparator b a); in
equiv a b && equiv b c -> equiv a c
let
equiv = x: y: (!comparator x y && !comparator y x);
in
equiv a b && equiv b c -> equiv a c
```
If the *comparator* violates any of these properties, then `builtins.sort`
@@ -4693,21 +4712,28 @@ static RegisterPrimOp primop_convertHash({
struct RegexCache
{
boost::concurrent_flat_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache;
std::regex get(std::string_view re)
struct Entry
{
std::regex regex;
/* No std::regex constructor overload from std::string_view, but can be constructed
from a pointer + size or an iterator range. */
ref<const std::regex> regex;
Entry(const char * s, size_t count)
: regex(make_ref<const std::regex>(s, count, std::regex::extended))
{
}
};
boost::concurrent_flat_map<std::string, Entry, StringViewHash, std::equal_to<>> cache;
ref<const std::regex> get(std::string_view re)
{
std::optional<ref<const std::regex>> regex;
cache.try_emplace_and_cvisit(
re,
/*s=*/re.data(),
/*count=*/re.size(),
std::regex::extended,
[&regex](const auto & kv) { regex = kv.second; },
[&regex](const auto & kv) { regex = kv.second; });
return regex;
[&regex](const auto & kv) { regex = kv.second.regex; },
[&regex](const auto & kv) { regex = kv.second.regex; });
return *regex;
}
};
@@ -4729,7 +4755,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v)
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match");
std::cmatch match;
if (!std::regex_match(str.begin(), str.end(), match, regex)) {
if (!std::regex_match(str.begin(), str.end(), match, *regex)) {
v.mkNull();
return;
}
@@ -4802,7 +4828,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v)
const auto str =
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.split");
auto begin = std::cregex_iterator(str.begin(), str.end(), regex);
auto begin = std::cregex_iterator(str.begin(), str.end(), *regex);
auto end = std::cregex_iterator();
// Any matches results are surrounded by non-matching results.

View File

@@ -243,7 +243,7 @@ static RegisterPrimOp primop_fetchClosure({
```nix
builtins.fetchClosure {
fromStore = "https://cache.nixos.org";
fromPath = /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1;
fromPath = /nix/store/nph9br6y2dmciy6q3dj3fwk2brdlr4gh-git-2.33.1;
toPath = /nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1;
}
```
@@ -258,8 +258,8 @@ static RegisterPrimOp primop_fetchClosure({
use [`nix store make-content-addressed`](@docroot@/command-ref/new-cli/nix3-store-make-content-addressed.md):
```console
# nix store make-content-addressed --from https://cache.nixos.org /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1
rewrote '/nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1' to '/nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1'
# nix store make-content-addressed --from https://cache.nixos.org /nix/store/nph9br6y2dmciy6q3dj3fwk2brdlr4gh-git-2.33.1
rewrote '/nix/store/nph9br6y2dmciy6q3dj3fwk2brdlr4gh-git-2.33.1' to '/nix/store/ldbhlwhh39wha58rm61bkiiwm6j7211j-git-2.33.1'
```
Alternatively, set `toPath = ""` and find the correct `toPath` in the error message.
@@ -271,7 +271,7 @@ static RegisterPrimOp primop_fetchClosure({
```nix
builtins.fetchClosure {
fromStore = "https://cache.nixos.org";
fromPath = /nix/store/r2jd6ygnmirm2g803mksqqjm4y39yi6i-git-2.33.1;
fromPath = /nix/store/nph9br6y2dmciy6q3dj3fwk2brdlr4gh-git-2.33.1;
inputAddressed = true;
}
```

View File

@@ -2,19 +2,17 @@
#include "nix/expr/print.hh"
#include "nix/util/signals.hh"
#include "nix/expr/eval.hh"
#include "nix/expr/eval-error.hh"
namespace nix {
// See: https://github.com/NixOS/nix/issues/9730
void printAmbiguous(
Value & v, const SymbolTable & symbols, std::ostream & str, std::set<const void *> * seen, int depth)
void printAmbiguous(EvalState & state, Value & v, std::ostream & str, std::set<const void *> * seen, size_t depth)
{
checkInterrupt();
if (depth <= 0) {
str << "«too deep»";
return;
}
if (depth > state.settings.maxCallDepth)
state.error<StackOverflowError>().atPos(v.determinePos(noPos)).debugThrow();
switch (v.type()) {
case nInt:
str << v.integer();
@@ -36,9 +34,9 @@ void printAmbiguous(
str << "«repeated»";
else {
str << "{ ";
for (auto & i : v.attrs()->lexicographicOrder(symbols)) {
str << symbols[i->name] << " = ";
printAmbiguous(*i->value, symbols, str, seen, depth - 1);
for (auto & i : v.attrs()->lexicographicOrder(state.symbols)) {
str << state.symbols[i->name] << " = ";
printAmbiguous(state, *i->value, str, seen, depth + 1);
str << "; ";
}
str << "}";
@@ -54,7 +52,7 @@ void printAmbiguous(
str << "[ ";
for (auto v2 : v.listView()) {
if (v2)
printAmbiguous(*v2, symbols, str, seen, depth - 1);
printAmbiguous(state, *v2, str, seen, depth + 1);
else
str << "(nullptr)";
str << " ";

View File

@@ -537,6 +537,16 @@ private:
output.flush();
checkInterrupt();
// Catch infinite recursion before it overflows the C++ stack.
// Non-cyclic structures can be infinitely deep when values are
// lazily produced (e.g., `let f = n: { inner = f (n + 1); }; in f 0`).
// We check print depth against max-call-depth rather than incrementing
// the callDepth counter, because accessing an attribute is not a call.
// Other places do increment callDepth for simplicity, but that is
// technically incorrect.
if (depth > state.settings.maxCallDepth)
state.error<StackOverflowError>().atPos(v.determinePos(noPos)).debugThrow();
try {
if (options.force) {
state.forceValue(v, v.determinePos(noPos));
@@ -592,6 +602,11 @@ private:
printUnknown();
break;
}
} catch (StackOverflowError &) {
// Always re-throw because stack overflow is a serious condition
// that expressions should avoid, unlike say `throw`, which can
// be part of legitimate expression patterns.
throw;
} catch (Error & e) {
if (options.errors == ErrorPrintBehavior::Throw
|| (options.errors == ErrorPrintBehavior::ThrowTopLevel && depth == 0)) {

View File

@@ -66,6 +66,8 @@ static void printValueAsXML(
{
checkInterrupt();
auto _level = state.addCallDepth(pos);
if (strict)
state.forceValue(v, pos);

View File

@@ -48,7 +48,7 @@ public:
ref<GitRepo> openRepo()
{
return GitRepo::openRepo(tmpDir, true, false);
return GitRepo::openRepo(tmpDir, {.create = true});
}
std::string getRepoName() const
@@ -115,9 +115,10 @@ TEST_F(GitUtilsTest, sink_hardlink)
try {
sink->createHardlink(CanonPath("foo-1.1/link"), CanonPath("hello"));
sink->flush();
FAIL() << "Expected an exception";
} catch (const nix::Error & e) {
ASSERT_THAT(e.msg(), testing::HasSubstr("cannot find hard link target"));
ASSERT_THAT(e.msg(), testing::HasSubstr("does not exist"));
ASSERT_THAT(e.msg(), testing::HasSubstr("/hello"));
ASSERT_THAT(e.msg(), testing::HasSubstr("foo-1.1/link"));
}

View File

@@ -203,16 +203,19 @@ static git_packbuilder_progress PACKBUILDER_PROGRESS_CHECK_INTERRUPT = &packBuil
} // extern "C"
static void initRepoAtomically(std::filesystem::path & path, bool bare)
static void initRepoAtomically(std::filesystem::path & path, GitRepo::Options options)
{
if (pathExists(path.string()))
return;
if (!options.create)
throw Error("Git repository %s does not exist.", path);
std::filesystem::path tmpDir = createTempDir(path.parent_path());
AutoDelete delTmpDir(tmpDir, true);
Repository tmpRepo;
if (git_repository_init(Setter(tmpRepo), tmpDir.string().c_str(), bare))
if (git_repository_init(Setter(tmpRepo), tmpDir.string().c_str(), options.bare))
throw Error("creating Git repository %s: %s", path, git_error_last()->message);
try {
std::filesystem::rename(tmpDir, path);
@@ -234,7 +237,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
/** Location of the repository on disk. */
std::filesystem::path path;
bool bare;
Options options;
/**
* libgit2 repository. Note that new objects are not written to disk,
@@ -255,18 +258,18 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
*/
git_odb_backend * packBackend = nullptr;
GitRepoImpl(std::filesystem::path _path, bool create, bool bare, bool packfilesOnly = false)
GitRepoImpl(std::filesystem::path _path, Options _options)
: path(std::move(_path))
, bare(bare)
, options(_options)
{
initLibGit2();
initRepoAtomically(path, bare);
initRepoAtomically(path, options);
if (git_repository_open(Setter(repo), path.string().c_str()))
throw Error("opening Git repository %s: %s", path, git_error_last()->message);
ObjectDb odb;
if (packfilesOnly) {
if (options.packfilesOnly) {
/* Create a fresh object database because by default the repo also
loose object backends. We are not using any of those for the
tarball cache, but libgit2 still does a bunch of unnecessary
@@ -295,7 +298,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
if (git_odb_add_backend(odb.get(), mempackBackend, 999))
throw Error("adding mempack backend to Git object database: %s", git_error_last()->message);
if (packfilesOnly) {
if (options.packfilesOnly) {
if (git_repository_set_odb(repo.get(), odb.get()))
throw Error("setting Git object database: %s", git_error_last()->message);
}
@@ -366,7 +369,26 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
{
// TODO: as an optimization, it would be nice to include `this` in the pool.
return Pool<GitRepoImpl>(std::numeric_limits<size_t>::max(), [this]() -> ref<GitRepoImpl> {
return make_ref<GitRepoImpl>(path, false, bare);
auto repo = make_ref<GitRepoImpl>(path, options);
/* Monkey-patching the pack backend to only read the pack directory
once. Otherwise it will do a readdir for each added oid when it's
not found and that translates to ~6 syscalls. Since we are never
writing pack files until flushing we can force the odb backend to
read the directory just once. It's very convenient that the vtable is
semi-public interface and is up for grabs.
This is purely an optimization for our use-case with a tarball cache.
libgit2 calls refresh() if the backend provides it when an oid isn't found.
We are only writing objects to a mempack (it has higher priority) and there isn't
a realistic use-case where a previously missing object would appear from thin air
on the disk (unless another process happens to be unpacking a similar tarball to
the cache at the same time, but that's a very unrealistic scenario).
*/
if (auto * backend = repo->packBackend)
backend->refresh = nullptr;
return repo;
});
}
@@ -665,6 +687,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
keyDecoded = base64::decode(k.key);
} catch (Error & e) {
e.addTrace({}, "while decoding public key '%s' used for git signature", k.key);
throw;
}
auto fingerprint =
trim(hashString(HashAlgorithm::SHA256, keyDecoded).to_string(nix::HashFormat::Base64, false), "=");
@@ -712,9 +735,9 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
}
};
ref<GitRepo> GitRepo::openRepo(const std::filesystem::path & path, bool create, bool bare, bool packfilesOnly)
ref<GitRepo> GitRepo::openRepo(const std::filesystem::path & path, GitRepo::Options options)
{
return make_ref<GitRepoImpl>(path, create, bare, packfilesOnly);
return make_ref<GitRepoImpl>(path, options);
}
/**
@@ -1055,185 +1078,155 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
{
ref<GitRepoImpl> repo;
struct PendingDir
{
std::string name;
TreeBuilder builder;
};
Pool<GitRepoImpl> repoPool;
std::vector<PendingDir> pendingDirs;
unsigned int concurrency = std::min(std::thread::hardware_concurrency(), 10U);
/**
* Temporary buffer used by createRegularFile for storing small file contents.
*/
std::string regularFileContentsBuffer;
ThreadPool workers{concurrency};
/**
* If repo has a non-null packBackend, this has a copy of the refresh function
* from the backend virtual table. This is needed to restore it after we've flushed
* the sink. We modify it to avoid unnecessary I/O on non-existent oids.
*/
decltype(::git_odb_backend::refresh) packfileOdbRefresh = nullptr;
/** Total file contents in flight. */
std::atomic<size_t> totalBufSize{0};
void pushBuilder(std::string name)
{
const git_tree_entry * entry;
Tree prevTree = nullptr;
if (!pendingDirs.empty() && (entry = git_treebuilder_get(pendingDirs.back().builder.get(), name.c_str()))) {
/* Clone a tree that we've already finished. This happens
if a tarball has directory entries that are not
contiguous. */
if (git_tree_entry_type(entry) != GIT_OBJECT_TREE)
throw Error("parent of '%s' is not a directory", name);
if (git_tree_entry_to_object((git_object **) (git_tree **) Setter(prevTree), *repo, entry))
throw Error("looking up parent of '%s': %s", name, git_error_last()->message);
}
git_treebuilder * b;
if (git_treebuilder_new(&b, *repo, prevTree.get()))
throw Error("creating a tree builder: %s", git_error_last()->message);
pendingDirs.push_back({.name = std::move(name), .builder = TreeBuilder(b)});
};
static constexpr std::size_t maxBufSize = 16 * 1024 * 1024;
GitFileSystemObjectSinkImpl(ref<GitRepoImpl> repo)
: repo(repo)
, repoPool(repo->getPool())
{
/* Monkey-patching the pack backend to only read the pack directory
once. Otherwise it will do a readdir for each added oid when it's
not found and that translates to ~6 syscalls. Since we are never
writing pack files until flushing we can force the odb backend to
read the directory just once. It's very convenient that the vtable is
semi-public interface and is up for grabs.
This is purely an optimization for our use-case with a tarball cache.
libgit2 calls refresh() if the backend provides it when an oid isn't found.
We are only writing objects to a mempack (it has higher priority) and there isn't
a realistic use-case where a previously missing object would appear from thin air
on the disk (unless another process happens to be unpacking a similar tarball to
the cache at the same time, but that's a very unrealistic scenario).
*/
if (auto * backend = repo->packBackend) {
if (backend->refresh(backend)) /* Refresh just once manually. */
throw Error("refreshing packfiles: %s", git_error_last()->message);
/* Save the function pointer to restore it later in flush() and
unset it in the vtable. libgit2 does nothing if it's a nullptr:
https://github.com/libgit2/libgit2/blob/58d9363f02f1fa39e46d49b604f27008e75b72f2/src/libgit2/odb.c#L1922
*/
packfileOdbRefresh = std::exchange(backend->refresh, nullptr);
}
pushBuilder("");
}
std::pair<git_oid, std::string> popBuilder()
~GitFileSystemObjectSinkImpl()
{
assert(!pendingDirs.empty());
auto pending = std::move(pendingDirs.back());
git_oid oid;
if (git_treebuilder_write(&oid, pending.builder.get()))
throw Error("creating a tree object: %s", git_error_last()->message);
pendingDirs.pop_back();
return {oid, pending.name};
// Make sure the worker threads are destroyed before any state
// they're referring to.
workers.shutdown();
}
struct Child;
/// A directory to be written as a Git tree.
struct Directory
{
std::map<std::string, Child> children;
std::optional<git_oid> oid;
Child & lookup(const CanonPath & path)
{
assert(!path.isRoot());
auto parent = path.parent();
auto cur = this;
for (auto & name : *parent) {
auto i = cur->children.find(std::string(name));
if (i == cur->children.end())
throw Error("path '%s' does not exist", path);
auto dir = std::get_if<Directory>(&i->second.file);
if (!dir)
throw Error("path '%s' has a non-directory parent", path);
cur = dir;
}
auto i = cur->children.find(std::string(*path.baseName()));
if (i == cur->children.end())
throw Error("path '%s' does not exist", path);
return i->second;
}
};
void addToTree(const std::string & name, const git_oid & oid, git_filemode_t mode)
size_t nextId = 0; // for Child.id
struct Child
{
assert(!pendingDirs.empty());
auto & pending = pendingDirs.back();
if (git_treebuilder_insert(nullptr, pending.builder.get(), name.c_str(), &oid, mode))
throw Error("adding a file to a tree builder: %s", git_error_last()->message);
git_filemode_t mode;
std::variant<Directory, git_oid> file;
/// Sequential numbering of the file in the tarball. This is
/// used to make sure we only import the latest version of a
/// path.
size_t id{0};
};
void updateBuilders(std::span<const std::string> names)
struct State
{
// Find the common prefix of pendingDirs and names.
size_t prefixLen = 0;
for (; prefixLen < names.size() && prefixLen + 1 < pendingDirs.size(); ++prefixLen)
if (names[prefixLen] != pendingDirs[prefixLen + 1].name)
break;
Directory root;
};
// Finish the builders that are not part of the common prefix.
for (auto n = pendingDirs.size(); n > prefixLen + 1; --n) {
auto [oid, name] = popBuilder();
addToTree(name, oid, GIT_FILEMODE_TREE);
Sync<State> _state;
void addNode(State & state, const CanonPath & path, Child && child)
{
assert(!path.isRoot());
auto parent = path.parent();
Directory * cur = &state.root;
for (auto & i : *parent) {
auto child = std::get_if<Directory>(
&cur->children.emplace(std::string(i), Child{GIT_FILEMODE_TREE, {Directory()}}).first->second.file);
assert(child);
cur = child;
}
// Create builders for the new directories.
for (auto n = prefixLen; n < names.size(); ++n)
pushBuilder(names[n]);
};
std::string name(*path.baseName());
bool prepareDirs(const std::vector<std::string> & pathComponents, bool isDir)
{
std::span<const std::string> pathComponents2{pathComponents};
updateBuilders(isDir ? pathComponents2 : pathComponents2.first(pathComponents2.size() - 1));
return true;
if (auto prev = cur->children.find(name); prev == cur->children.end() || prev->second.id < child.id)
cur->children.insert_or_assign(name, std::move(child));
}
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> func) override
{
auto pathComponents = tokenizeString<std::vector<std::string>>(path.rel(), "/");
if (!prepareDirs(pathComponents, false))
return;
checkInterrupt();
/* Multithreaded blob writing. We read the incoming file data into memory and asynchronously write it to a Git
blob object. However, to avoid unbounded memory usage, if the amount of data in flight exceeds a threshold,
we switch to writing directly to a Git write stream. */
using WriteStream = std::unique_ptr<::git_writestream, decltype([](::git_writestream * stream) {
if (stream)
stream->free(stream);
})>;
/* Maximum file size that gets buffered in memory before flushing to a WriteStream,
that's backed by a temporary objects/streamed_git2_* file. We should avoid that
for common cases, since creating (and deleting) a temporary file for each blob
is insanely expensive. */
static constexpr std::size_t maxBufferSize = 1024 * 1024; /* 1 MiB */
struct CRF : CreateRegularFileSink
{
const CanonPath & path;
GitFileSystemObjectSinkImpl & back;
CanonPath path;
GitFileSystemObjectSinkImpl & parent;
WriteStream stream;
std::string & contents;
std::optional<decltype(parent.repoPool)::Handle> repo;
std::string contents;
bool executable = false;
CRF(const CanonPath & path, GitFileSystemObjectSinkImpl & back, std::string & regularFileContentsBuffer)
: path(path)
, back(back)
, stream(nullptr)
, contents(regularFileContentsBuffer)
CRF(CanonPath path, GitFileSystemObjectSinkImpl & parent)
: path(std::move(path))
, parent(parent)
{
contents.clear();
}
void writeToStream(std::string_view data)
~CRF()
{
/* Lazily create the stream. */
if (!stream) {
::git_writestream * stream2 = nullptr;
if (git_blob_create_from_stream(&stream2, *back.repo, nullptr))
throw Error("creating a blob stream object: %s", git_error_last()->message);
stream = WriteStream{stream2};
assert(stream);
}
if (stream->write(stream.get(), data.data(), data.size()))
throw Error("writing a blob for tarball member '%s': %s", path, git_error_last()->message);
parent.totalBufSize -= contents.size();
}
void operator()(std::string_view data) override
{
/* Already in slow path. Just write to the slow stream. */
if (stream) {
writeToStream(data);
return;
}
if (!stream) {
contents.append(data);
parent.totalBufSize += data.size();
contents += data;
if (contents.size() > maxBufferSize) {
writeToStream(contents); /* Will initialize stream. */
contents.clear();
if (parent.totalBufSize > parent.maxBufSize) {
repo.emplace(parent.repoPool.get());
if (git_blob_create_from_stream(Setter(stream), **repo, nullptr))
throw Error("creating a blob stream object: %s", git_error_last()->message);
if (stream->write(stream.get(), contents.data(), contents.size()))
throw Error("writing a blob for tarball member '%s': %s", path, git_error_last()->message);
parent.totalBufSize -= contents.size();
contents.clear();
}
} else {
if (stream->write(stream.get(), data.data(), data.size()))
throw Error("writing a blob for tarball member '%s': %s", path, git_error_last()->message);
}
}
@@ -1241,112 +1234,140 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
{
executable = true;
}
} crf{path, *this, regularFileContentsBuffer};
};
func(crf);
auto crf = std::make_shared<CRF>(path, *this);
git_oid oid;
if (crf.stream) {
/* Call .release(), since git_blob_create_from_stream_commit
func(*crf);
auto id = nextId++;
if (crf->stream) {
/* Finish the slow path by creating the blob object synchronously.
Call .release(), since git_blob_create_from_stream_commit
acquires ownership and frees the stream. */
if (git_blob_create_from_stream_commit(&oid, crf.stream.release()))
git_oid oid;
if (git_blob_create_from_stream_commit(&oid, crf->stream.release()))
throw Error("creating a blob object for '%s': %s", path, git_error_last()->message);
} else {
if (git_blob_create_from_buffer(&oid, *repo, crf.contents.data(), crf.contents.size()))
throw Error(
"creating a blob object for '%s' from in-memory buffer: %s", path, git_error_last()->message);
addNode(
*_state.lock(),
crf->path,
Child{crf->executable ? GIT_FILEMODE_BLOB_EXECUTABLE : GIT_FILEMODE_BLOB, oid, id});
return;
}
addToTree(*pathComponents.rbegin(), oid, crf.executable ? GIT_FILEMODE_BLOB_EXECUTABLE : GIT_FILEMODE_BLOB);
/* Fast path: create the blob object in a separate thread. */
workers.enqueue([this, crf{std::move(crf)}, id]() {
auto repo(repoPool.get());
git_oid oid;
if (git_blob_create_from_buffer(&oid, *repo, crf->contents.data(), crf->contents.size()))
throw Error(
"creating a blob object for '%s' from in-memory buffer: %s", crf->path, git_error_last()->message);
addNode(
*_state.lock(),
crf->path,
Child{crf->executable ? GIT_FILEMODE_BLOB_EXECUTABLE : GIT_FILEMODE_BLOB, oid, id});
});
}
void createDirectory(const CanonPath & path) override
{
auto pathComponents = tokenizeString<std::vector<std::string>>(path.rel(), "/");
(void) prepareDirs(pathComponents, true);
if (path.isRoot())
return;
auto state(_state.lock());
addNode(*state, path, {GIT_FILEMODE_TREE, Directory()});
}
void createSymlink(const CanonPath & path, const std::string & target) override
{
auto pathComponents = tokenizeString<std::vector<std::string>>(path.rel(), "/");
if (!prepareDirs(pathComponents, false))
return;
workers.enqueue([this, path, target]() {
auto repo(repoPool.get());
git_oid oid;
if (git_blob_create_from_buffer(&oid, *repo, target.c_str(), target.size()))
throw Error("creating a blob object for tarball symlink member '%s': %s", path, git_error_last()->message);
git_oid oid;
if (git_blob_create_from_buffer(&oid, *repo, target.c_str(), target.size()))
throw Error(
"creating a blob object for tarball symlink member '%s': %s", path, git_error_last()->message);
addToTree(*pathComponents.rbegin(), oid, GIT_FILEMODE_LINK);
auto state(_state.lock());
addNode(*state, path, Child{GIT_FILEMODE_LINK, oid});
});
}
std::map<CanonPath, CanonPath> hardLinks;
void createHardlink(const CanonPath & path, const CanonPath & target) override
{
std::vector<std::string> pathComponents;
for (auto & c : path)
pathComponents.emplace_back(c);
if (!prepareDirs(pathComponents, false))
return;
// We can't just look up the path from the start of the root, since
// some parent directories may not have finished yet, so we compute
// a relative path that helps us find the right git_tree_builder or object.
auto relTarget = CanonPath(path).parent()->makeRelative(target);
auto dir = pendingDirs.rbegin();
// For each ../ component at the start, go up one directory.
// CanonPath::makeRelative() always puts all .. elements at the start,
// so they're all handled by this loop:
std::string_view relTargetLeft(relTarget);
while (hasPrefix(relTargetLeft, "../")) {
if (dir == pendingDirs.rend())
throw Error("invalid hard link target '%s' for path '%s'", target, path);
++dir;
relTargetLeft = relTargetLeft.substr(3);
}
if (dir == pendingDirs.rend())
throw Error("invalid hard link target '%s' for path '%s'", target, path);
// Look up the remainder of the target, starting at the
// top-most `git_treebuilder`.
std::variant<git_treebuilder *, git_oid> curDir{dir->builder.get()};
Object tree; // needed to keep `entry` alive
const git_tree_entry * entry = nullptr;
for (auto & c : CanonPath(relTargetLeft)) {
if (auto builder = std::get_if<git_treebuilder *>(&curDir)) {
assert(*builder);
if (!(entry = git_treebuilder_get(*builder, std::string(c).c_str())))
throw Error("cannot find hard link target '%s' for path '%s'", target, path);
curDir = *git_tree_entry_id(entry);
} else if (auto oid = std::get_if<git_oid>(&curDir)) {
tree = lookupObject(*repo, *oid, GIT_OBJECT_TREE);
if (!(entry = git_tree_entry_byname((const git_tree *) &*tree, std::string(c).c_str())))
throw Error("cannot find hard link target '%s' for path '%s'", target, path);
curDir = *git_tree_entry_id(entry);
}
}
assert(entry);
addToTree(*pathComponents.rbegin(), *git_tree_entry_id(entry), git_tree_entry_filemode(entry));
hardLinks.insert_or_assign(path, target);
}
Hash flush() override
{
updateBuilders({});
workers.process();
auto [oid, _name] = popBuilder();
if (auto * backend = repo->packBackend) {
/* We are done writing blobs, can restore refresh functionality. */
backend->refresh = packfileOdbRefresh;
/* Create hard links. */
{
auto state(_state.lock());
for (auto & [path, target] : hardLinks) {
if (target.isRoot())
continue;
try {
auto child = state->root.lookup(target);
auto oid = std::get_if<git_oid>(&child.file);
if (!oid)
throw Error("cannot create a hard link to a directory");
addNode(*state, path, {child.mode, *oid});
} catch (Error & e) {
e.addTrace(nullptr, "while creating a hard link from '%s' to '%s'", path, target);
throw;
}
}
}
// Flush all repo objects to disk.
{
auto repos = repoPool.clear();
ThreadPool workers{repos.size()};
for (auto & repo : repos)
workers.enqueue([repo]() { repo->flush(); });
workers.process();
}
// Write the Git trees to disk. Would be nice to have this multithreaded too, but that's hard because a tree
// can't refer to an object that hasn't been written yet. Also it doesn't make a big difference for performance.
auto repo(repoPool.get());
[&](this const auto & visit, Directory & node) -> void {
checkInterrupt();
// Write the child directories.
for (auto & child : node.children)
if (auto dir = std::get_if<Directory>(&child.second.file))
visit(*dir);
// Write this directory.
git_treebuilder * b;
if (git_treebuilder_new(&b, *repo, nullptr))
throw Error("creating a tree builder: %s", git_error_last()->message);
TreeBuilder builder(b);
for (auto & [name, child] : node.children) {
auto oid_p = std::get_if<git_oid>(&child.file);
auto oid = oid_p ? *oid_p : std::get<Directory>(child.file).oid.value();
if (git_treebuilder_insert(nullptr, builder.get(), name.c_str(), &oid, child.mode))
throw Error("adding a file to a tree builder: %s", git_error_last()->message);
}
git_oid oid;
if (git_treebuilder_write(&oid, builder.get()))
throw Error("creating a tree object: %s", git_error_last()->message);
node.oid = oid;
}(_state.lock()->root);
repo->flush();
return toHash(oid);
return toHash(_state.lock()->root.oid.value());
}
};
@@ -1427,8 +1448,12 @@ namespace fetchers {
ref<GitRepo> Settings::getTarballCache() const
{
static auto repoDir = std::filesystem::path(getCacheDir()) / "tarball-cache";
return GitRepo::openRepo(repoDir, /*create=*/true, /*bare=*/true, /*packfilesOnly=*/true);
/* v1: Had either only loose objects or thin packfiles referring to loose objects
* v2: Must have only packfiles with no loose objects. Should get repacked periodically
* for optimal packfiles.
*/
static auto repoDir = std::filesystem::path(getCacheDir()) / "tarball-cache-v2";
return GitRepo::openRepo(repoDir, {.create = true, .bare = true, .packfilesOnly = true});
}
} // namespace fetchers
@@ -1442,7 +1467,7 @@ GitRepo::WorkdirInfo GitRepo::getCachedWorkdirInfo(const std::filesystem::path &
if (i != cache->end())
return i->second;
}
auto workdirInfo = GitRepo::openRepo(path)->getWorkdirInfo();
auto workdirInfo = GitRepo::openRepo(path, {})->getWorkdirInfo();
_cache.lock()->emplace(path, workdirInfo);
return workdirInfo;
}

View File

@@ -637,11 +637,6 @@ struct GitInputScheme : InputScheme
url);
}
// If we don't check here for the path existence, then we can give libgit2 any directory
// and it will initialize them as git directories.
if (!pathExists(path)) {
throw Error("The path '%s' does not exist.", path);
}
repoInfo.location = std::filesystem::absolute(path);
} else {
if (url.scheme == "file")
@@ -703,7 +698,7 @@ struct GitInputScheme : InputScheme
if (auto res = cache->lookup(key))
return getIntAttr(*res, "lastModified");
auto lastModified = GitRepo::openRepo(repoDir)->getLastModified(rev);
auto lastModified = GitRepo::openRepo(repoDir, {})->getLastModified(rev);
cache->upsert(key, {{"lastModified", lastModified}});
@@ -726,7 +721,7 @@ struct GitInputScheme : InputScheme
Activity act(
*logger, lvlChatty, actUnknown, fmt("getting Git revision count of '%s'", repoInfo.locationToArg()));
auto revCount = GitRepo::openRepo(repoDir)->getRevCount(rev);
auto revCount = GitRepo::openRepo(repoDir, {})->getRevCount(rev);
cache->upsert(key, Attrs{{"revCount", revCount}});
@@ -737,7 +732,7 @@ struct GitInputScheme : InputScheme
{
auto head = std::visit(
overloaded{
[&](const std::filesystem::path & path) { return GitRepo::openRepo(path)->getWorkdirRef(); },
[&](const std::filesystem::path & path) { return GitRepo::openRepo(path, {})->getWorkdirRef(); },
[&](const ParsedURL & url) { return readHeadCached(url.to_string(), shallow); }},
repoInfo.location);
if (!head) {
@@ -795,7 +790,7 @@ struct GitInputScheme : InputScheme
if (auto repoPath = repoInfo.getPath()) {
repoDir = *repoPath;
if (!input.getRev())
input.attrs.insert_or_assign("rev", GitRepo::openRepo(repoDir)->resolveRef(ref).gitRev());
input.attrs.insert_or_assign("rev", GitRepo::openRepo(repoDir, {})->resolveRef(ref).gitRev());
} else {
auto repoUrl = std::get<ParsedURL>(repoInfo.location);
std::filesystem::path cacheDir = getCachePath(repoUrl.to_string(), shallow);
@@ -805,7 +800,7 @@ struct GitInputScheme : InputScheme
std::filesystem::create_directories(cacheDir.parent_path());
PathLocks cacheDirLock({cacheDir.string()});
auto repo = GitRepo::openRepo(cacheDir, true, true);
auto repo = GitRepo::openRepo(cacheDir, {.create = true, .bare = true});
// We need to set the origin so resolving submodule URLs works
repo->setRemote("origin", repoUrl.to_string());
@@ -876,7 +871,7 @@ struct GitInputScheme : InputScheme
// the remainder
}
auto repo = GitRepo::openRepo(repoDir);
auto repo = GitRepo::openRepo(repoDir, {});
auto isShallow = repo->isShallow();
@@ -963,7 +958,7 @@ struct GitInputScheme : InputScheme
for (auto & submodule : repoInfo.workdirInfo.submodules)
repoInfo.workdirInfo.files.insert(submodule.path);
auto repo = GitRepo::openRepo(repoPath, false, false);
auto repo = GitRepo::openRepo(repoPath, {});
auto exportIgnore = getExportIgnoreAttr(input);
@@ -1003,7 +998,7 @@ struct GitInputScheme : InputScheme
}
if (!repoInfo.workdirInfo.isDirty) {
auto repo = GitRepo::openRepo(repoPath);
auto repo = GitRepo::openRepo(repoPath, {});
if (auto ref = repo->getWorkdirRef())
input.attrs.insert_or_assign("ref", *ref);

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