Compare commits

..
Author SHA1 Message Date
Alois Wohlschlager 7653f109c6 Enable nixpkgsLibTests again
The required nixpkgs bumps have now been performed.

Change-Id: I6a6a6964316f8434c355405c52b0a7b7f70b4332
2025-09-07 18:58:38 +02:00
Alois Wohlschlager 16894c7bc5 flake: update nixpkgs input
Without https://github.com/NixOS/nixpkgs/pull/434761 evaluation of the
`nixpkgsLibTests` will fail in CI with recent enough Lix, due to reliance on
the TOML integer saturation bug.

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

Change-Id: I6a6a6964838009d2c525f67035f84072fdfad988
2025-09-07 18:56:03 +02:00
594efc2e56 flake/inputs: 24.11-small -> 25.05-small
We upgrade to 25.05 release, which contains the curl commit
https://github.com/curl/curl/commit/5fbd78eb2dc4afbd8884e8eed27147fc3d4318f6
done in
https://github.com/NixOS/nixpkgs/pull/396200#issuecomment-2795944006.

This fixes HTTP transfers generating arbitrary errors and possibly
failing unusually.

Users who are already depending on 25.05-small or a recent unstable
already had the fix.

Special mention to the Linux kernel who gave me the opportunity to get
on a 24 hours bisection side quest to fix the local release engineering
test.

Special thanks to everyone who had to endure me ranting.

Change-Id: I866caf65d5ea103f1fa5eccd57df8031c9eacda0
Co-authored-by: eldritch horrors <pennae@lix.systems>
Co-authored-by: helle <helle@h3l.li>
Co-authored-by: Alois Wohlschlager <alois1@gmx-topmail.de>
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-09-07 18:46:29 +02:00
K900andAlois Wohlschlager c63eb21e8d perl: drop version check
Meson started handling those differently[0], and Perl 5.8 is old enough
that anyone running an even older Perl is honestly asking for it.

[0]: https://github.com/mesonbuild/meson/commit/a3679a64eec7c312c81d657880f34f015426c7db

Change-Id: Ifba22e38a82abf4b6965dda0eed43a3064533d25
2025-09-07 18:44:40 +02:00
Alois Wohlschlager 92cf5ac91b Disable nixpkgsLibTests temporarily
Several nixpkgs bumps up to https://github.com/NixOS/nixpkgs/pull/434761 will
be required to fix them. Disable the tests temporarily to avoid having to
squash all the backports, which would lose history.

Change-Id: I6a6a6964029a3442c4691e74a52923e3f59d6448
2025-09-07 18:41:55 +02:00
sternenseemann 88302eaaf4 libcmd: add support for lowdown >= 1.4
lowdown 1.4.0 changed the lowdown_opts to include a new and separate
lowdown_opts_term which allows for configuring values specific to
-Tterm (which we're using). This version should have been called 2.0.0
according to semver, hence 2.0.0 was released later without any actual
breaking changes to sort of migitate the problem.

We need to support lowdown >= 1.3 && < 1.4 since the ship has sailed for
updating lowdown in NixOS 25.05 as well as lowdown >= 1.4 or we'll be
stuck in Nixpkgs forever. Support for < 1.4 can be dropped as soon as
NixOS 25.05 is EOL, assuming this change lands before NixOS 25.11
branch-off.

We detect the changed API based on the lowdown version from pkg-config
and define LOWDOWN_SEPARATE_TERM_OPTS based on that. The ifdef is named
according to the specific API change that impacts us, so that it's
hopefully a little simpler to maintain going forward. In the new API,
all newly configurable settings use what would have been the (implicit)
default before. Changing some of these values, especially hpadding,
could be interesting in future changes.

Compared to cl/3081, this change makes sure to initialize all new fields
of lowdown_opts_term explicitly.

It seems that, while making -Tterm more configurable, lowdown's word
wrapping behavior changed slightly which broke basic_repl.test. I've
chosen to work around this by using builtins.add as an example which has
a very short documentation string, so wrapping doesn't matter.

Change-Id: Id73be4c0e43d7eb4f56e10a261b4254402698ff8
(cherry picked from commit 858de5f47a)
2025-07-23 23:42:28 +02:00
Jade Lovelace 4601564996 fix: VERSION_SUFFIX was not getting into meson
It was a regression caused by switching to structured attrs, I think.

Fixes: https://git.lix.systems/lix-project/lix/issues/908
Change-Id: Ia62892919945a1f16a81a2e0bb585595fac46669
(cherry picked from commit ae00b12983)
2025-07-20 21:31:20 +00:00
K900andjade 4015082602 packaging: use structuredAttrs
staging-next banned !structuredAttrs && separateDebugInfo && disallowedRequisites
due to weird output interactions. Enable structuredAttrs so we can build again.

Also, fix type confusion that makes stdenv explode (https://github.com/NixOS/nixpkgs/issues/422989).

Co-authored-by: eldritch horrors <pennae@lix.systems>
Change-Id: Ic0c773394ee79e10d427f27750d59892d6d1f1d1
(cherry picked from commit 378b360bf8)
2025-07-20 21:31:20 +00:00
eldritch horrors a91e28009f libstore: weaken tmpdir root access mode
libarchive *should* not break with 0710 on the tmpdir root on darwin,
just like it doesn't break on linux, but for some reason it does. the
restriction to 0710 can be weakened to 0750 with causing any trouble.

fixes #921

Change-Id: Ia9fc2f8eb9695fc19cefae9857368d5a4e58c8b9
2025-07-20 16:52:55 +00:00
eldritch horrorsandRaito Bezarius c698466dc7 libstore: add intermediate directory to build-dirs
this makes the actual build directories used by builders invisible and
inaccessible to other processes on the system, avoiding another vector
for outside processes to interfere with builds or pass credentials the
build sandbox should not have access to into the build sandbox anyway.

fixes #919

Change-Id: Ifaa4d8e3940cfde1406e925f75c1375d2e86d81a
(cherry picked from commit 9d5a5c4dc0)
2025-07-18 03:41:44 +02:00
Raito Bezarius f10ca0d677 release: merge release 2.92.3 back to mainline
This merge commit returns to the previous state prior to the release but leaves the tag in the branch history.
Release created with releng/create_release.xsh

Change-Id: I90d92d46de3073797e659b16cbc4eb6671d84cf4
2025-06-30 00:59:27 +02:00
Raito Bezarius 8c5e1c8f63 release: 2.92.3 "Bombe glacée"
Release produced with releng/create_release.xsh

Change-Id: If52727313f7f9a0dd4ce6c95dccfeb33585eac0a
2025-06-30 00:59:27 +02:00
Raito Bezarius fe090a7b9b release: release notes for 2.92.3
Release created with releng/create_release.xsh

Change-Id: I7683080179723ab8e36206c511c1e8819250fe5f
2025-06-30 00:59:26 +02:00
Raito Bezarius 4a3983906f version: 2.92.2 -> 2.92.3
Resolves critical correctness bugs as reported in fj#883.
Following the CVE fixes.

Change-Id: Ife85fb4ca71ba920aae4b98a6dc141857e10d759
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-29 20:36:57 +00:00
EmilyandRaito Bezarius bac0d67928 libstore: fix Unix sockets in the build directory on sandboxed macOS
We’re already allowing `/tmp` anyway, so this should be harmless,
and it fixes a regression in the default configuration caused by
moving the build directories out of `temp-dir`. (For instance, that
broke the Lix `guessOrInventPath.sockets` test.)

Note that removing `/tmp` breaks quite a few builds, so although it may
be a good idea in general it would require work on the Nixpkgs side.

Fixes: 749afbbe99
Change-Id: I6a6a69645f429bc50d4cb24283feda3d3091f534
(cherry picked from commit d1db3e5fa3)
2025-06-29 20:36:57 +00:00
Raito Bezarius 22a1d233bb libstore: fallback on creating a safe space in the default tempdir
If `settings.buildDir` cannot be written to, because we are in a chroot
store, unprivileged or anything.

We can and should always gracefully fallback to a *secure* location
inside of /tmp, i.e. `/tmp/<a directory under 0700>/<our temporary
directory for build under 0700>/...`.

This does not reintroduce CVE-2025-52991 because we are creating a
directory in-between compared to creating only ONE level of directory.

Under macOS, the first level of directory has actually mode 0755 instead
of 0700 as macOS often do not possess the right primitives to chroot
inside of these directories, leading to
https://github.com/NixOS/nix/pull/11031.

Thanks to Emily for the heads-up on this type of matter.

Fixes #876.

Change-Id: Ie521202923f763225e1901ab1b9b6c6132aaf548
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-29 20:36:57 +00:00
eldritch horrors 4901a6cda9 Revert "libstore/build: automatic clean up of unsuccessfully built scratch outputs"
This reverts commit 2f32368136 as this is the root cause for the critical correctness bug.

Change-Id: I573cdfbaed8316ad93197aab621ad7e3ff966c1d
2025-06-29 20:36:57 +00:00
eldritch horrors 8cbdc36a60 Revert "libstore: fix scratch output cleanup"
This reverts commit 1d36dd7596 as this is an insufficient fix for the critical correctness bug.

Change-Id: Id48fec6e2146ccc98edb39629d9944404a17ba8c
2025-06-29 20:36:57 +00:00
eldritch horrors 56b0b39465 Revert "libstore: don't delete already valid outputs after build"
This reverts commit 99456a0c7e as this is an insufficient fix for the critical correctness bug.

Change-Id: I950b4d007f4919877df6dd9eef5d6c1e95ca270e
2025-06-29 20:15:29 +00:00
Raito Bezarius 438e1839f1 releng: go back to a non-official release
This is necessary to unblock releng.

This is suboptimal releng because we usually merge the branches back and
the releng script did not.

Change-Id: I12c9f6713adf344c1597e2d4adafaf2d3c62f537
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-27 23:17:38 +02:00
eldritch horrors 99456a0c7e libstore: don't delete already valid outputs after build
eagerly consider outputs as not needing deletion during output
registration rather than only doing so after registration. not
waiting for registration to succeed may keep store paths alive
in the file system if registration fails for some reason; that
seem preferrable to the possibility of having another instance
of this bug. since we only leave *good* outputs around there's
not much to worry about except maybe bit of wasted disk space.

fixes #883

Change-Id: I8c22c92e39b9e203f1061278f86cde19dc4474a4
2025-06-27 16:35:53 +02:00
eldritch horrors 1d36dd7596 libstore: fix scratch output cleanup
the daemon must use real store paths, not virtual store paths. using
virtual paths may inadvertently delete paths in the system nix store
when a build was run on a redirected store as root, which isn't good

Change-Id: Id048b236bda0e0ab1f3be6ccba0ddc1de2a3e941
2025-06-27 16:35:04 +02:00
Raito Bezarius 21317ce965 release: 2.92.2 "Bombe glacée"
Release produced with releng/create_release.xsh

Change-Id: I43476413ebe28aa60618f24205fdda9a3a92902c
2025-06-24 10:50:36 +00:00
Raito Bezarius b43a289c02 release: release notes for 2.92.2
Release created with releng/create_release.xsh

Change-Id: I9bcc8bec834ebf9b2d0ec9df00a585b610152ba8
2025-06-24 10:50:36 +00:00
Raito Bezarius 2138b0f7e9 version: 2.92.1 -> 2.92.2
Fixes CVE-2025-46415, CVE-2025-46416, CVE-2025-52991, CVE-2025-52992,
and CVE-2025-52993.

Change-Id: Ia73b43abd1cf2d0cfa185938c59d3a836a9eb160
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-24 10:50:36 +00:00
Raito Bezarius 2f32368136 libstore/build: automatic clean up of unsuccessfully built scratch outputs
When a build fails, its scratch output paths are not cleaned up.

Until recently, this was deemed not a problem but as part of the effort
to harden the Nix builds and protect these paths against being part of a
staged attack (race conditions, etc.), we automatically cleanup after
failed builds.

Fixes CVE-2025-52992.

Change-Id: I58481b1cc83826298b9d80d37fecf81f117ccb09
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-24 10:50:36 +00:00
eldritch horrorsandRaito Bezarius a713c064af libstore: don't default build-dir to temp-dir
if a build directory is accessible to other users it is possible to
smuggle data in and out of build directories. usually this ins only
a build purity problem, but in combination with other issues it can
be used to break out of a build sandbox. to prevent this we default
to using a subdirectory of nixStateDir (which is more restrictive).

Fixes CVE-2025-52991.

Change-Id: Iacfc9b50534de158618c815f9fb99d7dae1be4d0
2025-06-24 10:50:36 +00:00
cba05329ee libstore: use pasta for FODs if available
This allows using a userspace program, pasta, to handle comms between
the build sandbox, and the outside world; allowing for full isolation
including the network namespace, closing the "fixed-output derivation
talks to the host over an abstract domain socket" hole for good.

Fixes CVE-2025-46416.

Co-Authored-By: Puck Meerburg <puck@puckipedia.com>
Change-Id: Ifd499b7dbb3784600a6e842fede65fc031ff9f15
2025-06-24 10:50:36 +00:00
eldritch horrors f5f2e1537d libutil: add capability support to runProgram2
launching pasta to not run as root will ambient require capabilities.

Change-Id: I1dd2506a1fa3944a9d9062123ef8a74903c597ea
2025-06-24 10:50:36 +00:00
eldritch horrors 0ea8649445 libutil: add generic redirections runProgram2
explicit stderr redirection makes mergeStderrToStdout unnecessary also.

Change-Id: I63de929e6dc53f6c5ceb2d43c2ce288bfc04d872
2025-06-24 10:50:36 +00:00
eldritch horrors d0678a57f9 libutil: make RunningProgram more useful
make it moveable, make it killable, and add a stdout fd accessor.

Change-Id: I2387cbe8ac67b899a322cd6c7d306ef9ea7abcd0
2025-06-24 10:50:36 +00:00
Raito Bezarius 1d4ddb7e3b libutil: ensure that _deletePath does NOT use absolute paths with dirfds
When calling `_deletePath` with a parent file descriptor, `openat` is
made effective by using relative paths to the directory file descriptor.

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

Fixes CVE-2025-46415.

Change-Id: I6b3fc766bad2afe54dc27d47d1df3873e188de96
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-24 10:50:36 +00:00
Raito Bezarius c7867e89f9 libstore: ensure that passAsFile is created in the original temp dir
This ensures that `passAsFile` data is created inside the expected
temporary build directory by `openat()` from the parent directory file
descriptor.

Fixes CVE-2025-52993.

Change-Id: Ie5273446c4a19403088d0389ae8e3f473af8879a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-24 10:45:29 +00:00
Raito Bezarius deb5150c82 libutil: writeFile variant for file descriptors
`writeFile` lose its `sync` boolean flag to make things simpler.

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

Change-Id: Ib871a5283a9c047db1e4fe48a241506e4aab9192
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-23 16:50:44 +02:00
Raito Bezarius 92eb418a59 libstore: chown to builder variant for file descriptors
We use it immediately for the build temporary directory.

Change-Id: I180193c63a2b98721f5fb8e542c4e39c099bb947
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-23 16:50:44 +02:00
Raito Bezarius 7fceee3ce3 libstore: open build directory as a dirfd as well
We now keep around a proper AutoCloseFD around the temporary directory
which we plan to use for openat operations and avoiding the build
directory being swapped out while we are doing something else.

Change-Id: I18d387b0f123ebf2d20c6405cd47ebadc5505f2a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-23 16:50:44 +02:00
Raito Bezarius 31f976dc19 libutil: guess or invent a path from file descriptors
This is useful for certain error recovery paths (no pun intended) that
does not thread through the original path name.

Change-Id: I2d800740cb4f9912e64c923120d3f977c58ccb7e
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-23 16:50:44 +02:00
jadeandLix Systems Gerrit d8db15010d Merge changes I577bdc15,I1c5f7a5c,I75f56c80 into release-2.92
* changes:
  version: 2.92.1
  release-notes: note the flake.lock fix
  libexpr/flake: user friendly error if parsing flake.lock fails
2025-03-17 22:26:40 +00:00
Jade Lovelace 253be7d2ba version: 2.92.1
Change-Id: I577bdc1549e80c0b7621624e2d390153581b3bf2
2025-03-17 12:11:24 -07:00
Jade Lovelace a34e583305 releng: workaround awscli breaking garage by changing checksum algo
CHERRY-PICK: required to release

We use https://garagehq.deuxfleurs.fr for https://docs.lix.systems,
https://releases.lix.systems, https://cache.lix.systems. It's generally
great, but AWS doesn't, erm, care, about other implementations and broke
their client library.

We already ran into
https://git.deuxfleurs.fr/Deuxfleurs/garage/issues/824, which was
mitigated by a garage upgrade to create a new error. These bugs were
what got us:
- https://github.com/boto/boto3/issues/4392
- https://github.com/aws/aws-cli/issues/9214

Error:
upload failed: release/manual/.nojekyll to s3://docs/manual/lix/nightly/.nojekyll An error occurred (InvalidRequest) when calling the PutObject operation: Bad request: invalid checksum algorithm

The missing checksum algorithm is CRC32NVME, with a bug filed here:
https://git.deuxfleurs.fr/Deuxfleurs/garage/issues/963

Change-Id: Ib78a89034bf0f2a6773fc505a347b2aadb775e93
(cherry picked from commit 0f4c5b3b8a)
2025-03-17 19:10:24 +00:00
Rebecca Turnerandjade a8fb008106 releng: use aws s3 sync --delete when uploading manual
CHERRY-PICK: prereq to fixing the aws flags for garage shenanigans

For the user manual, we don't delete things that are missing when doing
aws s3 sync. This doesn't seem wise. If you delete a page in the manual,
it will stay public and visible.

This adds `--delete` to the `aws s3 sync` commands to fix this issue.

Closes #396

Change-Id: I6d7fb97bcdab96c0115d6c66fea0310125207df4
(cherry picked from commit 16df34b295)
2025-03-17 19:09:10 +00:00
Jade Lovelace 32cbb66a69 release-notes: note the flake.lock fix
Change-Id: I1c5f7a5cba12da1bfb2896ffc04ec89862cb346d
2025-03-17 12:06:39 -07:00
giliceandjade 9631e9a30f libexpr/flake: user friendly error if parsing flake.lock fails
CHERRY-PICK: repeated bug reports

Fix: https://git.lix.systems/lix-project/lix/issues/559
Change-Id: I75f56c801d7f16a2e1ef8e702f16f1ef91f7b01f
(cherry picked from commit 68373f8664)
2025-03-17 19:01:23 +00:00
jadeandLix Systems Gerrit 98772c4a3b Merge "Revert "libstore: don't use curl decompression support"" into release-2.92 2025-03-17 18:17:41 +00:00
jadeandLix Systems Gerrit a7fd5c3867 Merge "libexpr: fix checkSourcePath purity regression" into release-2.92 2025-03-17 17:58:29 +00:00
jadeandLix Systems Gerrit 6f3a7bbeb0 Revert "libstore: don't use curl decompression support"
This reverts commit 0d1f794178.

Reason for revert: pennae says it makes the bug more visible, for some unknown reason. See https://git.lix.systems/lix-project/lix/issues/662

Change-Id: I91853cb6645f188a260c4c71cfff4de7bea99feb
2025-03-17 17:56:20 +00:00
eldritch horrorsandjade 0d1f794178 libstore: don't use curl decompression support
it's broken with http2 and transfer flow control. cf fj#662

BACKPORT: due to regression
Change-Id: Iaf6312bfcefa18d168faef47f57481199dd30b8d
2025-03-09 08:39:10 +00:00
Alois Wohlschlager ef5689dc1b libexpr: fix checkSourcePath purity regression
Starting with commit 0dbfa7b26e access would also
be allowed to ancestors of allowed paths. This is (ironically) a significant
purity regression, since several users of the purity checks will themselves
assume that arbitrary descent is allowed. For example, `builtins.readDir` and
`builtins.path` could now refer to the filesystem root, breaking purity
entirely in the latter case by allowing to read arbitrary files. Restore the
previous behaviour of only allowing access to explicitly allowed paths.

Change-Id: Ie64180733ab735da9873255e1ccbf95ba7c9161c
(cherry picked from commit 9d99a7c2cf)
2025-03-04 18:15:15 +01:00
Lunaphiedandjade db55ca9a2e hotfix for releng scripts, fixes #440
Change-Id: I33b29fbf3920a2d4fb53b58db477dff5bf7a1af1
2025-02-21 01:17:44 +00:00
eldritch horrorsandJade Lovelace 4cd618272a libstore: never return from lockFile without a lock
signals could cause lockFile to return without having locked the file.
the garbage collector didn't check for this, and then hilarity ensued.

Change-Id: If86d33595e8bf5510d2b032139342261dc6e07c9
(cherry picked from commit d186064c3d)
2025-02-09 12:54:48 -08:00
eldritch horrorsandJade Lovelace 73f0213500 libstore: split tryLockFile lockFile
lockFile is currently interruptible by signals like SIGCHLD. which
happen a lot in daemons. now imagine that daemon enabled automatic
garbage collection. observe that the local store does not actually
check whether its lock operations have succeeded ... get the idea?

Change-Id: Ibfd7ee786c4fee3add72d4456a7e95e73e09c73e
(cherry picked from commit 79f9c39e36)
2025-02-09 12:54:48 -08:00
eldritch horrorsandJade Lovelace 9c1db3cd8b libstore: extract unlockFile from lockFile
propagating the "unlock" lock type through this high-level api is
nonsense. it doesn't make sense to treat locking and unlocking as
similar operations; unlocking *must* not not interruptible by our
checkInterrupt machinery or it will just leave locks lying around
for a potentially very long time. unlock operations should not be
taking long enough to *want* them interrupted anyway. even on nfs
this makes very little sense because nfs waits *uninterruptibly*.

Change-Id: I10d605c8fe6c651bee64466eee1f8e20251d39f4
(cherry picked from commit aa87c8aa93)
2025-02-09 12:54:48 -08:00
Dusk Banksandeldritch horrors 5fa27057b2 libexpr: fix --debugger --ignore-try
a65e9e5828 did not inform `tryEval` that
(as far as it's concerned) `state.debug` moved to `state.errors.debug`
and changed types. this resulted in the REPL erroneously coming up, that
REPL having a non-debug state, and segfaulting after that REPL exited.

it's probably good that `state.debug` isn't mutated by `--ignore-try`
anymore.

Change-Id: I1918e93edacd626452aa423fc2eb825080738835
Fixes: a65e9e5828 ("libexpr: extract eval error creation into new type")
Signed-off-by: Dusk Banks <me@bb010g.com>
(cherry picked from commit 6a583136b7)
2025-01-31 12:36:14 +00:00
Dusk Banksandeldritch horrors d2b1af70ee doc: add bb010g to change-authors
Change-Id: Iddd3c21b2c42669cec394ac6b80f4e766e4cb81c
Signed-off-by: Dusk Banks <me@bb010g.com>
(cherry picked from commit 050cf17307)
2025-01-31 03:21:44 +00:00
Raito Bezariusandjade 50def3fa73 fix(gc): log sudden "path in use" exceptions and recover during GC gracefully
Original-Author: picnoir <picnoir@alternativebit.fr>

Inspired from
https://github.com/NixOS/nix/pull/11922/commits/ced8d311a593fcf9c3823e4e118474ac132d8e60
and adapted for Lix needs.

TL;DR: The topological sort should ensure that it is possible to delete
the path iterated upon. Nonetheless, in some cases,
`invalidatePathChecked` can still throw `PathInUse`, the exception
bubbles up and cancel the garbage collection procedure, leaving the rest
of the paths untouched. This change ensure that the error is logged for
further investigation but doesn't prevent the GC to continue when it
can.

After code review, we decided to make it a `printInfo` to inform the
user about sudden "in use" dependencies during garbage collection and
let them re-run garbage collection if they care about this.

References: https://github.com/NixOS/nix/issues/11923
References: https://git.lix.systems/lix-project/lix/issues/621
Change-Id: I5606c9afd16b5faa747b713fde2dc24016990ba3
Signed-off-by: Raito Bezarius <raito@lix.systems>
(cherry picked from commit 6a41dae49a)
2025-01-23 06:04:00 +00:00
eldritch horrorsandjade 8e2ab5532c FileTransfer: fix race condition on awaitData
There's a race condition where awaitData could early-return for data
coming from a 404 response or similar and thus not rethrow the exception
that is forthcoming, and a related race during transfer setup (which
could retry a transfer *twice* per retry round).

This would then cause substitution failures like below since the exception
isn't caught in HttpBinaryCacheStore::getFile as intended, but instead
by an exception handler downstream of `drain()` which would error out
the entire operation.

Symptom:

 » nix-build ./docs-service.nix -o "docs-service-result"
error: unable to download 'https://cache.nixos.org/7mr3fy8w66gi5inmf0jkkkl90lxy4jyg.narinfo': HTTP e
rror 404 ()

       response body:

This is kind of a hack in how it is implemented: it assumes that you
can't intentionally be receiving a large unsuccessful response since in
such a case, `awaitData` will wait for finish() to be called to throw an
exception and will never escape until the download finishes, while
continuing to buffer the entire response into memory, which could be bad
if an error response had a large payload.

That said, nobody is sending Lix 1GiB of 404, so meh I guess, and this
is how it is seemingly intended to work. That was a design flaw of the
thing before any of the Lix team got our paws on it.

I tested this by adding _exit(0) inside the expected exception catch and
then running the offending command repeatedly to see if the symptom ever
appeared again, and it did not.

Needs cherry-pick to 2.92 and a 2.92.1 release once reviewed.

Fixes: https://git.lix.systems/lix-project/lix/issues/635
Co-Authored-By: lix@jade.fyi
Change-Id: If54f6eeaad60b5ca9d5b77d4d9232da1d295e7d1
(cherry picked from commit de58cd6e80)
2025-01-22 21:06:58 +00:00
1458 changed files with 22727 additions and 44447 deletions
-4
View File
@@ -18,10 +18,6 @@ Checks:
- -bugprone-branch-clone
# extremely noisy before clang 19: https://github.com/llvm/llvm-project/issues/93959
- -bugprone-multi-level-implicit-pointer-conversion
# we don't compile out our asserts
- -bugprone-assert-side-effect
# FIXME(jade): figure out if this warning is any good
- -bugprone-exception-escape
# all thrown exceptions must derive from std::exception
- hicpp-exception-baseclass
# capturing async lambdas are dangerous
-4
View File
@@ -33,7 +33,3 @@ max_line_length = 0
[meson.build]
indent_style = space
indent_size = 2
[*.json]
indent_style = space
indent_size = 4
-2
View File
@@ -39,5 +39,3 @@ buildtime.bin
# Python compiled files from the code generators and test suite
*.pyc
**/.idea
Generated
+3 -3
View File
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3
[[package]]
name = "countme"
@@ -47,9 +47,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "rnix"
version = "0.12.0"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f15e00b0ab43abd70d50b6f8cd021290028f9b7fdd7cdfa6c35997173bc1ba9"
checksum = "bb35cedbeb70e0ccabef2a31bcff0aebd114f19566086300b8f42c725fc2cb5f"
dependencies = [
"rowan",
]
-26
View File
@@ -1,26 +0,0 @@
# Docs
per-file README.md=*
per-file CONTRIBUTING.md=*
# DevX
per-file justfile=*
per-file .envrc=*
per-file .gitignore=*
per-file .github=*
per-file .mailmap=*
# Build
per-file meson.build=*
per-file meson.options=*
per-file flake.nix=*
per-file flake.lock=*
per-file *.nix=*
per-file Cargo.lock=*
per-file Cargo.toml=*
per-file version.json=*
# Code style
per-file .clang-tidy=*
per-file .clang-format=*
per-file .editorconfig=*
per-file treefmt.toml=*
+1 -4
View File
@@ -17,13 +17,10 @@ For systems that **already have a Nix implementation installed**, such as NixOS
## Building And Developing
See our [Hacking guide](https://git.lix.systems/lix-project/lix/src/branch/main/doc/manual/src/contributing/hacking.md) in our manual for instruction on how to set up a development environment and build Lix from source.
See our [Hacking guide](https://git.lix.systems/lix-project/lix/src/branch/main/doc/manual/src/contributing/hacking.md) in our manual for instruction on how to to set up a development environment and build Lix from source.
## Additional Resources
- The Lix reference manual:
- [Stable](https://docs.lix.systems/manual/lix/stable/)
- [Nightly](https://docs.lix.systems/manual/lix/nightly/) (NOTE: [not automatically updated, yet](https://git.lix.systems/lix-project/lix/issues/742))
- [Our wiki](https://wiki.lix.systems)
- [Matrix - #space:lix.systems](https://matrix.to/#/#space:lix.systems)
-1
View File
@@ -1,4 +1,3 @@
bench-*.json
bench-*.md
perf-*.json
nixpkgs
-1
View File
@@ -1 +0,0 @@
*
-237
View File
@@ -1,237 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 -p hyperfine -p "if stdenv.isLinux then linuxPackages.perf else null"
import argparse
import subprocess
import os
import json
import tempfile
import platform
import shlex
import textwrap
import dataclasses
flake_args = ["--extra-experimental-features", "nix-command flakes"]
cases = {
"search": lambda build: [
f"{build}/bin/nix",
*flake_args,
"search",
"--no-eval-cache",
"github:nixos/nixpkgs/e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870",
"hello",
],
"rebuild": lambda build: [
f"{build}/bin/nix",
*flake_args,
"eval",
"--raw",
"--impure",
"--expr",
textwrap.dedent("""
(import <nixpkgs/nixos> {
configuration = ./bench/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma6.nix;
}).config.system.build.toplevel
""").replace("\n", " "),
],
"rebuild_lh": lambda build: [
"GC_INITIAL_HEAP_SIZE=10g",
*cases['rebuild'](build),
],
"parse": lambda build: [
f"{build}/bin/nix",
*flake_args,
"eval",
"-f",
"bench/nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix",
],
}
arg_parser = argparse.ArgumentParser()
# FIXME(jade, gilice): it is a reasonable use case to want to run a benchmark run
# on just one build. However, since we are using hyperfine in comparison
# mode, we would have to combine the JSON ourselves to support that, which
# would probably be better done by writing a benchmarking script in
# not-bash.
arg_parser.add_argument(
'builds',
nargs='+',
help="At least two build directories to compare, containing bin/nix",
)
arg_parser.add_argument(
'--cases',
type=str,
help="A comma-separated list of cases you want to run. Defaults to running all",
)
arg_parser.add_argument(
'--mode',
nargs='+',
choices=[ "walltime", "memory" ] + [ "icount" ] if platform.system() == 'Linux' else [], # perf doesn't run on Darwin
default=[ "walltime" ],
)
arg_parser.add_argument(
'--daemon',
action='store_true',
help='Run a temporary daemon for the benchmark instead of using a local store directly',
)
args = arg_parser.parse_args()
if len(args.builds) < 1:
raise ValueError("need at least one build directory to benchmark")
benchmarks: list[str] = []
if args.cases is None:
benchmarks = list(cases.keys())
else:
for case in args.cases.split(","):
if case not in cases:
raise ValueError(f"no such case: {case}")
benchmarks.append(case)
def make_full_command(build, case):
cmd = " ".join(map(shlex.quote, cases[case](build)))
if args.daemon:
return " ".join([
f"{build}/bin/nix --extra-experimental-features nix-command daemon &",
"trap 'kill %1' EXIT;",
f"NIX_REMOTE=daemon {cmd}",
])
else:
return cmd
def bench_walltime(env):
for case in benchmarks:
for build in args.builds:
subprocess.run([
"taskset", "-c", "2,3",
"chrt", "-f","50",
*[
"hyperfine", "--warmup", "2", "--runs", "10",
"--export-json", f"bench/bench-{case}-{build}.json",
"--export-markdown", f"bench/bench-{case}-{build}.md",
"--", make_full_command(build, case),
],
], env=env, check=True)
print("Benchmarks summary\n---\n")
for case in benchmarks:
results = []
for build in args.builds:
with open(f"bench/bench-{case}-{build}.json") as fd:
results.append(json.load(fd)["results"][0])
for result in results:
print(result["command"])
print("-" * min(80,len(result["command"])))
def attr_rounded(attr):
return f"{result[attr]:.3f}"
print(" mean: ", attr_rounded("mean"), "±", attr_rounded("stddev"))
print(" user:", attr_rounded("user"), "| system", attr_rounded("system"))
print(" median: ", attr_rounded("median"))
print(" range: ", attr_rounded("min") + "s.." + attr_rounded("max")+"s")
print(" relative:", f"{result["mean"]/results[0]["mean"]:.3f}")
print("\n")
def bench_icount(env):
perf_results_for: dict[str, list[tuple[str, float]]] = {}
for case in benchmarks:
for build in args.builds:
# the perf stat -j output (incorrectly) localizes numbers, which will trip up the json parser.
env["LC_ALL"]="C"
case_command = make_full_command(build, case)
commandline = [
"perf", "stat", "-o", f"bench/perf-{case}.json", "-j",
"sh", "-c", case_command,
]
print("running", case_command)
subprocess.run(commandline, env=env, check=True, stdout=subprocess.DEVNULL) # warmup run
subprocess.run(commandline, env=env, check=True, stdout=subprocess.DEVNULL)
perf_fd = open(f"bench/perf-{case}.json")
perf_data = [json.loads(x) for x in perf_fd.readlines()]
perf_fd.close()
instr = next(x for x in perf_data if x["event"] in ["instructions", "instructions:u"]) # an implementation of a find_first iterator
if case not in perf_results_for:
perf_results_for[case] = []
perf_results_for[case].append((case_command, float(instr["counter-value"])))
print("Benchmarks summary\n---\n")
for (case, entries) in perf_results_for.items():
for entry in entries:
cmd,instr = entry
print(cmd)
print("-" * min(80,len(cmd)))
print(" instructions: ", int(instr))
print(" relative instructions:", int(instr)/perf_results_for[case][0][1])
print("\n")
@dataclasses.dataclass
class MemoryStatistics:
envBytes: int
listBytes: int
setBytes: int
valueBytes: int
heapBytes: int
heapSize: int
def bench_memory(env):
path = "bench/bench-memory.json"
env = env | {
'NIX_SHOW_STATS': '1',
'NIX_SHOW_STATS_PATH': path,
}
results: dict[str, list[tuple[str, MemoryStatistics]]] = {}
for case in benchmarks:
for build in args.builds:
case_command = make_full_command(build, case)
commandline = [ "sh", "-c", case_command ]
print("running", case_command)
subprocess.run(commandline, env=env, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
with open(path) as fd:
stats = json.load(fd)
results.setdefault(case, []).append((case_command, MemoryStatistics(
envBytes=stats['envs']['bytes'],
listBytes=stats['list']['bytes'],
setBytes=stats['sets']['bytes'],
valueBytes=stats['values']['bytes'],
heapSize=stats['gc']['heapSize'],
heapBytes=stats['gc']['totalBytes'],
)))
print("Benchmarks summary\n---\n")
for (case, entries) in results.items():
for cmd, stats in entries:
print(cmd)
print("-" * min(80, len(cmd)))
print(f" env bytes: {stats.envBytes :15d} | {(stats.envBytes / entries[0][1].envBytes) :.3f}x")
print(f" list bytes: {stats.listBytes :15d} | {(stats.listBytes / entries[0][1].listBytes) :.3f}x")
print(f" set bytes: {stats.setBytes :15d} | {(stats.setBytes / entries[0][1].setBytes) :.3f}x")
if not entries[0][1].valueBytes:
print(f" value bytes: {0:15d}")
else:
print(f" value bytes: {stats.valueBytes:15d} | {(stats.valueBytes / entries[0][1].valueBytes):.3f}x")
print(f" heap alloc'd: {stats.heapBytes :15d} | {(stats.heapBytes / entries[0][1].heapBytes) :.3f}x")
print(f" heap size: {stats.heapSize :15d} | {(stats.heapSize / entries[0][1].heapSize) :.3f}x")
print("\n")
with tempfile.TemporaryDirectory() as tmp_dir:
subprocess.run([
"nix", "build",
"--extra-experimental-features", "nix-command flakes",
"--impure", "--expr",'(builtins.getFlake "git+file:.").inputs.nixpkgs.outPath',
"-o","bench/nixpkgs"
], check=True)
subenv = os.environ.copy()
subenv["NIX_CONF_DIR"] = "/var/empty"
subenv["NIX_REMOTE"] = tmp_dir
subenv["NIX_PATH"] = ":".join([
"nixpkgs=bench/nixpkgs",
])
subenv["NIX_DAEMON_SOCKET_PATH"] = f"{tmp_dir}/daemon"
for mode in args.mode:
if mode == "walltime":
bench_walltime(subenv)
elif mode == "memory":
bench_memory(subenv)
else:
bench_icount(subenv)
Executable
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash -p hyperfine
set -euo pipefail
shopt -s inherit_errexit
scriptdir=$(cd "$(dirname -- "$0")" ; pwd -P)
cd "$scriptdir/.."
if [[ $# -lt 2 ]]; then
# FIXME(jade): it is a reasonable use case to want to run a benchmark run
# on just one build. However, since we are using hyperfine in comparison
# mode, we would have to combine the JSON ourselves to support that, which
# would probably be better done by writing a benchmarking script in
# not-bash.
echo "Fewer than two result dirs given, nothing to compare!" >&2
echo "Pass some directories (with names indicating which alternative they are) with bin/nix in them" >&2
echo "Usage: ./bench/bench.sh result-1 result-2 [result-3...]" >&2
exit 1
fi
_exit=""
trap "$_exit" EXIT
flake_args=("--extra-experimental-features" "nix-command flakes")
# XXX: yes this is very silly. flakes~!!
nix build "${flake_args[@]}" --impure --expr '(builtins.getFlake "git+file:.").inputs.nixpkgs.outPath' -o bench/nixpkgs
# We must ignore the global config, or else NIX_PATH won't work reliably.
# See https://github.com/NixOS/nix/issues/9574
export NIX_CONF_DIR='/var/empty'
export NIX_REMOTE="$(mktemp -d)"
_exit='rm -rfv "$NIX_REMOTE"; $_exit'
export NIX_PATH="nixpkgs=bench/nixpkgs:nixos-config=bench/configuration.nix"
builds=("$@")
flake_args="${flake_args[*]@Q}"
hyperfineArgs=(
--parameter-list BUILD "$(IFS=,; echo "${builds[*]}")"
--warmup 2 --runs 10
)
declare -A cases
cases=(
[search]="{BUILD}/bin/nix $flake_args search --no-eval-cache github:nixos/nixpkgs/e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870 hello"
[rebuild]="{BUILD}/bin/nix $flake_args eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system'"
[rebuild-lh]="GC_INITIAL_HEAP_SIZE=10g {BUILD}/bin/nix eval $flake_args --raw --impure --expr 'with import <nixpkgs/nixos> {}; system'"
[parse]="{BUILD}/bin/nix $flake_args eval -f bench/nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix"
)
benches=(
rebuild
rebuild-lh
search
parse
)
for k in "${benches[@]}"; do
taskset -c 2,3 \
chrt -f 50 \
hyperfine "${hyperfineArgs[@]}" --export-json="bench/bench-${k}.json" --export-markdown="bench/bench-${k}.md" "${cases[$k]}"
done
echo "Benchmarks summary (from ./bench/summarize.jq bench/bench-*.json)"
bench/summarize.jq bench/*.json
+314
View File
@@ -0,0 +1,314 @@
{
config,
pkgs,
lib,
...
}:
{
boot = {
initrd = {
availableKernelModules = [
"xhci_pci"
"ahci"
];
kernelModules = [ "dm-snapshot" ];
luks.devices = {
croot = {
device = "/dev/sdb";
allowDiscards = true;
};
};
};
kernelModules = [ "kvm-intel" ];
kernelPackages = pkgs.linuxPackages_latest;
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
};
hardware = {
enableRedistributableFirmware = true;
cpu.intel.updateMicrocode = true;
graphics.enable32Bit = true;
graphics.extraPackages = with pkgs; [
vaapiIntel
intel-media-driver
intel-compute-runtime
];
};
fileSystems = {
"/" = {
device = "/dev/sda2";
fsType = "xfs";
options = [ "noatime" ];
};
"/boot" = {
device = "/dev/sda1";
fsType = "vfat";
};
"/nas" = {
device = "nas:/";
fsType = "nfs4";
options = [
"ro"
"x-systemd.automount"
];
};
};
swapDevices = [ { device = "/dev/swap"; } ];
networking = {
useDHCP = false;
hostName = "host";
wireless = {
enable = true;
interfaces = [ "eth1" ];
};
interfaces = {
eth0.useDHCP = true;
eth1.useDHCP = true;
};
wg-quick.interfaces = {
wg0 = {
address = [ "2001:db8::1" ];
privateKeyFile = "/etc/secrets/wg0.key";
peers = [
{
publicKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
endpoint = "[2001:db8::2]:61021";
allowedIPs = [ "2001::db8:1::/64" ];
}
];
};
};
firewall.allowedUDPPorts = [ 4567 ];
};
i18n = {
defaultLocale = "en_US.UTF-8";
inputMethod.enable = true;
inputMethod.type = "ibus";
};
services = {
libinput.enable = true;
xserver = {
enable = true;
xkb.layout = "us";
xkb.variant = "altgr-intl";
xkb.options = "ctrl:nocaps";
wacom.enable = true;
videoDrivers = [ "modesetting" ];
modules = [ pkgs.xf86_input_wacom ];
displayManager.sx.enable = true;
windowManager.i3.enable = true;
};
udev.extraHwdb = ''
# not like this mattered at all
# we're not running udev from here
'';
udev.extraRules = ''
# ACTION=="add", SUBSYSTEM=="input", ...
'';
};
programs = {
light.enable = true;
wireshark = {
enable = true;
package = pkgs.wireshark-qt;
};
gnupg.agent = {
enable = true;
};
};
fonts.packages = with pkgs; [
font-awesome
noto-fonts
noto-fonts-cjk-sans
noto-fonts-emoji
noto-fonts-extra
dejavu_fonts
powerline-fonts
source-code-pro
cantarell-fonts
];
users = {
mutableUsers = false;
users = {
user = {
isNormalUser = true;
group = "user";
extraGroups = [
"wheel"
"video"
"audio"
"dialout"
"users"
"kvm"
"wireshark"
];
password = "unimportant";
};
};
groups = {
user = { };
};
};
security = {
pam.loginLimits = [
{
domain = "@audio";
item = "memlock";
type = "-";
value = "unlimited";
}
{
domain = "@audio";
item = "rtprio";
type = "-";
value = "99";
}
{
domain = "@audio";
item = "nofile";
type = "soft";
value = "99999";
}
{
domain = "@audio";
item = "nofile";
type = "hard";
value = "99999";
}
];
sudo.extraRules = [
{
users = [ "user" ];
commands = [
{
command = "${pkgs.linuxPackages.cpupower}/bin/cpupower";
options = [ "NOPASSWD" ];
}
];
}
];
};
environment.systemPackages = with pkgs; [
a2jmidid
age
ardour
bemenu
blender
breeze-icons
breeze-qt5
bubblewrap
calf
claws-mail
darktable
duperemove
emacs
feh
file
firefox
fluidsynth
adwaita-icon-theme
gnuplot
graphviz
helm
i3status-rust
inkscape
jack2
jq
krita
ldns
libqalculate
libreoffice
man-pages
nix-diff
nix-index
nix-output-monitor
open-music-kontrollers.patchmatrix
pamixer
pavucontrol
pciutils
picom
pwgen
redshift
ripgrep
rlwrap
silver-searcher
soundfont-fluid
whois
wol
xclip
xdot
xdotool
xorg.xkbcomp
yt-dlp
zathura
borgbackup
linuxPackages.cpupower
mtr
kitty
xf86_input_wacom
];
environment.pathsToLink = [ "/share/soundfonts" ];
systemd.user.services.run-python = {
after = [ "network-online.target" ];
script = ''
exec ${pkgs.python3}/bin/python
'';
serviceConfig = {
CapabilityBoundingSet = [ "" ];
KeyringMode = "private";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = "AF_INET AF_INET6";
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~ @resources @privileged"
];
UMask = "077";
};
};
system.stateVersion = "23.11";
}
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env -S jq -Mrf
def round3:
. * 1000 | round | . / 1000
;
def stats($first):
[
" mean: \(.mean | round3)s ± \(.stddev | round3)s",
" user: \(.user | round3)s | system: \(.system | round3)s",
" median: \(.median | round3)s",
" range: \(.min | round3)s ... \(.max | round3)s",
" relative: \(.mean / $first.mean | round3)"
]
| join("\n")
;
def fmt($first):
"\(.command)\n" + (. | stats($first))
;
[.results | .[0] as $first | .[] | fmt($first)] | join("\n\n") | (. + "\n\n---\n")
-1
View File
@@ -1 +0,0 @@
*
-1
View File
@@ -1 +0,0 @@
*
+3 -2
View File
@@ -7,8 +7,9 @@ create-missing = false
[output.html]
additional-css = ["custom.css"]
additional-js = ["redirects.js"]
# Jumps directly into a new Gerrit CL editing the file in question.
edit-url-template = "https://gerrit.lix.systems/admin/repos/edit/repo/lix/branch/main/file/doc/manual/{path}"
# Using our GitHub mirror enables easier typo fixes since there is no easy way
# to just submit a Gerrit CL by the web for trivial stuff.
edit-url-template = "https://github.com/lix-project/lix/tree/main/doc/manual/{path}"
git-repository-url = "https://git.lix.systems/lix-project/lix"
# Folding by default would prevent things like "Ctrl+F for nix-env" from working
# trivially, but the user should be able to fold if they want to.
-94
View File
@@ -12,10 +12,6 @@
forgejo: rbt
github: 9999years
9p4:
display_name: Ersei Saggi
github: 9p4
Artturin:
github: Artturin
@@ -40,10 +36,6 @@ alois31:
forgejo: alois31
github: alois31
andrewhamon:
display_name: Andrew Hamon
github: andrewhamon
artemist:
display_name: Artemis Tosini
forgejo: artemist
@@ -53,10 +45,6 @@ bb010g:
forgejo: bb010g
github: bb010g
blitz:
display_name: Julian Stecklina
github: blitz
cole-h:
display_name: Cole Helbling
github: cole-h
@@ -66,22 +54,10 @@ delan:
forgejo: delan
github: delan
delroth:
github: delroth
detroyejr:
display_name: Jonathan De Troye
github: detroyejr
edolstra:
display_name: Eelco Dolstra
github: edolstra
emilazy:
display_name: Emily
forgejo: emilazy
github: emilazy
ericson:
display_name: John Ericson
github: ericson2314
@@ -106,9 +82,6 @@ ian-h-chamberlain:
forgejo: ian-h-chamberlain
github: ian-h-chamberlain
infinisil:
github: infinisil
isabelroses:
forgejo: isabelroses
github: isabelroses
@@ -120,16 +93,6 @@ jade:
just1602:
forgejo: just1602
kasimeka:
display_name: ورد
forgejo: janw4ld
github: kasimeka
kfears:
display_name: KFears
forgejo: kfearsoff
github: kfearsoff
kiara:
github: KiaraGrouwstra
@@ -145,10 +108,6 @@ lheckemann:
forgejo: lheckemann
github: lheckemann
lily:
forgejo: lilyinstarlight
github: lilyinstarlight
lilyball:
forgejo: lilyball
github: lilyball
@@ -163,51 +122,24 @@ ma27:
matthewbauer:
github: matthewbauer
mic92:
github: mic92
midnightveil:
display_name: julia
forgejo: midnightveil
github: midnightveil
nan-git:
display_name: NaN-git
github: NaN-git
ncfavier:
github: ncfavier
not-my-profile:
display_name: Martin Fischer
github: not-my-profile
p-e-meunier:
display_name: Pierre-Etienne Meunier
github: P-E-Meunier
pamplemousse:
display_name: Xavier Maso
github: pamplemousse
piegames:
display_name: piegames
forgejo: piegames
github: piegamesde
poliorcetics:
display_name: Poliorcetics
github: poliorcetics
puck:
display_name: puck
forgejo: puck
github: puckipedia
quantenzitrone:
display_name: Zitrone
forgejo: quantenzitrone
quantumjump:
display_name: Quantum Jump
github: QuantumBJump
@@ -224,18 +156,6 @@ roberth:
display_name: Robert Hensing
github: roberth
seppel3210:
github: Seppel3210
teofilc:
forgejo: teofilc
github: TeofilC
thubrecht:
display_name: Tom Hubrecht
forgejo: tom-hubrecht
github: Tom-Hubrecht
thufschmitt:
display_name: Théophane Hufschmitt
github: thufschmitt
@@ -253,24 +173,10 @@ vigress8:
forgejo: vigress8
github: vigress8
vlinkz:
display_name: Victor Fuentes
forgejo: vlinkz
github: vlinkz
winter:
forgejo: winter
github: winterqt
xanderio:
github: xanderio
xokdvium:
github: xokdvium
yorickvp:
github: yorickvp
yshui:
github: yshui
+1 -1
View File
@@ -225,7 +225,7 @@ let
showCategory = cat: ''
${optionalString (cat != "") "**${cat}:**"}
${listOptions (filterAttrs (n: v: v.category == cat && !v.hidden) allOptions)}
${listOptions (filterAttrs (n: v: v.category == cat) allOptions)}
'';
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
showOption =
-1
View File
@@ -1,7 +1,6 @@
nix_env_for_docs = {
'HOME': '/dummy',
'NIX_CONF_DIR': '/dummy',
'XDG_CONFIG_HOME': '/dummy',
'NIX_SSL_CERT_FILE': '/dummy/no-ca-bundle.crt',
'NIX_STATE_DIR': '/dummy',
'NIX_CONFIG': 'cores = 0',
-16
View File
@@ -1,16 +0,0 @@
---
synopsis: First argument to `--arg`/`--argstr` must be a valid Nix identifier
issues: [fj#496]
category: "Breaking Changes"
credits: [ma27]
---
The first argument to `--arg`/`--argstr` must be a valid Nix identifier, i.e.
`nix-build --arg config.allowUnfree true` is now rejected.
This is because that invocation is a false friend since it doesn't set
`{ config = { allowUnfree = true; }; }`, but `{ "config.allowUnfree" = true; }`.
The idea is to change the behavior to the latter in the long-term. For that,
non-identifiers started giving a warning since 2.92 and are now rejected to give people
who depend on that a chance to notice and potentially weigh in on the discussion.
-20
View File
@@ -1,20 +0,0 @@
---
synopsis: "Improved susbtituter query speed"
issues: []
cls: []
category: Improvements
credits: [horrors]
---
The code used to query substituters for derivations has been rewritten slightly
to take advantage of our asynchronous runtime. Such queries run for every build
that could download from substituters and processes every derivation that isn't
yet present on the local system. Previously Lix would use `http-connections` to
limit query concurrency, even for modern caches that support HTTP/2 and have no
limit on how many queries can be run concurrently on one single connection. Lix
no longer does this, resulting in approximately 60% reduction in query time for
medium-sized closures (e.g. NixOS system closures) during testing, although the
exact number depends greatly on local network latency and generally improves as
latency increases. Unlike previously setting `http-connections` to `1` or other
low values no longer brings a massive penalty in query performance if the cache
in use by the querying system supports HTTP/2 (as e.g. `cache.nixos.org` does).
-12
View File
@@ -1,12 +0,0 @@
---
synopsis: "`build-dir` no longer defaults to `temp-dir`"
cls: [3453]
category: "Fixes"
credits: [horrors]
---
The directory in which temporary build directories are created no longer defaults
to the value of the `temp-dir` setting to avoid builders making their directories
world-accessible. This behavior has been used to escape the build sandbox and can
cause build impurities even when not used maliciously. We now default to `builds`
in `NIX_STATE_DIR` (which is `/nix/var/nix/builds` in the default configuration).
@@ -1,60 +0,0 @@
---
synopsis: "Global certificate authorities are copied inside the builder's environment"
issues: [gh#12698, fj#885]
cls: [3765]
category: Fixes
credits: [raito, emilazy]
---
Previously, CA certificates were only installed at
`/etc/ssl/certs/ca-certificates.crt` for sandboxed builds on Linux.
This setup was insufficient in light of recent changes in `nixpkgs`, which now
enforce HTTPS usage for `fetchurl`, even for fixed-output derivations, to
mitigate confidentiality risks such as `netrc` or credentials leakage.
`nixpkgs` still make use of a special package called `cacerts` which contains a
copy of the CA certificates maintained by Nixpkgs and added as a reference for
TLS-enabled fetchers.
As a result, having a consistent and trusted certificate authority in all
builder environments is becoming more essential.
On `nix-darwin`, the `NIX_SSL_CERT_FILE` environment variable is always
explicitly defined, but it is ignored by the sandbox setup.
Simultaneously, Nix evaluates and propagates impure environment variables via
`lib.proxyImpureEnvVars`, meaning that if `NIX_SSL_CERT_FILE` is set (which
influences the default value for `ssl-cert-file`), it will be forwarded
unchanged into the builder environment.
However, on Linux, Nix also *copies* the CA file into the sandbox, creating a
discrepancy between the value of `NIX_SSL_CERT_FILE` and the actual trusted
certificate path used during the build.
This divergence caused confusion and was partially addressed by attempts to
whitelist the CA path in the Darwin sandbox (see cl/2906), but that approach
involved a non-trivial path canonicalization step and is not as general as this one.
To address this properly, we now emit a warning and override
`NIX_SSL_CERT_FILE` inside the builder, explicitly pointing it to the CA file
copied into the sandbox.
This eliminates ambiguity between `NIX_SSL_CERT_FILE`
and `ssl-cert-file`, ensuring consistent trust anchors across platforms.
This warning might become a hard error as we figure out what to do regarding
`lib.proxyImpureEnvVars` in nixpkgs.
The behavior has been verified across sandboxed and unsandboxed builds on both
Linux and Darwin.
As a consequence of this change, approximately 500KB of CA certificate data is
now unconditionally copied into the build directory for fixed-output
derivations.
While this ensures consistent trust verification without having to restart the
daemon after system upgrades, it may introduce a slight overhead in build
performance. At present, no optimizations have been implemented to avoid this
copy, but if this overhead proves noticeable in your workflows, please open an
issue so we can evaluate and possibly implement different strategies to render
trust anchors visible.
-69
View File
@@ -1,69 +0,0 @@
---
synopsis: New cgroup delegation model
issues: [fj#537, fj#77]
cls: [3230]
category: "Breaking Changes"
credits: [raito, horrors, lheckemann]
---
Builds using cgroups (i.e. `use-cgroups = true` and the experimental feature
`cgroups`) now always delegate a cgroup tree to the sandbox.
Compared to the original C++ Nix project, our delegation includes the
`subtree_control` file as well, which means that the sandbox can disable
certain controllers in its own cgroup tree.
This is a breaking change because this requires the Nix daemon to run with an
already delegated cgroup tree by the service manager.
## How to setup the cgroup tree with systemd?
systemd offers knobs to perform the required setup using:
```
[Service]
Delegate=yes
DelegateSubtree=supervisor
```
These directives are now included in our systemd packaging.
## What about using Nix as root without connecting to the daemon?
Builds run as `root` without connecting to the daemon relying on the cgroup
feature are now broken, i.e.
```console
# nix-build --use-cgroups --sandbox ... # will not work
```
Consider doing instead:
```console
# systemd-run --same-dir --wait -p Delegate=yes -p DelegateSubgroup=supervisor nix-build --use-cgroups ...
```
If you need to disable cgroups temporarily, remember that you can do
`NIX_CONF='include /etc/nix/nix.conf\nuse-cgroups = false' nix-build ...` or
`nix-build --no-use-cgroups ...`.
## What about other service managers than systemd?
systemd has a [documentation](https://systemd.io/CGROUP_DELEGATION/) on how to
handle cgroup delegation from service management perspective.
If your service manager adheres to systemd semantics, e.g. writing an extended
attribute `user.delegate=1` on the delegated cgroup tree directory and moving
the `nix-daemon` process inside a cgroup tree to respect the inner process
rule, then, the feature will work as well.
## Why is the cgroup feature still experimental?
While the cgroup feature unlocks many use cases, its behavior and integration (e.g. user experience), especially at scale on build farms or in multi-tenant environments, are not yet fully matured. Theres also potential for deeper systemd integration (e.g. using slices and scopes) that has not been fully explored.
To avoid locking in an unstable interface, were keeping the experimental flag until we have validated the feature across a broader range of scenarios, including but not limited to:
* Nix as root
* Hydra-style build farms
* Forgejo CI runners
* Shared remote builders
@@ -1,16 +0,0 @@
---
synopsis: Deprecation of CA derivations, dynamic derivations, and impure derivations
issues: [fj#815]
cls: []
significance: significant
category: Miscellany
credits: []
---
Content-addressed derivations are now deprecated and slated for removal in Lix 2.94.
We're doing this because the CA derivation system has been a known cause of problems
and inconsistencies, is unmaintained, habitually makes improving the store code very
difficult (or blocks such improvements outright), and is beset by a number of design
flaws that in our opinion cannot be fixed without a full reimplementation from zero.
Dynamic derivations and impure derivations are built on the CA derivation framework,
and owing to this they too are deprecated and slated for removal in another release.
-25
View File
@@ -1,25 +0,0 @@
---
synopsis: "Hitting Control-C twice always terminates Lix"
cls: [3574]
issues: []
category: "Improvements"
credits: [horrors]
---
Hitting Control-C or sending `SIGINT` to Lix now prints an informational message
if it is still running after on second, the second Control-C/`SIGINT` terminates
Lix immediately without waiting for any shutdown code to finish running. Lix did
not treat the second such event differently from first in the past; this made it
impossible to easily terminate running Lix processes that got stuck in e.g. very
expensive Nixlang code that never interacted with the store. We now terminate as
soon as the user hits Control-C again without waiting any more, to much the same
effect as putting Lix into the background and killing it immediately afterwards.
This means you can now more conveniently break out of stuck Nixlang evaluations:
```
nix-instantiate --eval --expr 'let f = n: if n == 0 then 0 else f (n - 1) + f (n - 1); in f 32'
^CStill shutting down. Press ^C again to abort all operations immediately.
^C
❌130
```
-12
View File
@@ -1,12 +0,0 @@
---
synopsis: "libstore: exponential backoff for downloads"
issues: [lix#932]
cls: [3856]
category: Fixes
credits: [ma27]
---
The connection timeout when downloading from e.g. a binary cache is exponentially
increased per failure. The option `connect-timeout` is now an alias to `max-connect-timeout`
which is the maximum value for a timeout. The start value is controlled
by `initial-connect-timeout` which is `5` by default.
-9
View File
@@ -1,9 +0,0 @@
---
synopsis: Fix develop shells for derivations with escape codes
issues: [fj#991]
cls: [4154, 4155]
category: Fixes
credits: [Qyriad]
---
ASCII control characters (including `\e`, used for ANSI escape codes) in derivation variables are now correctly escaped for `nix develop` and `nix print-dev-env`, instead of erroring.
-13
View File
@@ -1,13 +0,0 @@
---
synopsis: "nix-store --delete: always remove obsolete hardlinks"
issues: []
cls: [3188]
category: Fixes
credits: [lheckemann]
---
Deleting specific paths using `nix-store --delete` or `nix store
delete` previously did not delete hard links created by `nix-store
--optimise` even if they became obsolete, unless _all_ of the given
paths were deleted successfully. Now, hard links are always cleaned
up, even if some of the given paths could not be deleted.
-24
View File
@@ -1,24 +0,0 @@
---
synopsis: "Report GC statistics correctly"
issues: []
cls: [3188]
category: Fixes
credits: [lheckemann]
---
Deleting specific paths using `nix-store --delete` or `nix store delete` previously did
not report statistics correctly when some of the paths could not be deleted, even if
others were deleted:
```
$ nix store delete /nix/store/9bwryidal9q3g91cjm6xschfn4ikd82q-hello-2.12.1 --delete-closure -v
finding garbage collector roots...
deleting '/nix/store/9bwryidal9q3g91cjm6xschfn4ikd82q-hello-2.12.1'
0 store paths deleted, 0.00 MiB freed
error: Cannot delete some of the given paths because they are still alive. Paths not deleted:
k9bxzr1l92r5y6mihrkbpbr3fmc8qszx-libidn2-2.3.8
mbx9ii53lzjlrsnlrfmzpwm33ynljwdn-libunistring-1.3
rf8hcy6bldxdqc0g6q1dcka1vh47x69s-xgcc-14.2.1.20250322-libgcc
vbrdc5wgzn0w1zdp10xd2favkjn5fk7y-glibc-2.40-66
To find out why, use nix-store --query --roots and nix-store --query --referrers.
```
-16
View File
@@ -1,16 +0,0 @@
---
synopsis: Add `inputs.self.submodules` flake attribute
issues: [fj#942]
cls: [3839]
category: Features
credits: [edolstra, kasimeka]
---
A port of <https://github.com/NixOS/nix/pull/12421> to Lix, which:
- adds a general `inputs.self` flake attribute that retroactively applies
configurations to a flake after it's been fetched, then triggers a refetch of
the flake with the new config.
- implements `inputs.self.submodules` that allows a flake to declare its need
for submodules, which are then fetched automatically with no need to pass
`?submodules=1` anywhere.
@@ -1,16 +0,0 @@
---
synopsis: Add hyperlinks in attr set printing
issues: []
cls: [3790]
category: Features
credits: [jade]
---
The attribute set printer, such as is seen in `nix repl` or in type errors, now prints hyperlinks on each attribute name to its definition site if it is known.
Example: all of the attributes shown here are hyperlinks to the exact definition site of the attribute in question:
```
$ nix eval -f '<nixpkgs>' lib.licenses.mit
{ deprecated = false; free = true; fullName = "MIT License"; redistributable = true; shortName = "mit"; spdxId = "MIT"; url = "https://spdx.org/licenses/MIT.html"; }
```
-24
View File
@@ -1,24 +0,0 @@
---
synopsis: Repl debugger uses `--ignore-try` by default
issues: [lix#666]
cls: [3488]
category: Breaking Changes
credits: [jade]
---
Previously, using the debugger meant that exceptions thrown in `builtins.tryEval` would trigger the debugger.
However, this caught nixpkgs initialization code, which is unhelpful in the majority of cases, so we changed the default.
To get the old behaviour, use `--no-ignore-try`.
```
$ nix repl --debugger --expr 'with import <nixpkgs> {}; pkgs.hello'
Lix 2.94.0-dev-pre20250625-9a59106
Type :? for help.
error: file 'nixpkgs-overlays' was not found in the Nix search path (add it using $NIX_PATH or -I)
This exception occurred in a 'tryEval' call. Use --ignore-try to skip these.
Added 13 variables.
nix-repl>
```
@@ -1,25 +0,0 @@
---
synopsis: "Fallback to safe temp dir when build-dir is unwritable"
issues: [fj#876]
cls: [3501]
category: "Fixes"
credits: ["raito", "horrors"]
---
Non-daemon builds started failing with a permission error after introducing the `build-dir` option:
```
$ nix build --store ~/scratch nixpkgs#hello --rebuild
error: creating directory '/nix/var/nix/builds/nix-build-hello-2.12.2.drv-0': Permission denied
```
This happens because:
1. These builds are not run via the daemon, which owns `/nix/var/nix/builds`.
2. The user lacks permissions for that path.
We considered making `build-dir` a store-level option and defaulting it to `<chroot-root>/nix/var/nix/builds` for chroot stores, but opted instead for a fallback: if the default fails, Nix now creates a safe build directory under `/tmp`.
To avoid CVE-2025-52991, the fallback uses an extra path component between `/tmp` and the build dir.
**Note**: this fallback clutters `/tmp` with build directories that are not cleaned up. To prevent this, explicitly set `build-dir` to a path managed by Lix, even for local workloads.
-47
View File
@@ -1,47 +0,0 @@
---
synopsis: Experimental integer coercion in interpolated strings
issues: []
cls: [3198]
category: "Features"
credits: [raito, delroth, horrors, winter]
---
Ever tried interpolating a port number in Lix and ended up with something like this?
```nix
"http://${config.network.host}:${builtins.toString config.network.port}/"
```
You're not alone. Thousands of Lix users suffer every day from excessive `builtins.toString` syndrome. Its 2025, and we still have to cast integers to use them in strings.
To address this, Lix introduces the **`coerce-integers`** experimental feature. When enabled, interpolated integers within `"${...}"` are automatically coerced to strings. This allows writing:
```nix
"http://${config.network.host}:${config.network.port}/"
```
without additional conversion.
To enable the feature, you need to add `coerce-integers` to your set of experimental features.
### Stabilization criteria
The `coerce-integers` feature is experimental and limited strictly to string interpolation (`"${...}"`). Before stabilization, the following must hold:
1. **Interpolation-only**
Coercion must not occur outside interpolation. Expressions like `"" + 42` must continue to fail.
2. **Expectation that no explicit cast are being observed**
Cases observing explicit coercion (e.g., via `tryEval` gadget or similar) are expected not to be load-bearing in actual production code.
### Timeline for stabilization
If the feature proves safe and is widely adopted across typical usage (e.g., actual configurations in the wild turning on the flag, non-trivial out-of-tree projects using it), the experimental flag will be removed **after six months of active use or two Lix releases**, whichever is longer.
This avoids locking the feature in experimental status indefinitely, as happened with Flakes, while allowing time for validation and ecosystem integration.
### What about coercing floats or more?
Coercion beyond integers -- such as for floats or other types -- is **not planned**, even under an experimental flag. Questions like "what is the canonical string representation of a float?" involve subtle and context-dependent trade-offs. Without a robust and principled mechanism to define and audit such behavior, introducing broader coercion risks setting unintended and hard-to-reverse precedents. The scope of `coerce-integers` is intentionally narrow and will remain so.
In terms of outlook, a proposal like https://git.lix.systems/lix-project/lix/issues/835 could pave the way for a better solution.
@@ -1,16 +0,0 @@
---
synopsis: Parse overflowing JSON number literals as floatingpoint
issues: []
cls: [3919]
category: "Fixes"
credits: [emilazy]
---
Previously, `builtins.fromJSON "-9223372036854775809"` would
return a floatingpoint number, while `builtins.fromJSON
"9223372036854775808"` would cause an evaluation error. This was
introduced with the banning of integer overflow in Lix 2.91; previously
the latter would result in C++ undefined behaviour. These cases are
now treated consistently with JSONs model of a single numeric type,
and JSON number literals that do not fit in a Nixlanguage integer
will be parsed as floatingpoint numbers.
-13
View File
@@ -1,13 +0,0 @@
---
synopsis: "`--keep-failed` chowns the build directory to the user that request the build"
issues: []
cls: []
category: Improvements
credits: [horrors]
---
Running a build with `--keep-failed` now chowns the temporary directory from the
builder user and group to the user that request the build if the build came from
a local user connected to the daemon. This makes inspecting failed derivations a
lot easier. On Linux the build directory made visible to the user will not be in
the same path as it was in the sandbox and continuing builds will usually break.
@@ -1,11 +0,0 @@
---
synopsis: Fix handling of OSC codes in terminal output
issues: [fj#160]
cls: [3143]
category: Fixes
credits: [lilyball]
---
OSC codes in terminal output are now handled correctly, where OSC 8 (hyperlink) is preserved any
time color codes are allowed and all other OSC codes are stripped out. This applies not only to
output from build commands but also to rendered documentation in the REPL.
-14
View File
@@ -1,14 +0,0 @@
---
synopsis: Better debuggability on fixed-output hash mismatches
issues: []
cls: []
category: Improvements
credits: [lheckemann]
---
Fixed-output derivation hash mismatch error messages will now include the path that was
produced unexpectedly, and this path will be registered as valid even if `--check`
(`nix-store`, `nix-build`) or `--rebuild` (`nix build`) was passed. This makes comparing
the expected path with the obtained path easier, and is useful for debugging when
upstreams modify previously-published releases or when changes in fixed-output
derivations' dependencies affect their output unexpectedly.
-10
View File
@@ -1,10 +0,0 @@
---
synopsis: "nix-eval-jobs: support `--no-instantiate` flag"
issues: [fj#987]
category: Features
credits: [mic92,ma27]
---
`nix-eval-jobs` now supports a flag called `--no-instantiate`. With this enabled,
no write operations on the eval store are performed. That means, only evaluation is
performed, but derivations (and their gcroots) aren't created.
@@ -1,29 +0,0 @@
---
synopsis: "Fix nix develop for derivations that rejects dependencies with structured attrs"
issues: [fj#997]
cls: [4182]
category: Fixes
credits: [raito]
---
For the sake of concision, we refer to `disallowedReferences` in what follows,
but all output checks were equally fixed:
`{dis,}allowed{References,Requisites}`.
Derivations can define *output checks* to reject unwanted dependencies, such as
interpreters like `bash` or compilers like `gcc`. This can be done in two ways:
* **Legacy style**: `disallowedReferences = [ ... ]` in the environment.
* **Structured attrs**: `outputChecks.<output>.disallowedReferences = [ ... ]`,
typically used in `__json`.
Only the structured form supports derivations with multiple outputs.
`nix develop` internally rewrites derivations to create development shells. It
relied on the legacy `disallowedReferences`, and failed to honor the structured
variant. This led to broken shells in cases where `bashInteractive` was
explicitly disallowed using structured output checks, e.g. `nix develop
nixpkgs#systemd` after the "bash-less NixOS" changes.
This fix teaches `nix develop` to respect structured output checks, restoring
support for such derivations.
-12
View File
@@ -1,12 +0,0 @@
---
synopsis: "Add --raw flag to `nix-instantiate --eval` for unescaped output"
issues: []
prs: [gh#12119]
cls: [2886]
category: Improvements
credits: [not-my-profile, infinisil, raito]
---
The `nix-instantiate --eval` command now supports a `--raw` flag. When used,
the result must be coercible to a string (as with `${...}`) and is printed
verbatim, without quotes or escaping.
@@ -1,12 +0,0 @@
---
synopsis: Allow `nix store ls` to read nar listings from binary cache stores.
issues: []
cls: [3225]
category: Improvements
credits: [vlinkz]
---
The `nix store ls` command now supports reading `.ls` nar listings from binary cache stores.
If a listing is detected for the store path being queried, the nar is no longer downloaded.
These nar listings are available in binary cache stores where the `write-nar-listing` option is
enabled, such as cache.nixos.org.
@@ -1,10 +0,0 @@
---
synopsis: "nix-eval-jobs: retain NIX_PATH"
issues: []
cls: [3859]
category: Fixes
credits: [ma27,mic92]
---
`nix-eval-jobs` doesn't clear the `NIX_PATH` from the environment anymore. This matches the behavior
of [upstream version `2.30`](https://github.com/nix-community/nix-eval-jobs/releases/tag/v2.30.0).
-25
View File
@@ -1,25 +0,0 @@
---
synopsis: "show tree with references that lead to an output cycle"
issues: [fj#551]
category: Improvements
credits: [ma27]
---
When Lix determines a cyclic dependency between several outputs of a derivation,
it now displays which files in which outputs lead to an output cycle:
```
error: cycle detected in build of '/nix/store/gc5h2whz3rylpf34n99nswvqgkjkigmy-demo.drv' in the references of output 'bar' from output 'foo'.
Shown below are the files inside the outputs leading to the cycle:
/nix/store/3lrgm74j85nzpnkz127rkwbx3fz5320q-demo-bar
└───lib/libfoo: …stuffbefore /nix/store/h680k7k53rjl9p15g6h7kpym33250w0y-demo-baz andafter.…
→ /nix/store/h680k7k53rjl9p15g6h7kpym33250w0y-demo-baz
└───share/snenskek: …???? /nix/store/dm24c76p9y2mrvmwgpmi64rryw6x5qmm-demo-foo ....…
→ /nix/store/dm24c76p9y2mrvmwgpmi64rryw6x5qmm-demo-foo
└───bin/alarm: …textexttext/nix/store/3lrgm74j85nzpnkz127rkwbx3fz5320q-demo-bar abcabcabc.…
→ /nix/store/3lrgm74j85nzpnkz127rkwbx3fz5320q-demo-bar
```
Please note that showing the files and its contents while displaying the cycles only works
on Linux.
-20
View File
@@ -1,20 +0,0 @@
---
synopsis: "Fixed output derivations can be run using `pasta` network isolation"
cls: [3452]
issues: [fj#285]
category: "Breaking Changes"
credits: [horrors, puck]
---
Fixed output derivations traditionally run in the host network namespace.
On Linux this allows such derivations to communicate with other sandboxes
or the host using the abstract Unix domains socket namespace; this hasn't
been unproblematic in the past and has been used in two distinct exploits
to break out of the sandbox. For this reason fixed output derivations can
now run in a network namespace (provided by [`pasta`]), restricted to TCP
and UDP communication with the rest of the world. When enabled this could
be a breaking change and we classify it as such, even though we don't yet
enable or require such isolation by default. We may enforce this in later
releases of Lix once we have sufficient confidence that breakage is rare.
[`pasta`]: https://passt.top/
@@ -1,21 +0,0 @@
---
synopsis: Remove reliance on Bash for remote stores via SSH
issues: [fj#830, fj#805, fj#304]
cls: [3159]
category: "Fixes"
credits: [raito]
---
The pre-flight `echo started` handshake -- added years ago to catch race conditions -- has been removed.
After removal of connection sharing in Lix 2.93, it required a Bash-compatible shell and a standard `echo`, so it failed on:
* builders protected by `ForceCommand` wrappers (e.g. `nix-remote-build`),
* BusyBox / initrd images with no Bash,
* hosts using non-POSIX shells such as Nushell.
The race the probe once addressed was tied to SSH connection-sharing -- since connection-sharing code has already been removed, the probe is now pointless.
Real connection or protocol errors are now left to SSH/Nix to report directly.
This is technically a breaking change if you had scripts that relied on the literal "started" which needs to be updated to rely on other signals, e.g., exit codes.
-20
View File
@@ -1,20 +0,0 @@
---
synopsis: Remove support for daemon protocols before 2.18
issues: [fj#510]
cls: [3249]
significance: significant
category: "Breaking Changes"
credits: [horrors]
---
Support for daemon wire protocols belonging to Nix 2.17 or older have been
removed. This impacts clients connecting to the local daemon socket or any
remote builder configured using the `ssh-ng` protocol. Builders configured
with the `ssh` protocol are still accessible from clients such as Nix 2.3.
Additionally Lix will not be able to connect to an old daemon locally, and
remote build connections to old daemons is likewise limited to `ssh` urls.
We have decided to take this step because the old protocols are very badly
tested (if at all), maintenance overhead is high, and a number of problems
with their design makes it infeasible to remain backwards compatible while
we move Lix to a more modern RPC mechanism with better versioning support.
-14
View File
@@ -1,14 +0,0 @@
---
synopsis: "`nix eval --write-to` has been removed"
cls: [4045]
issues: [fj#974, fj#227]
category: "Breaking Changes"
credits: [horrors]
---
`nix eval --write-to` has been removed since it was underspecified, not widely
useful, and prone to security-sensitive misbehaviors. The feature was added in
Nix 2.4 purely for internal use in the build system. According to our research
it hasn't found any use outside of some distribution packaging scripts. Please
use structured outputs formats (such as JSON) instead as they have better type
fidelity, don't conflate attributes with paths, and are useful to other tools.
@@ -1,17 +0,0 @@
---
synopsis: Remove impure derivations and dynamic derivations
issues: [fj#815]
cls: [3210]
significance: significant
category: "Breaking Changes"
credits: [horrors]
---
The `impure-derivations` and `dynamic-derivations` experimental feature have
been removed.
New impure or dynamic derivations cannot be created from this point forward, and
any such pre-existing store derivations canot be read or built any more.
Derivation outputs created by building such a derivation are still valid
until garbage collected; existing store derivations can only be garbage
collected.
@@ -1,17 +0,0 @@
---
synopsis: Remove the `parse-toml-timestamps` experimental feature
category: "Breaking Changes"
credits: [emilazy]
---
The `parse-toml-timestamps` experimental feature has been removed.
This feature used inband signalling to mark timestamps, making it
impossible to unambiguously parse TOML documents. It also exposed
implementationdefined behaviour in the TOML specification that
changed in the toml11 parser library.
Any interface for parsing TOML timestamps suitable for future
stabilization would necessarily involve breaking changes, and there
is no evidence this experimental feature is being relied upon in the
wild, so it has been removed.
-20
View File
@@ -1,20 +0,0 @@
---
synopsis: "repl-overlays now work in the debugger for flakes"
issues: [fj#777]
cls: [3398]
category: Fixes
credits: [jade]
---
Due to a bug, it was previously not possible to use the debugger on flakes with repl-overlays, or with pure evaluation in general:
```
$ nix repl --pure-eval
Lix 2.94.0-dev-pre20250617-87d99da
Type :? for help.
Loading 'repl-overlays'...
error: access to absolute path '/Users/jade/.config/nix/repl.nix' is forbidden in pure eval mode (use '--impure' to override)
```
This is now fixed.
The contents of the repl-overlays file itself (i.e. most typically the top level lambda in it) will be evaluated in impure mode.
It may be necessary to use `builtins.seq` to force the impure operations to happen first if one wants to do impure operations inside a repl-overlays file in pure evaluation mode.
@@ -1,19 +0,0 @@
---
synopsis: "`disallowedRequisites` now reports chains of disallowed requisites"
issues: [fj#334,fj#626,gh#10877]
category: Improvements
credits: [ma27,roberth]
---
When a build fails because of [`disallowedRequisites`](@docroot@/language/advanced-attributes.md#adv-attr-disallowedRequisites), the error message now includes the chain of references that led to the failure. This makes it easier to see in which derivations the chain can be broken, to resolve the problem.
Example:
```
$ nix-build -A hello
error: output '/nix/store/0b7k85gg5r28gb54px9nq7iv5986mns9-hello-2.12.2' is not allowed to refer to the following paths:
/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-glibc-2.40-66
Shown below are chains that lead to the forbidden path(s).
/nix/store/0b7k85gg5r28gb54px9nq7iv5986mns9-hello-2.12.2
└───/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-glibc-2.40-66
```
@@ -1,17 +0,0 @@
---
synopsis: "libstore/binary-cache-store: don't cache narinfo on nix copy, remove negative entry"
issues: []
cls: [3789]
category: Fixes
credits: [ma27]
---
When using e.g. [Snix's nar-bridge](https://snix.dev/docs/components/overview/#nar-bridge) via
an `http`-store, Lix would create cache entries with a wrong URL to the NAR when uploading
a store-path.
This caused hard build failures for Hydra.
Lix doesn't create these entries on upload anymore. Instead, it only removes negative cache entries.
The cache entry for a narinfo is now created the first time, Lix queries the cache
for the previously uploaded store-path again.
-10
View File
@@ -1,10 +0,0 @@
---
synopsis: "Lix libraries can now be linked statically"
issues: [fj#789]
cls: [3775, 3778]
category: Fixes
credits: [alois31]
---
Previously the pkg-config files distributed with Lix were only suitable for dynamic linkage, causing "undefined reference to…" linker errors when trying to link statically.
Private dependency information has now been added to make static linkage work as expected without user intervention.
In addition, relevant static libraries are now prelinked to avoid strange failures due to missing static initializers.
-34
View File
@@ -1,34 +0,0 @@
---
synopsis: Symbols reuses once-allocated Value to reduce garbage collected allocations
issues: []
cls: [3308, 3300, 3314, 3310, 3312, 3313]
category: Improvements
credits: [raito, horrors, thubrecht, xokdvium, nan-git]
---
In the Lix evaluator, **symbols** represent immutable strings, like those used
for attribute names.
In evaluator design, such strings are typically [**interned**](https://en.wikipedia.org/wiki/String_interning), stored uniquely
to save memory, and Lix inherits this approach from the original C++ codebase.
However, some builtins, like `builtins.attrNames`, must return a `Value` type
that can represent any Nix value (strings, integers, lists, etc.).
Before this change, these builtins would create lists of `Value` objects by
allocating them through the garbage collector, copying the symbols string
content each time.
This allocation is unnecessary if the interned symbols themselves also hold a
`Value` representation allocated outside the garbage collector, since these
live for the full duration of evaluation.
As a result, this reduces the number of allocations, leading to:
* A significant drop in maximum [resident set memory](https://en.wikipedia.org/wiki/Resident_set_size) (RSS), with some large-scale
tests showing up to 11% (about 500 MiB) savings in large colmena deployments.
* A slight decrease in CPU usage during Nix evaluations.
This change is inspired by https://github.com/NixOS/nix/pull/13258 but the approach is different.
**Note** : [`xokdvium`](https://github.com/xokdvium) is the rightful author of https://gerrit.lix.systems/c/lix/+/3300 and the credit was missed on our end during the development process. We are deeply sorry for this mistake.
@@ -1,14 +0,0 @@
---
synopsis: Reject overflowing TOML integer literals
issues: []
cls: [3916]
category: "Breaking Changes"
credits: [emilazy]
---
The toml11 library used by Lix was updated. The new
version aligns with the [TOML v1.0.0 specifications
requirement](https://toml.io/en/v1.0.0#integer) to reject integer
literals that cannot be losslessly parsed. This means that code like
`builtins.fromTOML "v=0x8000000000000000"` will now produce an error
rather than silently saturating the integer result.
@@ -1,15 +0,0 @@
---
synopsis: uid-range depends on cgroups
issues: []
cls: [3230]
category: "Breaking Changes"
credits: [raito, horrors]
---
`uid-range` builds now depends on `cgroups`, an experimental feature.
`uid-range` builds already depended upon `auto-allocate-uids`, another experimental feature.
The rationale for doing so is that `uid-range` provides a sandbox with many
UIDs, this is useful for re-mapping them into a nested namespace, e.g. a
container.
@@ -1,10 +0,0 @@
---
synopsis: add description to zsh completions
issues: [fj#910]
cls: [3632]
category: "Fixes"
credits: [matthewbauer]
---
Emit descriptions when completing args in zsh completions. This uses the descriptions we already
provided in NIX\_GET\_COMPLETIONS.
+1 -1
View File
@@ -20,6 +20,7 @@
- [Basic Package Management](package-management/basic-package-mgmt.md)
- [Profiles](package-management/profiles.md)
- [Garbage Collection](package-management/garbage-collection.md)
- [Garbage Collector Roots](package-management/garbage-collector-roots.md)
- [Sharing Packages Between Machines](package-management/sharing-packages.md)
- [Serving a Nix store via HTTP](package-management/binary-cache-substituter.md)
- [Copying Closures via SSH](package-management/copy-closure.md)
@@ -197,7 +198,6 @@
- [Release Notes](release-notes/release-notes.md)
- [Upcoming release](release-notes/rl-next.md)
<!-- RELENG-AUTO-INSERTION-MARKER (see releng/release_notes.py) -->
- [Lix 2.93 (2025-05-09)](release-notes/rl-2.93.md)
- [Lix 2.92 (2025-01-18)](release-notes/rl-2.92.md)
- [Lix 2.91 (2024-08-12)](release-notes/rl-2.91.md)
- [Lix 2.90 (2024-07-10)](release-notes/rl-2.90.md)
@@ -75,9 +75,7 @@ by spaces. Only the first element is required. To leave a field at its
default, set it to `-`.
1. The URI of the remote store in the format
`ssh://[username@]hostname[?port=<port>]`, e.g. `ssh://nix@mac` or `ssh://mac`.
If the ssh server is not listening on port 22 (e.g. port 1337 in this case)
the URI would be `ssh://nix@mac?port=1337`
`ssh://[username@]hostname`, e.g. `ssh://nix@mac` or `ssh://mac`.
For backward compatibility, `ssh://` may be omitted. The hostname
may be an alias defined in your `~/.ssh/config`.
+3 -3
View File
@@ -22,9 +22,9 @@ The following [concept map] shows its main components (rectangles), the objects
| |
+----------|-------------------|--------------------------------+
| Nix impl.| V |
| (Lix) | +------------------------+ |
| | | command line interface |------. |
| | +------------------------+ | |
| (Lix) | +-------------------------+ |
| | | commmand line interface |------. |
| | +-------------------------+ | |
| | | | |
| evaluated by calls manages |
| | | | |
@@ -1,12 +0,0 @@
<!--
File-ish argument syntax summary.
This file gets included into pages like nix-build.md and nix-instantiate.md, and each individual page that includes
this also links to nix-build.md for the full explanation.
-->
- A normal filesystem path, like `/home/meow/nixfiles/default.nix`
- Or a directory, like `/home/meow/nixfiles`, equivalent to above
- A single lookup path, like `<nixpkgs>` or `<nixos>`
- A URL to a tarball, like `https://github.com/NixOS/nixpkgs/archive/refs/heads/release-23.11.tar.gz`
- A [flakeref](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references), introduced by the prefix `flake:`, like `flake:git+https://git.lix.systems/lix-project/lix`
- A *nixpkgs* channel tarball name, introduced by the prefix `channel:`, like `channel:nixos-unstable`.
- This uses a hard-coded URL pattern and is *not* related to the subscribed channels managed by the [nix-channel](@docroot@/command-ref/nix-channel.md) command.
+7 -43
View File
@@ -4,7 +4,7 @@
# Synopsis
`nix-build` [*fileish…*]
`nix-build` [*paths…*]
[`--arg` *name* *value*]
[`--argstr` *name* *value*]
[{`--attr` | `-A`} *attrPath*]
@@ -20,55 +20,19 @@ For documentation on the latter, run `nix build --help` or see `man nix3-build`.
# Description
The `nix-build` command builds the derivations described by the Nix
expressions in each *fileish*. If the build succeeds, it places a symlink to
expressions in *paths*. If the build succeeds, it places a symlink to
the result in the current directory. The symlink is called `result`. If
there are multiple Nix expressions, or the Nix expressions evaluate to
multiple derivations, multiple sequentially numbered symlinks are
created (`result`, `result-2`, and so on).
If no *fileish* is specified, then `nix-build` will use `default.nix` in
If no *paths* are specified, then `nix-build` will use `default.nix` in
the current directory, if it exists.
## Fileish Syntax
A given *fileish* may take one of a few different forms, the first being a simple filesystem path, e.g. `nix-build /tmp/some-file.nix`.
Like the [import builtin](../language/builtins.md#builtins-import) specifying a directory is equivalent to specifying `default.nix` within that directory.
It may also be a [search path](./env-common.md#env-NIX_PATH) (also known as a lookup path) like `<nixpkgs>`, which is convenient to use with `--attr`/`-A`:
```console
$ nix-build '<nixpkgs>' -A firefox
```
(Note the quotation marks around `<nixpkgs>`, which will be necessary in most Unix shells.)
If a *fileish* starts with `http://` or `https://`, it is interpreted as the URL of a tarball which will be fetched and unpacked.
Lix will then `import` the unpacked directory, so these tarballs must include at least a single top-level directory with a file called `default.nix`
For example, you could build from a specific version of Nixpkgs with something like:
```console
$ nix-build "https://github.com/NixOS/nixpkgs/archive/refs/heads/release-23.11.tar.gz" -A firefox
```
If a path starts with `flake:`, the rest of the argument is interpreted as a [flakeref](./new-cli/nix3-flake.md#flake-references) (see `nix flake --help` or `man nix3-flake`), which requires the "flakes" experimental feature to be enabled.
Lix will fetch the flake, and then `import` its unpacked directory, so the flake must include a file called `default.nix`.
For example, the flake analogues to the above `nix-build` commands are:
```console
$ nix-build flake:nixpkgs -A firefox
$ nix-build flake:github:NixOS/nixpkgs/release-23.11 -A firefox
```
Finally, for legacy reasons, if a path starts with `channel:`, the rest of the argument is interpreted as the name of a *nixpkgs* channel tarball to fetch from `https://nixos.org/channels/$CHANNEL_NAME/nixexprs.tar.xz`.
This is a **hard coded URL** pattern and is *not* related to the subscribed channels managed by the [nix-channel](./nix-channel.md) command.
> **Note**: any of the special syntaxes may always be disambiguated by prefixing the path.
> For example: a file in the current directory literally called `<nixpkgs>` can be addressed as `./<nixpkgs>`, to escape the special interpretation.
In summary, a path argument may be one of:
{{#include ./fileish-summary.md}}
## Notes
If an element of *paths* starts with `http://` or `https://`, it is
interpreted as the URL of a tarball that will be downloaded and unpacked
to a temporary location. The tarball must include a single top-level
directory containing at least a file named `default.nix`.
`nix-build` is essentially a wrapper around
[`nix-instantiate`](nix-instantiate.md) (to translate a high-level Nix
+1 -1
View File
@@ -14,7 +14,7 @@ The moving parts of channels are:
- The official channels listed at <https://nixos.org/channels>
- The user-specific list of [subscribed channels](#subscribed-channels)
- The [downloaded channel contents](#channels)
- The [Nix expression search path](@docroot@/command-ref/conf-file.md#conf-nix-path), set with the [`-I` option](#opt-I) or the [`NIX_PATH` environment variable](#env-NIX_PATH)
- The [Nix expression search path](@docroot@/command-ref/conf-file.md#conf-nix-path), set with the [`-I` option](#opt-i) or the [`NIX_PATH` environment variable](#env-NIX_PATH)
> **Note**
>
@@ -36,7 +36,7 @@ Instead, it looks in a few locations, and acts on all profiles it finds there:
>
> Not stable; subject to change
>
> Do not rely on this functionality; it just exists for migration purposes and may change in the future.
> Do not rely on this functionality; it just exists for migration purposes and is may change in the future.
> These deprecated paths remain a private implementation detail of Lix.
<!-- FIXME(Qyriad): this is inconsistent with https://git.lix.systems/lix-project/lix/issues/215, needs updating when that happens -->
+1 -1
View File
@@ -8,7 +8,7 @@
[`--option` *name* *value*]
[`--arg` *name* *value*]
[`--argstr` *name* *value*]
[{`--file` | `-f`} *fileish*]
[{`--file` | `-f`} *path*]
[{`--profile` | `-p`} *path*]
[`--system-filter` *system*]
[`--dry-run`]
@@ -26,7 +26,7 @@ This operation deletes the specified generations of the current profile.
>
> Older *and newer* generations will be deleted by this operation.
>
> One might expect this to just delete older generations than the current one, but that is only true if the current generation is also the latest.
> One might expect this to just delete older generations than the curent one, but that is only true if the current generation is also the latest.
> Because one can roll back to a previous generation, it is possible to have generations newer than the current one.
> They will also be deleted.
@@ -11,7 +11,6 @@
[`--from-profile` *path*]
[`--preserve-installed` | `-P`]
[`--remove-all` | `-r`]
[`--priority` *priority*]
# Description
@@ -60,11 +59,6 @@ a number of possible ways:
unambiguous way, which is necessary if there are multiple
derivations with the same name.
- If `--priority` *priority* is given, the priority of the derivations being
installed is set to *priority*. This can be used to override the priority of
the derivations being installed. This is useful if *args* are store paths,
which don't have any priority information.
- If *args* are [store derivations](@docroot@/glossary.md#gloss-store-derivation), then these are
[realised](@docroot@/command-ref/nix-store/realise.md), and the resulting output paths
are installed.
@@ -148,8 +142,8 @@ To copy the store path with symbolic name `gcc` from another profile:
$ nix-env --install --from-profile /nix/var/nix/profiles/foo gcc
```
To install a specific [store derivation](@docroot@/glossary.md#gloss-store-derivation)
(typically created by `nix-instantiate`):
To install a specific [store derivation] (typically created by
`nix-instantiate`):
```console
$ nix-env --install /nix/store/fibjb1bfbpm5mrsxc4mh2d8n37sxh91i-gcc-3.4.3.drv
@@ -2,16 +2,16 @@
The following options are allowed for all `nix-env` operations, but may not always have an effect.
- `--file` / `-f` *fileish*\
- `--file` / `-f` *path*\
Specifies the Nix expression (designated below as the *active Nix
expression*) used by the `--install`, `--upgrade`, and `--query
--available` operations to obtain derivations. The default is
`~/.nix-defexpr`.
*fileish* is interpreted the same as with [nix-build](../nix-build.md#fileish-syntax).
See that section for complete details (`nix-build --help`), but in summary, a path argument may be one of:
{{#include ../fileish-summary.md}}
If the argument starts with `http://` or `https://`, it is
interpreted as the URL of a tarball that will be downloaded and
unpacked to a temporary location. The tarball must include a single
top-level directory containing at least a file named `default.nix`.
- `--profile` / `-p` *path*\
Specifies the profile to be used by those operations that operate on
@@ -22,7 +22,7 @@ left untouched; this is not an error. It is also not an error if an
element of *args* matches no installed derivations.
For a description of how *args* is mapped to a set of store paths, see
[`--install`](install.md). If *args* describes multiple
[`--install`](#operation---install). If *args* describes multiple
store paths with the same symbolic name, only the one with the highest
version is installed.
+9 -31
View File
@@ -5,13 +5,13 @@
# Synopsis
`nix-instantiate`
[`--parse` | `--eval` [`--strict`] [`--raw`] [`--json`] [`--xml`] ]
[`--parse` | `--eval` [`--strict`] [`--json`] [`--xml`] ]
[`--read-write-mode`]
[`--arg` *name* *value*]
[{`--attr`| `-A`} *attrPath*]
[`--add-root` *path*]
[`--expr` | `-E`]
*fileish*
*files*
`nix-instantiate` `--find-file` *files…*
@@ -25,11 +25,8 @@ of the resulting store derivations are printed on standard output.
[store derivation]: ../glossary.md#gloss-store-derivation
If *fileish* is the character `-`, then a Nix expression will be read from standard input.
Otherwise, each *fileish* is interpreted the same as with [nix-build](./nix-build.md#fileish-syntax).
See that section for complete details (`nix-build --help`), but in summary, a path argument may be one of:
{{#include ./fileish-summary.md}}
If *files* is the character `-`, then a Nix expression will be read from
standard input.
# Options
@@ -38,14 +35,7 @@ See that section for complete details (`nix-build --help`), but in summary, a pa
- `--parse`\
Just parse the input files, and print their abstract syntax trees on
standard output. The output format of the AST depends on the current
internal representation and may change in the future.
Tooling can use the stderr and exit code of `--parse` to check any
Nix code for correctness, but should not rely on stdout without careful
versioning. Note that `--parse` also checks for unbound variables.
In cases where this is undesired, `with {};` can be prepended
to the program to transform all such parse errors into eval errors.
standard output as a Nix expression.
- `--eval`\
Just parse and evaluate the input files, and print the resulting
@@ -107,27 +97,15 @@ See that section for complete details (`nix-build --help`), but in summary, a pa
> This option can cause non-termination, because lazy data
> structures can be infinitely large.
- `--raw`\
When used with `--eval`, the result must be coercible to a string, i.e.,
something that can be converted using `${...}`.
Integers will always generate an error when output via `--raw`, regardless of
[`coerce-integers`](../contributing/experimental-features.md#xp-feature-coerce-integers) being enabled, to avoid ambiguity.
The output is printed exactly as-is, with no quotes, escaping, or trailing
newline.
- `--json`\
When used with `--eval`, print the resulting value as an JSON
representation of the resulting value rather than as a Nix expression.
The conversion behaviour, if `--strict` is passed, is the same as
[`builtins.toJSON`](../language/builtins.md#builtins-toJSON).
representation of the abstract syntax tree rather than as a Nix expression.
- `--xml`\
When used with `--eval`, print the resulting value as an XML
representation of the resulting value rather than as a Nix expression.
The schema is the same as that used by [`builtins.toXML`](../language/builtins.md#builtins-toXML).
representation of the abstract syntax tree rather than as a Nix expression.
The schema is the same as that used by the [`toXML`
built-in](../language/builtins.md).
- `--read-write-mode`\
When used with `--eval`, perform evaluation in read/write mode so
+4 -3
View File
@@ -33,9 +33,10 @@ the environment of a derivation for development.
If *path* is not given, `nix-shell` defaults to `shell.nix` if it
exists, and `default.nix` otherwise.
If *path* is given it is interpreted like a [*fileish* argument to nix-build](./nix-build.md#fileish-syntax):
{{#include ./fileish-summary.md}}
If *path* starts with `http://` or `https://`, it is interpreted as the
URL of a tarball that will be downloaded and unpacked to a temporary
location. The tarball must include a single top-level directory
containing at least a file named `default.nix`.
If the derivation defines the variable `shellHook`, it will be run
after `$stdenv/setup` has been sourced. Since this hook is not executed
@@ -4,7 +4,7 @@
# Synopsis
`nix-store` `--delete` [`--ignore-liveness`] [`--skip-live`] [`--delete-closure`] *paths…*
`nix-store` `--delete` [`--ignore-liveness`] *paths…*
# Description
@@ -18,13 +18,6 @@ With the option `--ignore-liveness`, reachability from the roots is
ignored. However, the path still wont be deleted if there are other
paths in the store that refer to it (i.e., depend on it).
This operation will raise an error if any of the paths are still live
and `--ignore-liveness` is not passed. Passing `--skip-live` will
prevent this from being considered an error.
The option `--delete-closure` will also attempt to delete any paths
that are in the given path's dependency closure.
{{#include ./opt-common.md}}
{{#include ../opt-common.md}}
@@ -93,12 +93,9 @@ symlink.
[deriver]: ../../glossary.md#gloss-deriver
- `--valid-derivers`\
Prints the set of all [derivers](../../glossary.md#gloss-deriver) that can be
used to build the store paths *paths*.
This differs from `--deriver`, which prints the deriver that actually
produced *paths*.
No deriver may be returned if is not present in the store,
eg, if *paths* were substituted from a binary cache.
Prints a set of derivation files (`.drv`) which are supposed produce
said paths when realized. Might print nothing, for example for source paths
or paths subsituted from a binary cache.
- `--graph`\
Prints the references graph of the store paths *paths* in the format
@@ -15,6 +15,7 @@ Each of *paths* is processed as follows:
1. If it is not [valid], substitute the store derivation file itself.
2. Realise its [output paths]:
- Try to fetch from [substituters] the [store objects] associated with the output paths in the store derivation's [closure].
- With [content-addressed derivations] (experimental): Determine the output paths to realise by querying content-addressed realisation entries in the [Nix database].
- For any store paths that cannot be substituted, produce the required store objects. This involves first realising all outputs of the derivation's dependencies and then running the derivation's [`builder`](@docroot@/language/derivations.md#attr-builder) executable. <!-- TODO: Link to build process page #8888 -->
- Otherwise, and if the path is not already valid: Try to fetch the associated [store objects] in the path's [closure] from [substituters].
@@ -27,6 +28,7 @@ If no substitutes are available and no store derivation is given, realisation fa
[store objects]: @docroot@/glossary.md#gloss-store-object
[closure]: @docroot@/glossary.md#gloss-closure
[substituters]: @docroot@/command-ref/conf-file.md#conf-substituters
[content-addressed derivations]: @docroot@/contributing/experimental-features.md#xp-feature-ca-derivations
[Nix database]: @docroot@/glossary.md#gloss-nix-database
The resulting paths are printed on standard output.
+1 -1
View File
@@ -85,7 +85,7 @@ Most commands in Lix accept the following command-line options:
- `multiline-with-logs`
Display the raw logs, with a progress bar and activities each in a new line at the bottom.
Displayes the raw logs, with a progress bar and activities each in a new line at the bottom.
- <span id="opt-no-build-output">[`--no-build-output`](#opt-no-build-output)</span> / `-Q`
+2 -2
View File
@@ -661,8 +661,8 @@ Verbosity levels are:
The default level that the command starts is `ERROR`. The simplest way to
increase the verbosity by stacking `-v` option (eg: `-vvv == level 3 == INFO`).
Use `--quiet` to decrease verbosity by one level.
There is one shortcut, `--debug` to run in `DEBUG` verbosity level.
There are also two shortcuts, `--debug` to run in `DEBUG` verbosity level and
`--quiet` to run in `ERROR` verbosity level.
----------
+31 -89
View File
@@ -11,19 +11,7 @@ The following instructions assume you already have some version of Nix or Lix in
[installation instructions]: ../installation/installation.md
A typical development flow for simple changes in Lix looks like:
- [Set up and build Lix](#building)
- For large changes, check in regarding design and possibly create an RFD issue on Forgejo
- Make the changes in your editor
- [Send the changes to Gerrit](#sending-to-gerrit)
- Once you have the number for the CL from Gerrit to put in the changelog, [write a changelog entry](#release-notes) and amend it into the commit
- Update the Gerrit change by submitting it with the same command as the first time
- Request and receive a code review
- Address feedback from the review
- Amend commits, send to Gerrit again
- Submit the approved change
## Building Lix in a development shell {#building}
## Building Lix in a development shell
### Setting up the development shell
@@ -51,28 +39,17 @@ $ nix-shell -A native-clangStdenvPackages
### Building from the development shell
Run a clean build and test with `just clean setup build install test`.
You can also run the unit tests and integration tests separately:
You can build and test Lix with just:
```bash
$ just setup build test-unit
$ just install test-integration
$ just setup
$ just build
$ just test --suite=check
$ just install
$ just test --suite=installcheck
```
Many justfile aliases have a `-custom` variant which pass extra arguments to `meson`.
For example, to work on both Lix and nix-eval-jobs you can run:
```
$ just setup-custom -Dnix-eval-jobs=enabled
$ # or
$ mesonFlags=-Dnix-eval-jobs=enabled just setup
```
Note that only targets which don't accept extra arguments can be used when
running multiple targets at once; `just setup build` is fine, but `just
setup-custom build` is an error. The `test` target is usually the last one to
run, so it always accepts extra arguments.
(Check and installcheck may both be done after install, allowing you to omit the --suite argument entirely, but this is the order package.nix runs them in.)
You can also build Lix manually:
@@ -141,36 +118,7 @@ To inspect the canonical source of truth on what the state of the buildsystem co
$ meson introspect
```
## Sending changes to Gerrit for review {#sending-to-gerrit}
We use Gerrit for all our code review in Lix.
Our instance is at <https://gerrit.lix.systems>.
There's much more information about how to use Gerrit in the [wiki section on Gerrit][wiki-gerrit] including how to use Jujutsu, how to use the UI and more.
The Snix project also has some Gerrit information [in their contributing docs][snix-gerrit].
[wiki-gerrit]: https://wiki.lix.systems/books/lix-contributors/chapter/gerrit
[snix-gerrit]: https://snix.dev/docs/guides/contributing/
The gist is that once you have your SSH key and git remote set up, you can send commits for review with:
```
$ git remote set-url origin ssh://YOURUSERNAME@gerrit.lix.systems:2022/lix
$ git push origin HEAD:refs/for/main
```
Then, you can request a review via the "Reply" button on the web UI.
If you click "Suggest Owners", it will try to suggest the maintainers of the area of the code change to send review requests to.
Requesting reviews from multiple people is normal.
We do our best to respond to directly sent reviews in a few days, so feel free to request another reviewer or ask on Matrix if you've not got a response for a while.
Keep in mind that Lix is a volunteer project and we have limited bandwidth, so some changes aren't feasible to shepherd through; please check in on Matrix at design time when doing large changes.
Once you get a `Code-Review+2` vote on your change, it's rebased on `main` and CI marks it `Verified+1`, you're able (and usually expected, so you can have a second chance to check it over) to hit the Submit button to merge it.
If the change appears as "Rebase Required", you need to rebase it on `main` locally or via the Gerrit UI and wait for `Verified+1` before the Submit button is made active
The `Code-Review+2` from before will stick around through trivial rebases so no need to re-request review for a mere rebase.
## Building Lix with `nix`
## Building Lix outside of development shells
To build a release version of Lix for the current operating system and CPU architecture:
@@ -189,11 +137,10 @@ You can also build Lix for one of the [supported platforms](#platforms).
Lix can be built for various platforms, as specified in [`flake.nix`]:
[`flake.nix`]: https://git.lix.systems/lix-project/lix/src/branch/main/flake.nix
[`flake.nix`]: https://git.lix.systems/lix-project/lix/lix/branch/main/flake.nix
- `x86_64-linux`
- `x86_64-darwin`
- `x86_64-freebsd`
- `i686-linux`
- `aarch64-linux`
- `aarch64-darwin`
@@ -270,7 +217,7 @@ Lix uses a string with the following format to identify the *system type* or *pl
It is set when Lix is compiled for the given system, and determined by [Meson's `host_machine.cpu_family()` and `host_machine.system()` values](https://mesonbuild.com/Reference-manual_builtin_host_machine.html).
For historic reasons and backward-compatibility, some CPU and OS identifiers are translated from the GNU Autotools naming convention in [`meson.build`](https://git.lix.systems/lix-project/lix/src/branch/main/meson.build) as follows:
For historic reasons and backward-compatibility, some CPU and OS identifiers are translated from the GNU Autotools naming convention in [`meson.build`](https://git.lix.systems/lix-project/lix/blob/main/meson.build) as follows:
| `host_machine.cpu_family()` | Nix |
|----------------------------|---------------------|
@@ -297,13 +244,13 @@ To build with one of those environments, you can use
$ nix build .#nix-ccacheStdenv
```
for <a id="nix-with-flakes">flake-enabled Nix</a>, or
for flake-enabled Nix, or
```console
$ nix-build --attr nix-ccacheStdenv
```
for <a id="classic-nix">classic Nix</a>.
for classic Nix.
You can use any of the other supported environments in place of `nix-ccacheStdenv`.
@@ -327,10 +274,10 @@ Configure your editor to use the `clangd` from the shell, either by running it i
> Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs and [vim-lsp](https://github.com/prabirshrestha/vim-lsp) for vim).
> Editor-specific setup is typically opinionated, so we will not cover it here in more detail.
# Manual and documentation
## Building the manual
### Checking links in the manual
The build checks for broken internal links.
This happens late in the process, so `nix build` is not suitable for iterating.
To build the manual incrementally, run:
```console
@@ -342,20 +289,15 @@ meson compile -C build manual
[`mdbook-linkcheck`]: https://github.com/Michael-F-Bryan/mdbook-linkcheck
[URI fragments]: https://en.wikipedia.org/wiki/URI_fragment
The built manual is in `build/doc/manual/manual/index.html`.
#### `@docroot@` variable
The build checks for broken internal links.
This happens late in the process, so `nix build` is not suitable for iterating and it's recommended to use the `meson` command above instead.
`@docroot@` provides a base path for links that occur in reusable snippets or other documentation that doesn't have a base path of its own.
### `@\docroot\@` variable
If a broken link occurs in a snippet that was inserted into multiple generated files in different directories, use `@docroot@` to reference the `doc/manual/src` directory.
`@\docroot\@` provides a base path for links that occur in reusable snippets or other documentation that doesn't have a base path of its own.
If a broken link occurs in a snippet that was inserted into multiple generated files in different directories, use `@\docroot\@` to reference the `doc/manual/src` directory.
If the `@\docroot\@` literal appears in an error message from the `mdbook-linkcheck` tool, the `@\docroot\@` replacement needs to be applied to the generated source file that mentions it.
See existing `@\docroot\@` logic in `doc/manual/substitute.py`.
Regular markdown files used for the manual have a base path of their own and they can use relative paths instead of `@\docroot\@`.
If the `@docroot@` literal appears in an error message from the `mdbook-linkcheck` tool, the `@docroot@` replacement needs to be applied to the generated source file that mentions it.
See existing `@docroot@` logic in the [Makefile].
Regular markdown files used for the manual have a base path of their own and they can use relative paths instead of `@docroot@`.
## API documentation
@@ -387,7 +329,7 @@ You can build it yourself:
Metrics about the change in line/function coverage over time will be available in the future (FIXME(lix-hydra)).
## Add a release note {#release-notes}
## Add a release note
`doc/manual/rl-next` contains release notes entries for all unreleased changes.
@@ -456,15 +398,15 @@ The following properties are supported:
### Build process
Releases have a precomputed `rl-MAJOR.MINOR.md`, and no `rl-next.md`.
Development releases have a generated `rl-next.md`.
Set `buildUnreleasedNotes = true;` in `flake.nix` to build the release notes on the fly.
# Adding experimental or deprecated features, global settings, or builtins
## Adding experimental or deprecated features, global settings, or builtins
Experimental and deprecated features, global settings, and builtins are generally referenced both in the code and in the documentation.
To prevent duplication or divergence, they are defined in data files, and a script generates the necessary glue.
The data file format is similar to the release notes: it consists of a YAML metadata header, followed by the documentation in Markdown format.
## Experimental or deprecated features
### Experimental or deprecated features
Experimental and deprecated features support the following metadata properties:
* `name` (required): user-facing name of the feature, to be used in `nix.conf` options and on the command line.
@@ -474,7 +416,7 @@ Experimental and deprecated features support the following metadata properties:
Experimental feature data files should live in `lix/libutil/experimental-features`, and deprecated features in `lix/libutil/deprecated-features`.
They must be listed in the `experimental_feature_definitions` or `deprecated_feature_definitions` lists in `lix/libutil/meson.build` respectively to be considered by the build system.
## Global settings
### Global settings
Global settings support the following metadata properties:
* `name` (required): user-facing name of the setting, to be used as key in `nix.conf` and in the `--option` command line argument.
@@ -502,23 +444,23 @@ Settings are not collected in a single place in the source tree, so an appropria
Look for related setting definition files under second-level subdirectories of `lix` whose name includes `settings`.
Then add the new file there, and don't forget to register it in the appropriate `meson.build` file.
## Builtin functions
### Builtin functions
The following metadata properties are supported for builtin functions:
* `name` (required): the language-facing name (as a member of the `builtins` attribute set) of the function.
* `implementation` (optional): a C++ expression specifying the implementation of the builtin.
It must be a function of signature `void(EvalState &, PosIdx, Value * *, Value &)`.
If not specified, defaults to `prim_${name}`.
* `renameInGlobalScope` (optional): whether the definition should be "hidden" in the global scope by prefixing its name with two underscores.
* `renameInGlobalScope` (optional): whether the definiton should be "hidden" in the global scope by prefixing its name with two underscores.
If not specified, defaults to `true`.
* `args` (required): list containing the names of the arguments, as shown in the documentation.
All arguments must be listed here since the function arity is derived as the length of this list.
* `experimental_feature` (optional): the user-facing name of the experimental feature which needs to be enabled for the builtin function to be available.
* `experimental_feature` (optional): the user-facing name of the experimental feature which needs to be enabled for the bultin function to be available.
If not specified, no experimental feature is required.
New builtin function definition files must be added to `lix/libexpr/builtins` and registered in the `builtin_definitions` list in `lix/libexpr/meson.build`.
## Builtin constants
### Builtin constants
The following metadata properties are supported for builtin constants:
* `name` (required): the language-facing name (as a member of the `builtins` attribute set) of the constant.
* `type` (required): the Nix language type of the constant; the C++ type is automatically derived.
+3
View File
@@ -449,6 +449,9 @@ I grepped `lix/` for `get[eE]nv\("` to find the mentions in Lix code.
- `NIX_CLIENT_PACKAGE` - Runs the test suite against an alternate Nix client with the current daemon.
**Expected value**: something like `/nix/store/...-nix-2.18.2`
- `NIX_TESTS_CA_BY_DEFAULT` - Pass `__contentAddressed`, `outputHashMode` and `outputHashAlgo` to builds of some input-addressed derivations in the test suite.
**Expected value**: 1
- `TEST_DATA` - Not an environment variable! This is used in repl characterization tests to refer to `tests/functional/repl_characterization/data`.
More specifically, that path is replaced with the string `$TEST_DATA` in output for reproducibility.
- `TEST_HOME` (output) - Set to the temporary directory that is set as `$HOME` inside the tests, underneath `$TEST_ROOT`.
+10 -3
View File
@@ -41,6 +41,12 @@
[realise]: #gloss-realise
- [content-addressed derivation]{#gloss-content-addressed-derivation}
A derivation which has the
[`__contentAddressed`](./language/advanced-attributes.md#adv-attr-__contentAddressed)
attribute set to `true`.
- [fixed-output derivation]{#gloss-fixed-output-derivation}
A derivation which includes the
@@ -95,7 +101,7 @@
See [File System Object](@docroot@/architecture/file-system-object.md) for details.
[file system object]: #gloss-store-path
[file system object]: #gloss-file-system-object
- [store object]{#gloss-store-object}
@@ -108,13 +114,14 @@
- [input-addressed store object]{#gloss-input-addressed-store-object}
A store object produced by building a
non-[content-addressed](#gloss-content-addressed-derivation),
non-[fixed-output](#gloss-fixed-output-derivation)
derivation.
- [output-addressed store object]{#gloss-output-addressed-store-object}
A [store object] whose [store path] is determined by its contents.
This includes derivations and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
This includes derivations, the outputs of [content-addressed derivations](#gloss-content-addressed-derivation), and the outputs of [fixed-output derivations](#gloss-fixed-output-derivation).
- [substitute]{#gloss-substitute}
@@ -242,7 +249,7 @@
links. NARs are generated and unpacked using `nix-store --dump`
and `nix-store --restore`.
- [`∅`]{#gloss-empty-set}
- [`∅`]{#gloss-emtpy-set}
The empty set symbol. In the context of profile history, this denotes a package is not present in a particular version of the profile.
@@ -54,6 +54,11 @@ The most current alternative to this section is to read `package.nix` and see wh
obtained from the its repository
<https://github.com/troglobit/editline>.
- The `libsodium` library for verifying cryptographic signatures
of contents fetched from binary caches.
It can be obtained from the official web site
<https://libsodium.org>.
- Recent versions of Bison and Flex to build the parser. (This is
because Nix needs GLR support in Bison and reentrancy support in
Flex.) For Bison, you need version 2.6, which can be obtained from
+1 -1
View File
@@ -148,7 +148,7 @@ paths) are set.
For example, the following command gets all dependencies of the
Pan newsreader, as described by [its
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pa/pan/package.nix):
Nix expression](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/networking/newsreaders/pan/default.nix):
```console
$ nix-shell '<nixpkgs>' --attr pan
+12 -3
View File
@@ -209,8 +209,15 @@ Derivations can declare some infrequently used optional attributes.
- [`__contentAddressed`]{#adv-attr-__contentAddressed}
> **Warning**
> This attribute is part of a removed [experimental feature](@docroot@/contributing/experimental-features.md).
> Setting this flag *will* cause eval errors.
> This attribute is part of an [experimental feature](@docroot@/contributing/experimental-features.md).
>
> To use this attribute, you must enable the
> [`ca-derivations`](@docroot@/contributing/experimental-features.md#xp-feature-ca-derivations) experimental feature.
> For example, in [nix.conf](../command-ref/conf-file.md) you could add:
>
> ```
> extra-experimental-features = ca-derivations
> ```
If this attribute is set to `true`, then the derivation
outputs will be stored in a content-addressed location rather than the
@@ -254,7 +261,7 @@ Derivations can declare some infrequently used optional attributes.
useful for very trivial derivations (such as `writeText` in Nixpkgs)
that are cheaper to build than to substitute from a binary cache.
You may disable the effects of this attribute by enabling the
You may disable the effects of this attibute by enabling the
`always-allow-substitutes` configuration option in Lix.
> **Note**
@@ -302,6 +309,8 @@ Derivations can declare some infrequently used optional attributes.
- `maxSize` defines the maximum size of the resulting [store object](../glossary.md#gloss-store-object).
- `maxClosureSize` defines the maximum size of the output's closure.
- `ignoreSelfRefs` controls whether self-references should be considered when
checking for allowed references/requisites.
Example:
+1 -1
View File
@@ -164,7 +164,7 @@ Note that lists are only lazy in values, and they are strict in length.
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
An attribute name can be an identifier or a [string](#type-string).
An attribute name can be an identifier or a [string](#string).
An identifier must start with a letter (`a-z`, `A-Z`) or underscore (`_`), and can otherwise contain letters (`a-z`, `A-Z`), numbers (`0-9`), underscores (`_`), apostrophes (`'`), or dashes (`-`).
> *name* = *identifier* | *string* \
@@ -126,7 +126,7 @@ $ nix-env --install --attr nixpkgs.subversion
```
will install the package called `subversion` from `nixpkgs` channel (which is, of course, the
[Subversion version management system](https://subversion.apache.org/)).
[Subversion version management system](http://subversion.tigris.org/)).
> **Note**
>
@@ -71,62 +71,3 @@ $ nix-collect-garbage -d
```
is a quick and easy way to clean up your system.
## Garbage Collector Roots
### Explicit roots
All store paths to which there are symlinks in the directory
`prefix/nix/var/nix/gcroots` will be used as roots by the garbage
collector. For instance, the following command makes the path
`/nix/store/d718ef...-foo` a root of the collector:
```console
$ ln -s /nix/store/d718ef...-foo /nix/var/nix/gcroots/bar
```
That is, after this command, the garbage collector will not remove
`/nix/store/d718ef...-foo` or any of its dependencies.
Subdirectories of `prefix/nix/var/nix/gcroots` are also searched for
symlinks.
Symlinks may also point to paths outside the nix store. If the
destination of the symlink is itself a symlink to a store path, it
is also considered a root. This style of GC root is called an
"indirect root", and is created by tools like `nix-build` to avoid
garbage-collecting paths that are being used on-the-fly rather than
installed in profiles.
### In-use roots
Lix will also perform a best-effort detection of paths that are in use
by running processes when scanning for garbage collection roots, to
avoid removing paths that are still needed by running processes.
Exact details vary between platforms, but the following will generally
be taken into account:
- Executables in the store that are currently running;
- Other files in the store that are mapped into a process's address space (e.g. shared libraries);
- Files in the store to which processes have open handles;
- Store paths found in processes' environment variables.
Note that this detection is susceptible to missing paths that may still be in use for multiple reasons:
- Time-of-check-to-time-of-use (TOCTTOU): new processes may appear
after Lix has enumerated the currently running processes, and will
not be taken into account;
- Access privileges: if the garbage collection is not running as the
root user (this is typically the case for single-user
installations), it will not be able to scan processes belonging to
other users;
- Other types of references: store paths may be stored in parts of the
filesystem (e.g. databases) or process memory (e.g. environment
variables changed since the start of the process) that Lix does not
scan.
For this reason, it is recommended to create explicit roots whenever
using store paths that aren't obtained from some existing explicit GC
root.
@@ -0,0 +1,18 @@
# Garbage Collector Roots
The roots of the garbage collector are all store paths to which there
are symlinks in the directory `prefix/nix/var/nix/gcroots`. For
instance, the following command makes the path
`/nix/store/d718ef...-foo` a root of the collector:
```console
$ ln -s /nix/store/d718ef...-foo /nix/var/nix/gcroots/bar
```
That is, after this command, the garbage collector will not remove
`/nix/store/d718ef...-foo` or any of its dependencies.
Subdirectories of `prefix/nix/var/nix/gcroots` are also searched for
symlinks. Symlinks to non-store paths are followed and searched for
roots, but symlinks to non-store paths *inside* the paths reached in
that way are not followed to prevent infinite recursion.
+14 -4
View File
@@ -2,8 +2,18 @@
For historical reasons, [derivations](@docroot@/glossary.md#gloss-store-derivation) are stored on-disk in [ATerm](https://homepages.cwi.nl/~daybuild/daily-books/technology/aterm-guide/aterm-guide.html) format.
Derivations are serialised in the following format:
Derivations are serialised in one of the following formats:
```
Derive(...)
```
- ```
Derive(...)
```
For all stable derivations.
- ```
DrvWithVersion(<version-string>, ...)
```
The only `version-string`s that are in use today are for [experimental features](@docroot@/contributing/experimental-features.md):
- `"xp-dyn-drv"` for the [`dynamic-derivations`](@docroot@/contributing/experimental-features.md#xp-feature-dynamic-derivations) experimental feature.
+1 -1
View File
@@ -13,7 +13,7 @@
- The `discard-references` feature has been stabilized.
This means that the
`unsafeDiscardReferences`
[unsafeDiscardReferences](@docroot@/contributing/experimental-features.md#xp-feature-discard-references)
attribute is no longer guarded by an experimental flag and can be used
freely.
+135 -2
View File
@@ -1,4 +1,137 @@
# Lix 2.92 "Bombe glacée" (2025-01-18)
# Lix 2.92.3 (2025-06-30)
## Fixes
- Revert CVE-2025-52992 failed mitigation [fj#883](https://git.lix.systems/lix-project/lix/issues/883) [fj#887](https://git.lix.systems/lix-project/lix/issues/887) [cl/3432](https://gerrit.lix.systems/c/lix/+/3432) [cl/3525](https://gerrit.lix.systems/c/lix/+/3525) [cl/3526](https://gerrit.lix.systems/c/lix/+/3526) [cl/3527](https://gerrit.lix.systems/c/lix/+/3527)
Following the initial mitigation of **CVE-2025-52992** in `cl/3432`, we
received reports of **unexpected deletion of in-use store paths**.
Upon investigation, we found that the patch did **not correctly cancel all
automatic deleters**, resulting in potentially critical path loss during normal
operation.
Given the severity and time-sensitive nature of the situation ([see incident
report](https://lix.systems/blog/2025-06-27-lix-critical-bug/)), we evaluated
possible options to repair the behavior safely. However, we concluded that a
rushed fix would either
* **Overdelete**, i.e. breaking running systems, or,
* **Underdelete**, effectively **reopening CVE-2025-52992** while leaving
orphaned paths behind.
As **CVE-2025-52992 has no known exploit vector**, and correctness is critical
in the Lix project, we have **fully reverted the previous mitigations**.
The affected patches (`cl/3432`) have been rolled back for the time being.
Moving forward, the Lix team will rework this code path in a **long-term,
correctness-first fix** on the main branch. We will explore backporting it to
stable channels once its safety is assured.
We are deeply sorry for the stability incident and the Lix team remain
available for assisting you in recovering your systems.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Fallback to safe temp dir when build-dir is unwritable [fj#876](https://git.lix.systems/lix-project/lix/issues/876) [cl/3503](https://gerrit.lix.systems/c/lix/+/3503)
Non-daemon builds started failing with a permission error after introducing the `build-dir` option:
```
$ nix build --store ~/scratch nixpkgs#hello --rebuild
error: creating directory '/nix/var/nix/builds/nix-build-hello-2.12.2.drv-0': Permission denied
```
This happens because:
1. These builds are not run via the daemon, which owns `/nix/var/nix/builds`.
2. The user lacks permissions for that path.
We considered making `build-dir` a store-level option and defaulting it to `<chroot-root>/nix/var/nix/builds` for chroot stores, but opted instead for a fallback: if the default fails, Nix now creates a safe build directory under `/tmp`.
To avoid CVE-2025-52991, the fallback uses an extra path component between `/tmp` and the build dir.
**Note**: this fallback clutters `/tmp` with build directories that are not cleaned up. To prevent this, explicitly set `build-dir` to a path managed by Lix, even for local workloads.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
# Lix 2.92.2 (2025-06-23)
## Breaking Changes
- Fixed output derivations can be run using `pasta` network isolation [fj#285](https://git.lix.systems/lix-project/lix/issues/285) [cl/3430](https://gerrit.lix.systems/c/lix/+/3430)
Fixed output derivations traditionally run in the host network namespace.
On Linux this allows such derivations to communicate with other sandboxes
or the host using the abstract Unix domains socket namespace; this hasn't
been unproblematic in the past and has been used in two distinct exploits
to break out of the sandbox. For this reason fixed output derivations can
now run in a network namespace (provided by [`pasta`]), restricted to TCP
and UDP communication with the rest of the world. When enabled this could
be a breaking change and we classify it as such, even though we don't yet
enable or require such isolation by default. We may enforce this in later
releases of Lix once we have sufficient confidence that breakage is rare.
[`pasta`]: https://passt.top/
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) and [puck](https://git.lix.systems/puck) for this.
## Fixes
- Always clean up scratch paths after derivations failed to build [cl/3432](https://gerrit.lix.systems/c/lix/+/3432)
Previously, scratch paths created during builds were not always cleaned up if
the derivation failed, potentially leaving behind unnecessary temporary files
or directories in the Nix store.
This fix ensures that such paths are consistently removed after a failed build,
improving Nix store hygiene, hardening Lix against mis-reuse of failed builds
scratch paths.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
- `build-dir` no longer defaults to `temp-dir` [cl/3431](https://gerrit.lix.systems/c/lix/+/3431)
The directory in which temporary build directories are created no longer defaults
to the value of the `temp-dir` setting to avoid builders making their directories
world-accessible. This behavior has been used to escape the build sandbox and can
cause build impurities even when not used maliciously. We now default to `builds`
in `NIX_STATE_DIR` (which is `/nix/var/nix/builds` in the default configuration).
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Forbid impure path accesses in pure evaluation mode again [cl/2708](https://gerrit.lix.systems/c/lix/+/2708)
Lix 2.92.0 mistakenly started allowing the access to ancestors of allowed paths in pure evaluation mode.
This made it possible to bypass the purity restrictions, for example by copying arbitrary files to the store:
```nix
builtins.path {
path = "/";
filter = …;
}
```
Restore the previous behaviour of prohibiting such impure accesses.
Many thanks to [alois31](https://git.lix.systems/alois31) for this.
- Parsing failures in flake.lock no longer crash Lix [fj#559](https://git.lix.systems/lix-project/lix/issues/559) [cl/2401](https://gerrit.lix.systems/c/lix/+/2401)
Failure to parse `flake.lock` no longer hard-crashes Lix and instead produces a nice error message.
```
error:
… while updating the lock file of flake 'git+file:///Users/jade/lix/lix2'
… while parsing the lock file at /nix/store/mm5dqh8a729yazzj82cjffxl97n5c62s-source//flake.lock
error: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal;
last read: '#'
```
Many thanks to [gilice](https://git.lix.systems/gilice) for this.
- Fix `--debugger --ignore-try` [cl/2440](https://gerrit.lix.systems/c/lix/+/2440)
When in debug mode (e.g. from using the `--debugger` flag), enabling [`ignore-try`](@docroot@/command-ref/conf-file.md#conf-ignore-try) once again properly disables debug REPLs within [`builtins.tryEval`](@docroot@/language/builtins.md#builtins-tryEval) calls. Previously, a debug REPL would be started as if `ignore-try` was disabled, but that REPL wouldn't actually be in debug mode, and upon exiting the REPL the evaluating process would segfault.
Many thanks to [Dusk Banks](https://git.lix.systems/bb010g) for this.
# Lix 2.92.0 (2025-01-18)
@@ -51,8 +184,8 @@
{
formatter = eachSystem (pkgs:
pkgs.writeShellScriptBin "formatter" ''
if [[ $# = 0 ]]; then set -- .; fi
exec "${pkgs.nixfmt-rfc-style}/bin/nixfmt" "$@"
if [[ $# = 0 ]]; set -- .; fi
exec "${pkgs.nixfmt-rfc-style}/bin/nixfmt "$@"
'');
};
}
-715
View File
@@ -1,715 +0,0 @@
# Lix 2.93 "Bici Bici" (2025-05-09)
# Lix 2.93.0 (2025-05-09)
## Breaking Changes
- more deprecated features
This release cycle features a new batch of deprecated (anti-)features.
You can opt in into the old behavior with `--extra-deprecated-features` or any equivalent configuration option.
- `cr-line-endings`: Current handling of CR (`\r`) or CRLF (`\r\n`) line endings in Nix is inconsistent and broken, and will lead to unexpected evaluation results with certain strings. Given that fixing the semantics might silently alter the evaluation result of derivations, the only option at the moment is to disallow them altogether. More proper support for CRLF is planned to be added back again in the future. Until then, all files must use `\n` exclusively.
- `nul-bytes`: Currently the Nix grammar allows NUL bytes (`\0`) in strings, and thus indirectly also in identifiers. Unfortunately, several core parts of the code base still work with NUL-terminated strings and cannot easily be migrated. Also note that it is still possible to introduce NUL bytes and thus problematic behavior via other means, those are tracked separately.
Many thanks to [piegames](https://git.lix.systems/piegames) and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Removal of the `recursive-nix` experimental feature [fj#767](https://git.lix.systems/lix-project/lix/issues/767) [cl/2872](https://gerrit.lix.systems/c/lix/+/2872)
The `recursive-nix` experimental feature and all associated code have been removed.
`recursive-nix` enabled running Nix operations (like evaluations and builds) *inside* a derivation builder. This worked by spawning a temporary Nix daemon socket within the build environment, allowing the derivation to emit outputs that appeared in the outer store. This was primarily used to prototype **dynamic derivations** (dyndrvs), where build plans are generated on-the-fly during a build.
However, this approach introduced critical issues:
- It entrenched the legacy Nix daemon protocol as part of the derivation ABI, which is a blocker for future stabilization.
- It imposed tight coupling between sandbox setup code and knowledge of Nix internals, complicating refactoring and long-term maintenance.
- It was never intended to be the final design for dynamic derivations. The original Nix implementation team, who are leading dyndrv development, have agreed it will be replaced (likely via `varlink` or similar) before any stabilization.
- There is currently no known usage of `recursive-nix` on `lix` or elsewhere **in production**.
If you're using `recursive-nix` for something niche or experimental, we'd love to hear from you on the RFD issue.
You can still run `nix` inside a builder manually if needed — including with isolated user namespaces and fake stores — but the special daemon-handshake machinery is gone.
This removal unblocks several important internal cleanups.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Flake inputs/`builtins.fetchTree` invocations with `type = "file"` now have consistent (but different from previous versions) resulting paths [fj#750](https://git.lix.systems/lix-project/lix/issues/750) [cl/2864](https://gerrit.lix.systems/c/lix/+/2864)
Previously `fetchTree { type = "file"; url = "...", narHash = "sha256-..."; }` could return a different result depending on whether someone has run `nix store add-path --name source ...` on a path with the same `narHash` as the flake input/`fetchTree` invocation (or if such a path exists in an accessible binary cache).
In the past `type = "file"` flake inputs were, in contrast to all other flake inputs, hashed in *flat* hash mode rather than *recursive* hash mode.
The difference between the two is that *flat* mode hashes are just what you get from `sha256sum` of a single file, whereas *recursive* hashes are the SHA256 sum of a NAR (Nix ARchive, a deterministic tarball-like format) of a file tree.
Much of flakes assumes that everything is recursive-hashed including `nix flake archive`, substitution of flake inputs from binary caches, and more, which led to the substitution path code being taken if such a path is present, yielding a different store path non-deterministically.
To fix this non-deterministic evaluation bug, we needed to break derivation hash stability, so some Nix evaluations now produce different results than previous versions of Lix.
Lix now has consistent behaviour with CppNix 2.24 with respect to `file` flake inputs: they are *always* recursively hashed.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Builders are always started in a fresh cgroup namespace [cl/1996](https://gerrit.lix.systems/c/lix/+/1996)
If you haven't enabled the experimental `cgroups` feature, Nix previously launched builder processes in new namespaces but did not create new cgroup namespaces. As a result, derivations could access and observe the parent cgroup namespace.
Although this update introduces a breaking change, it ensures that all derivations now start in a fresh cgroup namespace by default. This reduces potential impurities observable within the sandbox, improving the likelihood of reproducible builds across different environments.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- `nix-instantiate --parse` outputs json [fj#487](https://git.lix.systems/lix-project/lix/issues/487) [nix#11124](https://github.com/NixOS/nix/issues/11124) [nix#4726](https://github.com/NixOS/nix/issues/4726) [nix#3077](https://github.com/NixOS/nix/issues/3077) [cl/2190](https://gerrit.lix.systems/c/lix/+/2190)
`nix-instantiate --parse` does not print out the AST in a Nix-like format anymore.
Instead, it now prints a JSON representation of the internal expression tree.
Tooling should not rely on the stdout of `nix-instantiate --parse`.
We've done our best to ensure that the new behavior is as compatible with the old one as possible.
If you depend on the old behavior in ways that are not covered anymore or are otherwise negatively affected by this change,
then please reach out so that we can find a sustainable solution together.
Many thanks to [piegames](https://git.lix.systems/piegames) and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Remove experimental repl-flake [gh#10103](https://github.com/NixOS/nix/issues/10103) [fj#557](https://git.lix.systems/lix-project/lix/issues/557) [gh#10299](https://github.com/NixOS/nix/pull/10299) [cl/2147](https://gerrit.lix.systems/c/lix/+/2147)
The `repl-flake` experimental feature flag has been removed, its functionality is now the default when `flakes` experimental feature is active. The `nix repl` command now works like the rest of the new CLI in that `nix repl {path}` now tries to load a flake at `{path}` (or fails if the `flakes` experimental feature isn't enabled).
Many thanks to [Jonathan De Troye](https://github.com/detroyejr) and [KFears](https://git.lix.systems/kfearsoff) for this.
## Features
- `lix foo` now invokes `lix-foo` from PATH [cl/2119](https://gerrit.lix.systems/c/lix/+/2119)
Lix introduces the ability to extend the Nix command line by adding custom
binaries to the `PATH`, similar to how Git integrates with other tools. This
feature allows developers and end users to enhance their workflow by
integrating additional functionalities directly into the Nix CLI.
#### Examples
For example, a user can create a custom deployment tool, `lix-deploy-tool`, and
place it in their `PATH`. This allows them to execute `lix deploy-tool`
directly from the command line, streamlining the process of deploying
applications without needing to switch contexts or use separate commands.
#### Limitations
For now, autocompletion is supported to discover new custom commands, but the
documentation will not render them. Argument autocompletion of the custom
command is not supported either.
This is also locked behind a new experimental feature called
`lix-custom-sub-commands` to enable developing all the required features.
Only the top-level `lix` command can be extended, this is an artificial
limitation for the time being until we flesh out this feature.
#### Outline
In the future, this feature may pave the way for moving the Flake subcommand
line to its own standalone binary, allowing for a more focused approach to
managing Nix Flakes while letting the community explore alternatives to
dependency management.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- `nix-env --install` now accepts a `--priority` flag [cl/2607](https://gerrit.lix.systems/c/lix/+/2607)
`nix-env --install` now has an optional `--priority` flag.
Previously, it was only possible to specify a priority by adding a
`meta.priority` attribute to a derivation. `meta` attributes only exist during
eval, so that wouldn't work for installing a store path. It was also possible
to change a priority after initial installation using `nix-env --set-flag`,
however if there is already a conflict that needs to be resolved via priorities,
this will not work.
Now, a priority can be set at install time using `--priority`, which allows for
cleanly overriding the priority at install time.
#### Example
```console
$ nix-build
$ nix-env --install --priority 100 ./result
```
Many thanks to [Andrew Hamon](https://github.com/andrewhamon) for this.
- Add support for eBPF USDT/dtrace probes inside Lix [fj#727](https://git.lix.systems/lix-project/lix/issues/727) [cl/2884](https://gerrit.lix.systems/c/lix/+/2884)
eBPF tracers like `bpftrace` and `dtrace` are a group of similar tools for debugging production systems.
User-space statically defined tracing probes (USDT) allow for defining zero or near-zero disabled-probe-effect probes, thus allowing instrumentation of hot paths in production builds.
Lix now has internal support for defining these probes and has shipped its first probe.
As of this writing it is available by default in the Linux build of Lix.
To try it out on Linux, you can use the following example command:
```
$ sudo bpftrace -l 'usdt:/path/to/liblixstore.so:*:*'
usdt:/path/to/liblixstore.so:lix_store:filetransfer__read
$ sudo bpftrace -e 'usdt:*:lix_store:filetransfer__read { printf("%s read %d\n", str(arg0), arg1); }'
Attaching 1 probe...
https://cache.nixos.org/wvpzaycmvs39h5bcsfrxkjsg48mj4h73.narinf.. read 8192
https://cache.nixos.org/wvpzaycmvs39h5bcsfrxkjsg48mj4h73.narinf.. read 8192
https://cache.nixos.org/nar/1qshsc30nlarzdig0v9b1aasdkwaxhnv0a0.. read 65536
https://cache.nixos.org/nar/1qshsc30nlarzdig0v9b1aasdkwaxhnv0a0.. read 65536
```
Note that bpftrace does not offer any way to list the arguments to USDT probes in a human readable form.
To get the probe definitions, see the `*.d` files in the Lix source code, for example, `lix/libstore/trace-probes.d`.
For more resources on eBPF/bpftrace and dtrace, see:
* The book "BPF Performance Tools" by Brendan Gregg, which discusses bpftrace at length.
* <https://ebpf.io/get-started/>
* [Illumos' dtrace book](https://illumos.org/books/dtrace/preface.html)
Many thanks to [jade](https://git.lix.systems/jade) for this.
## Improvements
- Always print `post-build-hook` logs [fj#675](https://git.lix.systems/lix-project/lix/issues/675) [cl/2801](https://gerrit.lix.systems/c/lix/+/2801)
Logs of `post-build-hook` are now printed unconditionally.
They used to be tied to whether print-build-logs is set, which made debugging them a nightmare when they fail, since the failure output would be eaten if build logs are disabled.
Most usages of `post-build-hook` are pretty quiet especially compared to build logs, so it should not be that bothersome to not be able to turn off.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Crashes land in syslog now [cl/2640](https://gerrit.lix.systems/c/lix/+/2640)
When Lix crashes with unexpected exceptions and in some other conditions, it prints bug reporting instructions.
Previously, these only landed in stderr and not in syslog.
However, on larger Lix installations, it may be the case that Lix crashes in the client without the logs landing in the system logs, which impeded diagnosis.
Now, such crashes always land in syslog too.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Deletion of specific paths no longer fails fast [cl/2778](https://gerrit.lix.systems/c/lix/+/2778)
`nix-store --delete` and `nix store delete` now continue deleting
paths even if some of the given paths are still live. An error is only
thrown once deletion of all the given paths has been
attempted. Previously, if some paths were deletable and others
weren't, the deletable ones would be deleted iff they preceded the
live ones in lexical sort order.
The error message for still-live paths no longer reports the paths
that could not be deleted, because there could potentially be many of
these.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- `--skip-live` for path deletion [cl/2778](https://gerrit.lix.systems/c/lix/+/2778)
`nix-store --delete` and `nix store delete` now support a
`--skip-live` option and a `--delete-closure` option.
This makes custom garbage-collection logic a lot easier to implement
and experiment with:
- Paths known to be large can be thrown at `nix store delete` without
having to manually filter out those that are still reachable from a
root, e.g.
`nix store delete /nix/store/*mbrola-voices*`
- The `--delete-closure` option allows extending this to paths that are
not large themselves but do have a large closure size, e.g.
`nix store delete /nix/store/*nixos-system-gamingpc*`.
- Other heuristics like atime-based deletion can be applied more
easily, because `nix store delete` once again takes over the task of
working out which paths can't be deleted.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Allow `nix store diff-closures` to output JSON [cl/2360](https://gerrit.lix.systems/c/lix/+/2360)
Add the `--json` option to the `nix store diff-closures` command to allow users to collect diff information into a machine readable format.
```bash
$ build/lix/nix/nix store diff-closures --json /run/current-system /nix/store/n1prick95pihd4lkv58nn3pzg1yivcdb-neovim-0.10.4/bin/nvim | jq | head -n 23
{
"packages": {
"02overridedns": {
"sizeDelta": -688,
"versionsAfter": [],
"versionsBefore": [
""
]
},
"50-coredump.conf": {
"sizeDelta": -1976,
"versionsAfter": [],
"versionsBefore": [
""
]
},
"Diff": {
"sizeDelta": -514864,
"versionsAfter": [],
"versionsBefore": [
"0.4.1"
]
},
```
Many thanks to [Xavier Maso](https://github.com/pamplemousse) for this.
- Show all missing and unexpected arguments in erroneous function calls [cl/2477](https://gerrit.lix.systems/c/lix/+/2477)
When calling a function that expects an attribute set, lix will now show all
missing and unexpected arguments.
e.g. with `({ a, b, c } : a + b + c) { a = 1; d = 1; }` lix will now show the error:
```
[...]
error: function 'anonymous lambda' called without required arguments 'b' and 'c' and with unexpected argument 'd'
[...]
```
Previously lix would just show `b`.
Furthermore lix will now only suggest arguments that aren't yet used.
e.g. with `({ a?1, b?1, c?1 } : a + b + c) { a = 1; d = 1; e = 1; }` lix will now show the error:
```
[...]
error: function 'anonymous lambda' called with unexpected arguments 'd' and 'e'
at «string»:1:2:
1| ({ a?1, b?1, c?1 } : a + b + c) { a = 1; d = 1; e = 1; }
| ^
Did you mean one of b or c?
```
Previously lix would also suggest `a`.
Suggestions are unfortunately still currently just for the first missing argument.
Many thanks to [Zitrone](https://git.lix.systems/quantenzitrone) for this.
- REPL improvements [cl/2319](https://gerrit.lix.systems/c/lix/+/2319) [cl/2320](https://gerrit.lix.systems/c/lix/+/2320) [cl/2321](https://gerrit.lix.systems/c/lix/+/2321)
The REPL has seen various minor improvements:
- Variable declarations have been improved, making copy-pasting code from attrsets a lot easier:
- Declarations can now optionally end with a semicolon
- Multiple declarations can be done within one command, separated by semicolon
- The `foo.bar = "baz";` syntax from attrsets is also supported, however without the attrset merging rules and with restrictions on dynamic attrs like in `let` bindings.
- Variable names now use the proper Nix grammar rules, instead of a regex that only vaguely matched legal identifiers.
- Better error messages overall
- The `:env` command to print currently available variables now also works outside of debug mode
- Adding variables to the REPL now prints a small message on success
Many thanks to [piegames](https://git.lix.systems/piegames) for this.
- Consistently use SRI hashes in hash mismatch errors [cl/2868](https://gerrit.lix.systems/c/lix/+/2868)
Previously there were a few weird cases (flake inputs, e.g., among others) where Lix would print the old Nix base-32 hash format (sha256:abcd...) rather than the newer [SRI base64 format](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) (sha256-AAAA...) that is used in most Lix hash mismatch errors.
This made it annoying to compare them to hashes shown by most of the modern UI surface of Lix which uses SRI.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Allow specifying ports for remote ssh[-ng] stores [cl/2432](https://gerrit.lix.systems/c/lix/+/2432)
You can now specify which port should be used for a remote ssh store (e.g. for remote/distributed builds) through a uri parameter.
E.g., when a remote builder `foo` is listening on port `1234` instead of the default, it can be specified like this `ssh://foo?port=1234`.
Many thanks to [seppel3210](https://github.com/Seppel3210) for this.
- Implicit `__toString` now have stack trace entries [cl/3055](https://gerrit.lix.systems/c/lix/+/3055)
Coercion of attribute sets to strings via their `__toString` attribute now produce stack
frames pointing to the coercion site and the attribute definition. This makes locating a
coercion function error easier as the fault location is now more likely to be presented.
Previously:
```
nix-repl> builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
error:
… while calling the 'substring' builtin
at «string»:1:1:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… caused by explicit throw
at «string»:1:48:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
error: bar
```
Now:
```
nix-repl> builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
error:
… while calling the 'substring' builtin
at «string»:1:1:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… while converting a set to string
at «string»:1:25:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… from call site
at «string»:1:29:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… while calling '__toString'
at «string»:1:42:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
… caused by explicit throw
at «string»:1:48:
1| builtins.substring 1 1 "${{ __toString = self: throw ''bar''; }}"
| ^
error: bar
```
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
## Fixes
- Avoid unnecessarily killing processes for the build user's UID [nix#9142](https://github.com/NixOS/nix/issues/9142) [fj#667](https://git.lix.systems/lix-project/lix/issues/667)
We no longer kill all processes under the build user's UID before and after
builds on Linux with sandboxes enabled.
This avoids unrelated processes being killed. This might happen for instance,
if the user is running Lix inside a container, wherein the build users use the same UIDs as the daemon's.
Many thanks to [teofilc](https://git.lix.systems/teofilc) for this.
- Forbid impure path accesses in pure evaluation mode again [cl/2708](https://gerrit.lix.systems/c/lix/+/2708)
Lix 2.92.0 mistakenly started allowing the access to ancestors of allowed paths in pure evaluation mode.
This made it possible to bypass the purity restrictions, for example by copying arbitrary files to the store:
```nix
builtins.path {
path = "/";
filter = …;
}
```
Restore the previous behaviour of prohibiting such impure accesses.
Many thanks to [alois31](https://git.lix.systems/alois31) for this.
- Ctrl-C works correctly on macOS again [fj#729](https://git.lix.systems/lix-project/lix/issues/729) [cl/3066](https://gerrit.lix.systems/c/lix/+/3066)
Due to a kernel bug in macOS's `poll(2)` implementation where it would forget about event subscriptions, our detection of closed connections in the Lix daemon didn't work and left around lingering daemon processes.
We have rewritten that thread to use `kqueue(2)`, which is what the `poll(2)` implementation uses internally in the macOS kernel, so now Ctrl-C on clients will reliably terminate daemons once more.
This FD close monitoring has had the highest Apple bug ID references per line of code anywhere in the project, and hopefully not using poll anymore will stop us hitting bugs in poll.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Fetch peer PID for daemon connections on macOS [fj#640](https://git.lix.systems/lix-project/lix/issues/640) [cl/2453](https://gerrit.lix.systems/c/lix/+/2453)
`nix-daemon` will now fetch the peer PID for connections on macOS, to match behavior with Linux.
Besides showing up in the log output line, If `nix-daemon` is given an argument (such as `--daemon`)
that argument will be overwritten with the peer PID for the forked process that handles the connection,
which can be used for debugging purposes.
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
- Test group membership better on macOS [gh#5885](https://github.com/NixOS/nix/issues/5885) [cl/2566](https://gerrit.lix.systems/c/lix/+/2566)
`nix-daemon` will now test group membership better on macOS for `trusted-users` and `allowed-users`.
It not only fetches the peer gid (which fixes `@staff`) but it also asks opendirectory for group
membership checks instead of just using the group database, which means nested groups (like `@_developer`)
and groups with synthesized membership (like `@localaccounts`) will work.
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
- `nix store delete` no longer builds paths [cl/2782](https://gerrit.lix.systems/c/lix/+/2782)
`nix store delete` no longer realises the installables
specified. Previously, `nix store delete nixpkgs#hello` would download
hello only to immediately delete it again. Now, it exits with an error
if given an installable that isn't in the store.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Fix nix-store --delete on paths with remaining referrers [cl/2783](https://gerrit.lix.systems/c/lix/+/2783)
Nix 2.5 introduced a regression whereby `nix-store --delete` and `nix
store delete` started to fail when trying to delete a path that was
still referenced by other paths, even if the referrers were not
reachable from any GC roots. The old behaviour, where attempting to
delete a store path would also delete its referrer closure, is now
restored.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Add a straightforward way to detect if in a Nix3 Shell [nix#6677](https://github.com/NixOS/nix/issues/6677) [nix#3862](https://github.com/NixOS/nix/issues/3862) [cl/2090](https://gerrit.lix.systems/c/lix/+/2090)
Running `nix shell` or `nix develop` will now set `IN_NIX_SHELL` to
either `pure` or `impure`, depending on whether `--ignore-environment`
is passed. `nix develop` will always be an impure environment.
Many thanks to [Ersei Saggi](https://github.com/9p4) for this.
- Fix experimental and deprecated features showing as integers in `nix config show --json` [fj#738](https://git.lix.systems/lix-project/lix/issues/738) [cl/2882](https://gerrit.lix.systems/c/lix/+/2882)
Internal changes in 2.92 caused `nix config show --json` to show deprecated and experimental features not as the list of named features 2.91 and earlier produced, but as integers. This has been fixed.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- `builtins.fetchTree` is no longer visible in `builtins` when flakes are disabled [cl/2399](https://gerrit.lix.systems/c/lix/+/2399)
`builtins.fetchTree` is the foundation of flake inputs and flake lock files, but is not fully specified in behaviour, which leads to regressions, behaviour differences with CppNix, and other unfun times.
It's gated behind the `flakes` experimental feature, but prior to now, would throw an uncatchable error at runtime when used without the `flakes` feature enabled.
Now it's like other builtins which are experimental feature gated, where it is not visible without the relevant feature enabled.
This fixes a bug in using Eelco Dolstra's version of flake-compat on Lix (and a divergence with CppNix): https://github.com/edolstra/flake-compat/issues/66
Many thanks to [jade](https://git.lix.systems/jade) for this.
- fix usage of `builtins.filterSource` and `builtins.path` with the filter argument when using chroot stores [nix#11503](https://github.com/NixOS/nix/issues/11503)
The semantics of `builtins.filterSource` (and the `filter` argument for
`builtins.path`) have been adjusted regarding how paths inside the Nix store
are handled.
Previously, when evaluating whether a path should be included, the filtering
function received the **physical path** if the source was inside the chroot store.
Now, it receives the **logical path** instead.
This ensures consistency in path handling and avoids potential
misinterpretations of paths within the evaluator, which led to various fallouts
mentioned in <https://github.com/NixOS/nixpkgs/pull/369694>.
Many thanks to [lily](https://git.lix.systems/lilyinstarlight), [alois31](https://git.lix.systems/alois31), and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Fix `--help` formatting [fj#622](https://git.lix.systems/lix-project/lix/issues/622) [cl/2776](https://gerrit.lix.systems/c/lix/+/2776)
The help printed when invoking `nix` or `nix-store` and subcommands with `--help` previously contained garbled terminal escapes. These have been removed.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Parsing failures in flake.lock no longer crash Lix [fj#559](https://git.lix.systems/lix-project/lix/issues/559) [cl/2401](https://gerrit.lix.systems/c/lix/+/2401)
Failure to parse `flake.lock` no longer hard-crashes Lix and instead produces a nice error message.
```
error:
… while updating the lock file of flake 'git+file:///Users/jade/lix/lix2'
… while parsing the lock file at /nix/store/mm5dqh8a729yazzj82cjffxl97n5c62s-source//flake.lock
error: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal;
last read: '#'
```
Many thanks to [gilice](https://git.lix.systems/gilice) for this.
- Flakes follow `--eval-system` where it makes sense [fj#673](https://git.lix.systems/lix-project/lix/issues/673) [fj#692](https://git.lix.systems/lix-project/lix/issues/692) [gh#11359](https://github.com/NixOS/nix/issues/11359) [cl/2657](https://gerrit.lix.systems/c/lix/+/2657)
Most flake commands now follow `--eval-system` when choosing attributes to build/evaluate/etc.
The exceptions are commands that actually run something on the local machine:
- nix develop
- nix run
- nix upgrade-nix
- nix fmt
- nix bundle
This is not a principled approach to cross compilation or anything, flakes still impede rather than support cross compilation, but this unbreaks many remote build use cases.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Remove some gremlins from path garbage collection [fj#621](https://git.lix.systems/lix-project/lix/issues/621) [fj#524](https://git.lix.systems/lix-project/lix/issues/524) [cl/2465](https://gerrit.lix.systems/c/lix/+/2465) [cl/2387](https://gerrit.lix.systems/c/lix/+/2387)
Path garbage collection had some known unsoundness issues where it would delete things improperly and cause desynchronization between the filesystem state and the database state.
Now Lix tolerates better if such a condition exists by not failing the entire GC if a path fails to delete.
We also fixed a bug in our file locking implementation that is one possible root cause, but may not be every root cause.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) and [Raito Bezarius](https://git.lix.systems/raito) for this.
- Show illegal path references in fixed-outputs derivations [fj#530](https://git.lix.systems/lix-project/lix/issues/530) [cl/2726](https://gerrit.lix.systems/c/lix/+/2726)
The error created when referencing a store path in a Fixed-Output Derivation is now more verbose, listing the offending paths.
This allows for better pinpointing where the issue might be.
An offender is the following derivation:
```nix
pkgs.stdenv.mkDerivation {
name = "illegal-fod";
dontUnpack = true;
dontBuild = true;
installPhase = ''
cp -R ${pkgs.hello} $out
'';
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = pkgs.lib.fakeHash;
}
```
The previous error shown would have been:
```
error: illegal path references in fixed-output derivation '/nix/store/rpq4m1y79s2nhs1hj7k47yiyykxykiqa-illegal-fod.drv'
```
and is now:
```
error: the fixed-output derivation '/nix/store/rpq4m1y79s2nhs1hj7k47yiyykxykiqa-illegal-fod.drv' must not reference store paths but 2 such references were found:
/nix/store/1q8w6gl1ll0mwfkqc3c2yx005s6wwfrl-hello-2.12.1
/nix/store/wn7v2vhyyyi6clcyn0s9ixvl7d4d87ic-glibc-2.40-36
```
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- Show error when item from NIX_PATH cannot be downloaded
For e.g. `nix-instantiate -I https://example.com/404`, you'd only get a warning if the download failed, such as
warning: Nix search path entry 'https://example.com/404' cannot be downloaded, ignoring
Now, the full error that caused the download failure is displayed with a note that the search
path entry is ignored, e.g.
warning:
… while downloading https://example.com/404 to satisfy NIX_PATH lookup, ignoring search path entry
warning: unable to download 'https://example.com/404': HTTP error 404 ()
response body: […]
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- Fix Lix crashing on invalid json [fj#642](https://git.lix.systems/lix-project/lix/issues/642) [fj#753](https://git.lix.systems/lix-project/lix/issues/753) [fj#759](https://git.lix.systems/lix-project/lix/issues/759) [fj#769](https://git.lix.systems/lix-project/lix/issues/769) [cl/2907](https://gerrit.lix.systems/c/lix/+/2907)
Lix no longer crashes when it receives invalid JSON. Instead it'll point to the syntax error and give some context about what happened, for example
```
nix derivation add <<<"""
error:
… while parsing a derivation from stdin
error: failed to parse JSON: [json.exception.parse_error.101] parse error at line 2, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal
```
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Fix handling of `lastModified` in tarball inputs [cl/2792](https://gerrit.lix.systems/c/lix/+/2792)
Previous versions of Lix would fail with the following error, if a
[tarball flake input](@docroot@/protocols/tarball-fetcher.md) redirect
to a URL that contains a `lastModified` field:
```
error: input attribute 'lastModified' is not an integer
```
This is now fixed.
Many thanks to [xanderio](https://github.com/xanderio) and [Julian Stecklina](https://github.com/blitz) for this.
- Fix `--debugger --ignore-try` [cl/2440](https://gerrit.lix.systems/c/lix/+/2440)
When in debug mode (e.g. from using the `--debugger` flag), enabling [`ignore-try`](@docroot@/command-ref/conf-file.md#conf-ignore-try) once again properly disables debug REPLs within [`builtins.tryEval`](@docroot@/language/builtins.md#builtins-tryEval) calls. Previously, a debug REPL would be started as if `ignore-try` was disabled, but that REPL wouldn't actually be in debug mode, and upon exiting the REPL the evaluating process would segfault.
Many thanks to [Dusk Banks](https://git.lix.systems/bb010g) for this.
- Don't consider a path with a specified rev to be `locked` [cl/2064](https://gerrit.lix.systems/c/lix/+/2064)
Until now it was allowed to do e.g.
$ echo 'lalala' > testfile
$ nix eval --expr '(builtins.fetchTree { path = "/home/ma27/testfile"; rev = "0000000000000000000000000000000000000000"; type = "path"; })'
{ lastModified = 1723656303; lastModifiedDate = "20240814172503"; narHash = "sha256-hOMY06A0ohaaCLwnhpZIMoAqi/8kG2vk30NRiqi0dfc="; outPath = "/nix/store/lhfz259iipmv9ky995rml8018jvriynh-source"; rev = "0000000000000000000000000000000000000000"; shortRev = "0000000"; }
$ cat /nix/store/lhfz259iipmv9ky995rml8018jvriynh-source
lalala
because any kind of input with a `rev` specified is considered to be locked.
With this change, inputs of type `path`, `indirect` and `tarball` are no longer
considered locked with a rev, but no hash specified.
This behavior was changed in
[CppNix 2.21 as well](https://github.com/nixos/nix/commit/071dd2b3a4e6c0b2106f1b6f14ec26e153d97446) as well.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- Fix macOS sandbox profile size errors [fj#752](https://git.lix.systems/lix-project/lix/issues/752) [fj#718](https://git.lix.systems/lix-project/lix/issues/718) [cl/2861](https://gerrit.lix.systems/c/lix/+/2861)
Fixed an issue on macOS where the sandbox profile could exceed size limits when building derivations with many dependencies. The profile is now split into multiple allowed sections to stay under the interpreter's limits.
This resolves errors like
```
error: (failed with exit code 1, previous messages: sandbox initialization failed: data object length 65730 exceeds maximum (65535)|failed to configure sandbox)
error: unexpected EOF reading a line
```
Many thanks to [Pierre-Etienne Meunier](https://github.com/P-E-Meunier) and [Poliorcetics](https://github.com/poliorcetics) for this.
- Fix interference of the multiline progress bar with output [cl/2774](https://gerrit.lix.systems/c/lix/+/2774)
In some situations, the progress indicator of the multiline progress bar would interfere with persistent output.
This would result in progress bar headers being visible in place of the desired text, for example the outputs shown after a `:b` command in the repl.
The underlying ordering issue has been fixed, so that the undesired interference does not happen any more.
Many thanks to [alois31](https://git.lix.systems/alois31) for this.
- Paralellise `nix store sign` using a thread pool [fj#399](https://git.lix.systems/lix-project/lix/issues/399) [cl/2606](https://gerrit.lix.systems/c/lix/+/2606)
`nix store sign` with a large collection of provided paths (such as when using with `--all`) has historically
signed these paths serially. Taking extreme amounts of time when preforming operations such as fixing binary
caches. This has been changed. Now these signatures are performed using a thread pool like `nix store copy-sigs`.
Many thanks to [Lunaphied](https://git.lix.systems/Lunaphied) for this.
- `post-build-hook` only receives settings that are set [fj#739](https://git.lix.systems/lix-project/lix/issues/739) [cl/2800](https://gerrit.lix.systems/c/lix/+/2800)
If one is using `post-build-hook` to upload paths to a cache, it used to be broken if CppNix was used inside the script, since CppNix would fail about unsupported configuration option values in some of Lix's defaults.
This is because `post-build-hook` receives the settings of the nix daemon in the `NIX_CONFIG` environment variable.
Now Lix only emits overridden settings to `post-build-hook` invocations, which fixes this issue in the majority of cases: where the configuration is not explicitly incompatible.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Remove lix-initiated ssh connection sharing [fj#304](https://git.lix.systems/lix-project/lix/issues/304) [fj#644](https://git.lix.systems/lix-project/lix/issues/644) [cl/3005](https://gerrit.lix.systems/c/lix/+/3005)
Lix no longer explicitly requests ssh connection sharing (ControlMaster/ControlPath SSH
options, see also ssh_config(5) man page) when connecting to remote stores. This may
impact command latency when `NIX_REMOTE` is set to a `ssh://` or `ssh-ng://` url, or if
`--store` is specified. Remote build connections did not use ssh connection sharing.
Connection sharing configuration is now inherited from user configuration at all times. It
is now advisable to configure connection sharing for remote builders for improved latency.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
## Development
- Add `nix_plugin_entry` entry point for plugins [fj#740](https://git.lix.systems/lix-project/lix/issues/740) [fj#359](https://git.lix.systems/lix-project/lix/issues/359) [gh#8699](https://github.com/NixOS/nix/pull/8699) [cl/2826](https://gerrit.lix.systems/c/lix/+/2826)
Plugins are an exceptionally rarely used feature in Lix, but they are important as a prototyping tool for code destined for Lix itself, and we want to keep supporting them as a low-maintenance-cost feature.
As part of the overall move towards getting rid of static initializers for stability and predictability reasons, we added an explicit `nix_plugin_entry` function like CppNix has, which is called immediately after plugin load, if present.
This makes control flow more explicit and allows for easily registering things that have had their static initializer registration classes removed.
Many thanks to [jade](https://git.lix.systems/jade) and [yorickvp](https://github.com/yorickvp) for this.
## Miscellany
- Set default of `connect-timeout` to `5` [cl/2799](https://gerrit.lix.systems/c/lix/+/2799)
By default, the connection timeout to substituters is now 5s instead of 300s.
That way, unavailable substituters are detected quicker.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
+5 -44
View File
@@ -1,21 +1,9 @@
#!/usr/bin/env python3
"""
Preprocesses mdbook markdown, primarily for include directives.
The include directive format is as follows:
{{#include foo/bar/baz.md}}
The content of includes will be indented as much as the directive itself.
Including a generated file (from building Lix; generally for the 'new' CLI):
{{#include @generated@/foo/bar/baz.md}}
"""
from pathlib import Path
import json
import os, os.path
import sys
import textwrap
name = 'substitute.py'
@@ -23,12 +11,6 @@ def log(*args, **kwargs):
kwargs['file'] = sys.stderr
return print(f'{name}:', *args, **kwargs)
def remove_prefix_if_present(s: str, prefix: str) -> str | None:
if s.startswith(prefix):
return s.removeprefix(prefix)
else:
return None
def do_include(content: str, relative_md_path: Path, source_root: Path, search_path: Path):
assert not relative_md_path.is_absolute(), f'{relative_md_path=} from mdbook should be relative'
@@ -38,32 +20,16 @@ def do_include(content: str, relative_md_path: Path, source_root: Path, search_p
lines = []
for l in content.splitlines(keepends=True):
if remain := remove_prefix_if_present(l.strip(), "{{#include"):
requested = remain[1:-2]
# We indent bodies of indent directives by the indent of the
# directive itself.
num_leading_indent = len(l) - len(l.lstrip())
if subpath := remove_prefix_if_present(requested, "@generated@/"):
included = search_path / Path(subpath)
if l.strip().startswith("{{#include "):
requested = l.strip()[11:][:-2]
if requested.startswith("@generated@/"):
included = search_path / Path(requested[12:])
requested = included.relative_to(search_path)
else:
included = source_root / relative_md_path.parent / requested
requested = included.resolve().relative_to(source_root)
assert included.exists(), f"{requested} not found at {included}"
lines.append(
textwrap.indent(
do_include(
included.read_text(),
requested,
source_root,
search_path,
),
" " * num_leading_indent
)
+ "\n"
)
lines.append(do_include(included.read_text(), requested, source_root, search_path) + "\n")
else:
lines.append(l)
return "".join(lines)
@@ -90,11 +56,6 @@ def recursive_replace(data, book_root, search_path):
).replace(
'@docroot@',
("../" * len(path_to_chapter.parent.parts) or "./")[:-1]
).replace(
# this replacement is to avoid corrupting the
# hacking.md manual section on docroot
'@\\docroot\\@',
'@docroot@',
),
sub_items = [
recursive_replace(sub_item, book_root, search_path)
+1 -1
View File
@@ -156,7 +156,7 @@ let
nixConfContents =
(lib.concatStringsSep "\n" (
lib.mapAttrsToList (
lib.mapAttrsFlatten (
n: v:
let
vStr = if builtins.isList v then lib.concatStringsSep " " v else v;
Generated
+3 -3
View File
@@ -108,11 +108,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1758391731,
"narHash": "sha256-UuwQoPWv13DVKMveeev+F0OC/N95AOmAz6SzCuGhxjQ=",
"lastModified": 1757198069,
"narHash": "sha256-m3VUcOD4rTs8J7S+3dOjWMrAjw6RcITC3XYQ98zhEFs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3f00d36f15e16e0471d9ca1e8f88958941fa970a",
"rev": "0747026fc57ecb9c28901c7f7a2b5dc40e8af43c",
"type": "github"
},
"original": {
+83 -161
View File
@@ -48,7 +48,6 @@
sgr = builtins.fromJSON ''"\u001b["'';
freezePage = "https://wiki.lix.systems/books/lix-contributors/page/freezes-and-recommended-contributions";
codebaseOverview = "https://wiki.lix.systems/books/lix-contributors/page/codebase-overview";
gerritWiki = "https://wiki.lix.systems/books/lix-contributors/page/gerrit";
contribNotice = builtins.toFile "lix-contrib-notice" ''
Hey there!
@@ -66,10 +65,6 @@
and we'd like to work together with all contributors as much as possible.
Lix is a collaborative project :)
If you want to submit a patch and you never used gerrit before, please
check our gerrit wiki section:
${sgr}32m${gerritWiki}${sgr}0m
You can open an issue at https://git.lix.systems/lix-project/lix/issues
or chat with us on Matrix: #space:lix.systems.
@@ -109,7 +104,8 @@
"armv7l-linux"
"riscv64-linux"
"aarch64-linux"
"x86_64-freebsd"
# FIXME: still broken in 24.05: fails to build rustc(??) due to missing -lstdc++ dep
# "x86_64-freebsd"
# FIXME: broken dev shell due to python
# "x86_64-netbsd"
];
@@ -223,42 +219,11 @@
lix-clang-tidy = final.callPackage ./subprojects/lix-clang-tidy { };
nix-eval-jobs = final.callPackage ./subprojects/nix-eval-jobs {
srcDir = ./subprojects/nix-eval-jobs;
};
# HACK: We need nix-prefetch-git for fetchCargoVendor for Rust stuff,
# so it can't use Lix, or we infrec:
# lix -> Rust stuff -> fetchCargoVendor -> nix-prefetch-git -> nix (lix)
# This will eventually become a problem upstream, but until then,
# apply some duct tape and pray.
nix-prefetch-git =
if (lib.functionArgs prev.nix-prefetch-git.override) ? "nix" then
prev.nix-prefetch-git.override { nix = prev.nix; }
else
prev.nix-prefetch-git;
# Export the patched version of boehmgc that Lix uses into the overlay
# for consumers of this flake.
boehmgc-nix = final.nix.passthru.boehmgc-nix;
# And same thing for our build-release-notes package.
build-release-notes = final.nix.passthru.build-release-notes;
lowdown_1_3 =
# If the stable channel we are using ships lowdown >= 1.4, we need
# to swap this around, take the default lowdown from the stable
# channel and add an overridden one for the legacy version.
assert lib.versionOlder prev.lowdown.version "1.4.0";
prev.lowdown;
lowdown = prev.lowdown.overrideAttrs (prevAttrs: rec {
version = "2.0.2";
src = final.fetchurl {
url = "https://kristaps.bsd.lv/lowdown/snapshots/lowdown-${version}.tar.gz";
sha512 = "2a4d0rqh8gkw4ca3gkzddp0hjpmmw74cbks8k0inhh0vizmgbn188zdv6m1kgmr019b99g7insli8js3ci1ji7y4n5nk704bswf3z3i";
};
nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ final.buildPackages.bmake ];
postInstall = lib.replaceStrings [ "lowdown.so.1" ] [ "lowdown.so.2" ] prevAttrs.postInstall;
});
};
in
{
@@ -273,30 +238,6 @@
# Binary package for various platforms.
build = forAllSystems (system: self.packages.${system}.nix);
# Building Lix twice in CI is expensive, but we can catch a lot of static
# build regressions by at least making sure it evals and configures.
configure-static = lib.genAttrs linux64BitSystems (
system:
self.packages.${system}.nix-static.overrideAttrs {
dontBuild = true;
installPhase = ''
runHook preInstall
echo "configure-static complete. exiting with success"
mkdir -p "$out"
exit 0
'';
}
);
# Ensure support for lowdown < 1.4 doesn't regress
build-lowdown_1_3 = forAllSystems (
system:
self.packages.${system}.nix.override {
lowdown = nixpkgsFor.${system}.native.lowdown_1_3;
}
);
devShell = forAllSystems (system: {
default = self.devShells.${system}.default;
clang = self.devShells.${system}.native-clangStdenvPackages;
@@ -327,9 +268,6 @@
# Perl bindings for various platforms.
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nix.passthru.perl-bindings);
# nix-eval-jobs can be built against this Lix.
nix-eval-jobs = forAllSystems (system: nixpkgsFor.${system}.native.nix-eval-jobs);
# Binary tarball for various platforms, containing a Nix store
# with the closure of 'nix' package.
binaryTarball = forAllSystems (system: nixpkgsFor.${system}.native.nix.passthru.binaryTarball);
@@ -361,101 +299,90 @@
});
# System tests.
tests =
import ./tests/nixos {
inherit
self
lib
nixpkgs
nixpkgsFor
;
}
// {
nix-eval-jobs = forAllSystems (system: self.packages.${system}.nix-eval-jobs.tests.nix-eval-jobs);
tests = import ./tests/nixos { inherit lib nixpkgs nixpkgsFor; } // {
# This is x86_64-linux only, just because we have significantly
# cheaper x86_64-linux compute in CI.
# It is clangStdenv because clang's sanitizers are nicer.
asanBuild = self.packages.x86_64-linux.nix-clangStdenv.override {
# Improve caching of non-code changes by not changing the
# derivation name every single time, since this will never be seen
# by users anyway.
versionSuffix = "";
sanitize = [
"address"
"undefined"
];
# it is very hard to make *every* CI build use this option such
# that we don't wind up building Lix twice, so we do it here where
# we are already doing so.
werror = true;
};
# This is x86_64-linux only, just because we have significantly
# cheaper x86_64-linux compute in CI.
# It is clangStdenv because clang's sanitizers are nicer.
asanBuild = self.packages.x86_64-linux.nix-clangStdenv.override {
# Improve caching of non-code changes by not changing the
# derivation name every single time, since this will never be seen
# by users anyway.
# Although this might be nicer to do with pre-commit, that would
# require adding 12MB of nodejs to the dev shell, whereas building it
# in CI with Nix avoids that at a cost of slower feedback on rarely
# touched files.
jsSyntaxCheck =
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
docSources = lib.fileset.toSource {
root = ./doc;
fileset = lib.fileset.fileFilter (f: f.hasExt "js") ./doc;
};
in
pkgs.runCommand "js-syntax-check" { } ''
find ${docSources} -type f -print -exec ${pkgs.nodejs-slim}/bin/node --check '{}' ';'
touch $out
'';
# clang-tidy run against the Lix codebase using the Lix clang-tidy plugin
clang-tidy =
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
in
pkgs.callPackage ./package.nix {
# Required since we don't support gcc stdenv
stdenv = pkgs.clangStdenv;
versionSuffix = "";
sanitize = [
"address"
"undefined"
];
# it is very hard to make *every* CI build use this option such
# that we don't wind up building Lix twice, so we do it here where
# we are already doing so.
werror = true;
lintInsteadOfBuild = true;
};
# Although this might be nicer to do with pre-commit, that would
# require adding 12MB of nodejs to the dev shell, whereas building it
# in CI with Nix avoids that at a cost of slower feedback on rarely
# touched files.
jsSyntaxCheck =
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
docSources = lib.fileset.toSource {
root = ./doc;
fileset = lib.fileset.fileFilter (f: f.hasExt "js") ./doc;
};
in
pkgs.runCommand "js-syntax-check" { } ''
find ${docSources} -type f -print -exec ${pkgs.nodejs-slim}/bin/node --check '{}' ';'
touch $out
'';
# Make sure that nix-env still produces the exact same result
# on a particular version of Nixpkgs.
evalNixpkgs =
with nixpkgsFor.x86_64-linux.native;
runCommand "eval-nixos" { buildInputs = [ nix ]; } ''
type -p nix-env
# Note: we're filtering out nixos-install-tools because https://github.com/NixOS/nixpkgs/pull/153594#issuecomment-1020530593.
time nix-env --store dummy:// -f ${nixpkgs-regression} -qaP --drv-path | sort | grep -v nixos-install-tools > packages
[[ $(sha1sum < packages | cut -c1-40) = 402242fca90874112b34718b8199d844e8b03d12 ]]
mkdir $out
'';
# clang-tidy run against the Lix codebase using the Lix clang-tidy plugin
clang-tidy =
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
in
pkgs.callPackage ./package.nix {
# Required since we don't support gcc stdenv
stdenv = pkgs.clangStdenv;
versionSuffix = "";
lintInsteadOfBuild = true;
};
# Make sure that nix-env still produces the exact same result
# on a particular version of Nixpkgs.
evalNixpkgs =
with nixpkgsFor.x86_64-linux.native;
runCommand "eval-nixos" { buildInputs = [ nix ]; } ''
type -p nix-env
# Note: we're filtering out nixos-install-tools because https://github.com/NixOS/nixpkgs/pull/153594#issuecomment-1020530593.
time nix-env --store dummy:// -f ${nixpkgs-regression} -qaP --drv-path | sort | grep -v nixos-install-tools > packages
[[ $(sha1sum < packages | cut -c1-40) = 402242fca90874112b34718b8199d844e8b03d12 ]]
mkdir $out
'';
nixpkgsLibTests = forAllSystems (
system:
let
inherit (self.packages.${system}) nix;
pkgs = nixpkgsFor.${system}.native;
testWithNix = import (nixpkgs + "/lib/tests/test-with-nix.nix") { inherit pkgs lib nix; };
in
pkgs.symlinkJoin {
name = "nixpkgs-lib-tests";
paths = [
testWithNix
]
# NOTE: nixpkgs 25.05 is being ... *creative*, and requires this dance to override
# the evaluator used for the test. it will break again in the future, don't worry.
++ lib.optionals pkgs.stdenv.isLinux [
((pkgs.callPackage "${nixpkgs}/ci/eval" { inherit nix; }).attrpathsSuperset {
evalSystem = system;
})
];
}
);
};
nixpkgsLibTests = forAllSystems (
system:
let
inherit (self.packages.${system}) nix;
pkgs = nixpkgsFor.${system}.native;
testWithNix = import (nixpkgs + "/lib/tests/test-with-nix.nix") { inherit pkgs lib nix; };
in
pkgs.symlinkJoin {
name = "nixpkgs-lib-tests";
paths = [
testWithNix
]
# NOTE: nixpkgs 25.05 is being ... *creative*, and requires this dance to override
# the evaluator used for the test. it will break again in the future, don't worry.
++ lib.optionals pkgs.stdenv.isLinux [
((pkgs.callPackage "${nixpkgs}/ci/eval" { inherit nix; }).attrpathsSuperset {
evalSystem = system;
})
];
}
);
};
pre-commit = forAvailableSystems (
system:
@@ -501,10 +428,8 @@
# devShells and packages already get checked by nix flake check, so
# this is just jobs that are special
build-lowdown_1_3 = self.hydraJobs.build-lowdown_1_3.${system};
binaryTarball = self.hydraJobs.binaryTarball.${system};
perlBindings = self.hydraJobs.perlBindings.${system};
nix-eval-jobs = self.hydraJobs.nix-eval-jobs.${system};
nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system};
rl-next = self.hydraJobs.rl-next.${system}.user;
# Will be empty attr set on i686-linux, and filtered out by forAvailableSystems.
@@ -522,14 +447,11 @@
inherit (nixpkgsFor.${system}.native) nix;
default = nix;
inherit (nixpkgsFor.${system}.native) lix-clang-tidy nix-eval-jobs;
inherit (nixpkgsFor.${system}.native) lix-clang-tidy;
}
// (
lib.optionalAttrs (builtins.elem system linux64BitSystems) {
# python doesn't work in static builds as of 2025-06-27
nix-static = nixpkgsFor.${system}.static.nix.overrideAttrs (_: {
doCheck = false;
});
nix-static = nixpkgsFor.${system}.static.nix;
dockerImage =
let
pkgs = nixpkgsFor.${system}.native;
+7 -28
View File
@@ -8,51 +8,30 @@ list:
clean:
rm -rf build
# Prepare meson for building with extra options
setup-custom *OPTIONS:
# Prepare meson for building
setup *OPTIONS:
meson setup build --prefix="$PWD/outputs/out" $mesonFlags {{ OPTIONS }}
# Prepare meson for building
setup: (setup-custom)
# Build lix with extra options
build-custom *OPTIONS:
meson compile -C build {{ OPTIONS }}
# Build lix
build: (build-custom)
build *OPTIONS:
meson compile -C build {{ OPTIONS }}
alias compile := build
# Install lix for local development with extra options
install-custom *OPTIONS: (build-custom OPTIONS)
# Install lix for local development
install *OPTIONS: (build OPTIONS)
meson install -C build
# Install lix for local development
install: (install-custom)
# Run tests (usually requires `install`) with extra options
# Run tests
test *OPTIONS:
meson test -C build --print-errorlogs {{ OPTIONS }}
# Run unit tests only
test-unit *OPTIONS: (test "--suite" "check")
# Run integration tests only
test-integration *OPTIONS: install (test "--suite" "installcheck")
# Run functional2 tests using pytest directly, allowing for additional arguments to be passed to pytest e.g. for more granular test selection
test-functional2 *OPTIONS:
cd tests && python -m pytest -v {{ OPTIONS }} functional2
alias clang-tidy := lint
# Lint with `clang-tidy`
lint:
ninja -C build clang-tidy
alias clang-tidy-fix := lint-fix
# Fix lints with `clang-tidy-fix`
lint-fix:
ninja -C build clang-tidy-fix
-10
View File
@@ -1,10 +0,0 @@
# This reproduces the Lix Approvers plus Lix groups to yield the status quo
alois1@gmx-topmail.de
jade@lix.systems
lunaphied@lunaphied.me
maximilian@mbosch.me
me@0upti.me
pennae@lix.systems
qyriad@qyriad.me
raito@lix.systems
rbt@sent.as
-64
View File
@@ -1,64 +0,0 @@
#!@python@
import argparse
import capnp
from pathlib import Path
import os
import subprocess
import sys
if lang := os.environ.get('lix_capnp_lang'):
outputs = os.environ['lix_capnp_outputs'].split()
old_cwd = os.environ['lix_capnp_old_cwd']
schema = capnp.load('@capnp_include@/capnp/schema.capnp', imports=['@capnp_include@'])
request = schema.CodeGeneratorRequest.read(sys.stdin)
subprocess.run([lang], input=request.as_builder().to_bytes()).check_returncode()
base_dir = os.getcwd()
os.chdir(old_cwd)
include = [ str(Path(p).resolve()) for p in os.environ['lix_capnp_include'].split(':') ]
if depfile := os.environ['lix_capnp_depfile']:
deps = ""
for input in request.requestedFiles:
deps += " ".join(f"{input.filename}.{o}" for o in outputs)
deps += ":"
for dep in input.imports:
if dep.name.startswith("/"):
for candidate in (Path(i + dep.name) for i in include):
if candidate.exists():
deps += " " + str(candidate)
break
else:
raise RuntimeError("not handling relative includes")
deps += "\n\n"
Path(depfile).write_text(deps)
else:
parser = argparse.ArgumentParser()
parser.add_argument('--language')
parser.add_argument('--outdir')
parser.add_argument('--src-prefix')
parser.add_argument('--depfile', default="")
parser.add_argument('-I', '--include', action='append', default=['@capnp_include@'])
parser.add_argument('inputs', nargs='+')
args = parser.parse_args()
for infile in args.inputs:
os.environ['lix_capnp_lang'] = f"capnpc-{args.language}"
os.environ['lix_capnp_include'] = ':'.join(args.include)
os.environ['lix_capnp_depfile'] = args.depfile
os.environ['lix_capnp_old_cwd'] = os.getcwd()
if args.language == "c++":
os.environ['lix_capnp_outputs'] = "c++ h"
else:
raise RuntimeError("unknown language " + args.language)
subprocess.run([
'@capnp@',
'compile',
f'-o{sys.argv[0]}:{args.outdir}',
f'--src-prefix={args.src_prefix}',
*(f"-I{i}" for i in args.include),
infile
]).check_returncode()
+217 -376
View File
@@ -1,19 +1,7 @@
#include "lix/libstore/path.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/error.hh"
#include "lix/libutil/file-descriptor.hh"
#include "lix/libutil/logging.hh"
#include "lix/libutil/rpc.hh"
#include "lix/libutil/types-rpc.hh"
#include <algorithm>
#include <capnp/rpc-twoparty.h>
#include <chrono>
#include <cstring>
#include <future>
#include <kj/time.h>
#include <set>
#include <memory>
#include <string>
#include <tuple>
#if __APPLE__
#include <sys/time.h>
@@ -29,27 +17,13 @@
#include "lix/libstore/derivations.hh"
#include "lix/libutil/strings.hh"
#include "lix/libstore/local-store.hh"
#include "lix/libstore/types-rpc.hh"
#include "lix/libcmd/legacy.hh"
#include "lix/libutil/experimental-features.hh"
#include "lix/libutil/hash.hh"
#include "build-remote.hh"
#include "lix/libstore/build/hook-instance.capnp.h"
namespace nix {
namespace {
struct Instance final : rpc::build_remote::HookInstance::Server
{
unsigned int maxBuildJobs;
Instance(unsigned int maxBuildJobs) : maxBuildJobs(maxBuildJobs) {}
kj::Promise<void> build(BuildContext context) override;
};
}
std::string escapeUri(std::string uri)
{
std::replace(uri.begin(), uri.end(), '/', '_');
@@ -79,246 +53,7 @@ static bool allSupportedLocally(Store & store, const std::set<std::string>& requ
return true;
}
static std::tuple<bool, Machine *, AutoCloseFD> selectBestMachine(
Machines & machines,
const std::string & neededSystem,
const std::set<std::string> & requiredFeatures
)
{
bool rightType = false;
Machine * bestMachine = nullptr;
AutoCloseFD bestSlotLock;
uint64_t bestLoad = 0;
for (auto & m : machines) {
debug("considering building on remote machine '%s'", m.storeUri);
if (m.enabled && m.systemSupported(neededSystem) && m.allSupported(requiredFeatures)
&& m.mandatoryMet(requiredFeatures))
{
rightType = true;
AutoCloseFD free;
uint64_t load = 0;
for (uint64_t slot = 0; slot < m.maxJobs; ++slot) {
auto slotLock = openSlotLock(m, slot);
if (tryLockFile(slotLock.get(), ltWrite)) {
if (!free) {
free = std::move(slotLock);
}
} else {
++load;
}
}
if (!free) {
continue;
}
bool best = false;
if (!bestSlotLock) {
best = true;
} else if (load / m.speedFactor < bestLoad / bestMachine->speedFactor) {
best = true;
} else if (load / m.speedFactor == bestLoad / bestMachine->speedFactor) {
if (m.speedFactor > bestMachine->speedFactor) {
best = true;
} else if (m.speedFactor == bestMachine->speedFactor) {
if (load < bestLoad) {
best = true;
}
}
}
if (best) {
bestLoad = load;
bestSlotLock = std::move(free);
bestMachine = &m;
}
}
}
return {rightType, bestMachine, std::move(bestSlotLock)};
}
static void printSelectionFailureMessage(
Verbosity level,
const std::string_view drvstr,
const Machines & machines,
const std::string & neededSystem,
const std::set<std::string> & requiredFeatures
)
{
std::string machinesFormatted;
for (auto & m : machines) {
machinesFormatted += HintFmt(
"\n([%s], %s, [%s], [%s])",
concatStringsSep<StringSet>(", ", m.systemTypes),
m.maxJobs,
concatStringsSep<StringSet>(", ", m.supportedFeatures),
concatStringsSep<StringSet>(", ", m.mandatoryFeatures)
)
.str();
}
printMsg(
level,
"Failed to find a machine for remote build!\n"
"derivation: %s\n"
"required (system, features): (%s, [%s])\n"
"%s available machines:\n"
"(systems, maxjobs, supportedFeatures, mandatoryFeatures)%s",
drvstr,
neededSystem,
concatStringsSep<StringSet>(", ", requiredFeatures),
machines.size(),
Uncolored(machinesFormatted)
);
}
namespace {
struct BuilderConnection
{
AutoCloseFD slotLock;
std::shared_ptr<Store> sshStore;
std::string storeUri;
Pipe logPipe;
// start the thread that reads ssh stderr and turns it into log items.
// this future *must* outlive sshStore, otherwise it will never finish
std::future<void> startLogThread(int intoFD)
{
if (!logPipe.readSide) {
return {};
}
logPipe.writeSide.close();
return std::async(
std::launch::async,
[](int from, int to) {
AsyncIoRoot aio;
auto reader = AIO().lowLevelProvider.wrapInputFd(from);
auto writer = AIO().lowLevelProvider.wrapOutputFd(to);
reader->pumpTo(*writer).wait(aio.kj.waitScope);
},
logPipe.readSide.get(),
intoFD
);
}
};
struct AcceptedBuild final : rpc::build_remote::HookInstance::AcceptedBuild::Server
{
ref<Store> store;
StorePath drvPath;
BuilderConnection builder;
rpc::build_remote::HookInstance::BuildLogger::Client buildLogger;
AcceptedBuild(
ref<Store> store,
StorePath drvPath,
BuilderConnection builder,
rpc::build_remote::HookInstance::BuildLogger::Client buildLogger
)
: store(store)
, drvPath(drvPath)
, builder(std::move(builder))
, buildLogger(std::move(buildLogger))
{
}
kj::Promise<void> run(RunContext context) override;
};
enum class BuildRejected { Temporarily, Permanently };
}
static kj::Promise<Result<std::variant<BuildRejected, BuilderConnection>>> connectToBuilder(
const ref<Store> & store,
const std::optional<StorePath> & drvPath,
Machines & machines,
const unsigned int maxBuildJobs,
const bool amWilling,
const std::string & neededSystem,
const std::set<std::string> & requiredFeatures
)
try {
AutoCloseFD bestSlotLock;
/* It would be possible to build locally after some builds clear out,
so don't show the warning now: */
bool couldBuildLocally = maxBuildJobs > 0
&& (neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0)
&& allSupportedLocally(*store, requiredFeatures);
/* It's possible to build this locally right now: */
bool canBuildLocally = amWilling && couldBuildLocally;
/* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777);
while (true) {
bestSlotLock.reset();
AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
TRY_AWAIT(lockFileAsync(lock.get(), ltWrite));
auto [rightType, bestMachine, slotLock] =
selectBestMachine(machines, neededSystem, requiredFeatures);
bestSlotLock = std::move(slotLock);
if (!bestSlotLock) {
if (rightType && !canBuildLocally) {
co_return BuildRejected::Temporarily;
} else {
printSelectionFailureMessage(
couldBuildLocally ? lvlChatty : lvlWarn,
drvPath ? drvPath->to_string() : "<unknown>",
machines,
neededSystem,
requiredFeatures
);
co_return BuildRejected::Permanently;
}
}
#if __APPLE__
futimes(bestSlotLock.get(), nullptr);
#else
futimens(bestSlotLock.get(), nullptr);
#endif
lock.reset();
std::shared_ptr<Store> sshStore;
Pipe logPipe;
try {
Activity act(
*logger, lvlTalkative, actUnknown, fmt("connecting to '%s'", bestMachine->storeUri)
);
std::tie(sshStore, logPipe) = TRY_AWAIT(bestMachine->openStore());
TRY_AWAIT(sshStore->connect());
co_return BuilderConnection{
std::move(bestSlotLock), sshStore, bestMachine->storeUri, std::move(logPipe)
};
} catch (std::exception & e) { // NOLINT(lix-foreign-exceptions)
std::string msg = logPipe.readSide ? chomp(drainFD(logPipe.readSide.get(), false)) : "";
printError(
"cannot build on '%s': %s%s",
bestMachine->storeUri,
e.what(),
msg.empty() ? "" : ": " + msg
);
bestMachine->enabled = false;
}
}
} catch (...) {
co_return result::current_exception();
}
static int main_build_remote(AsyncIoRoot & aio, std::string programName, Strings argv)
static int main_build_remote(std::string programName, Strings argv)
{
{
logger = makeJSONLogger(*logger);
@@ -338,7 +73,7 @@ static int main_build_remote(AsyncIoRoot & aio, std::string programName, Strings
FdSource source(STDIN_FILENO);
/* Read the parent's settings. */
while (readNum<unsigned>(source)) {
while (readInt(source)) {
auto name = readString(source);
auto value = readString(source);
settings.set(name, value);
@@ -349,95 +84,191 @@ static int main_build_remote(AsyncIoRoot & aio, std::string programName, Strings
initPlugins();
auto conn = aio.kj.lowLevelProvider->wrapUnixSocketFd(1);
capnp::TwoPartyServer srv(kj::heap<Instance>(maxBuildJobs));
srv.accept(*conn, 1).wait(aio.kj.waitScope);
return 0;
}
}
kj::Promise<void> Instance::build(BuildContext context)
{
try {
// FIXME this does not open a daemon connection for historical reasons.
// we may create a lot of build hook instances, and having each of them
// also create a daemon instance is inefficient and wasteful. in future
// versions of the build hook (where we don't need one hook process per
// build) we should change this to using a daemon connection, ideally a
// daemon connection provided by the parent via file descriptor passing
auto store = TRY_AWAIT(openStore(settings.storeUri, {}, AllowDaemon::Disallow));
auto store = openStore();
/* It would be more appropriate to use $XDG_RUNTIME_DIR, since
that gets cleared on reboot, but it wouldn't work on macOS. */
auto currentLoadName = "/current-load";
if (auto localStore = store.try_cast_shared<LocalFSStore>())
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
currentLoad = std::string { localStore->config().stateDir } + currentLoadName;
else
currentLoad = settings.nixStateDir + currentLoadName;
std::shared_ptr<Store> sshStore;
AutoCloseFD bestSlotLock;
auto machines = getMachines();
debug("got %d remote builders", machines.size());
if (machines.empty()) {
context.getResults().initResult().initGood().setDeclinePermanently();
co_return;
std::cerr << "# decline-permanently\n";
return 0;
}
auto amWilling = context.getParams().getAmWilling();
auto neededSystem = rpc::to<std::string>(context.getParams().getNeededSystem());
auto drvPath = from(context.getParams().getDrvPath(), *store);
auto requiredFeatures =
rpc::to<std::set<std::string>>(context.getParams().getRequiredFeatures());
auto buildLogger = context.getParams().getBuildLogger();
std::optional<StorePath> drvPath;
std::string storeUri;
auto result = TRY_AWAIT(connectToBuilder(
store, drvPath, machines, maxBuildJobs, amWilling, neededSystem, requiredFeatures
));
while (true) {
if (auto immediateResponse = std::get_if<BuildRejected>(&result)) {
switch (*immediateResponse) {
case BuildRejected::Temporarily:
context.getResults().initResult().initGood().setPostpone();
co_return;
case BuildRejected::Permanently:
context.getResults().initResult().initGood().setDecline();
co_return;
try {
auto s = readString(source);
if (s != "try") return 0;
} catch (EndOfFile &) { return 0; }
auto amWilling = readInt(source);
auto neededSystem = readString(source);
drvPath = store->parseStorePath(readString(source));
auto requiredFeatures = readStrings<std::set<std::string>>(source);
/* It would be possible to build locally after some builds clear out,
so don't show the warning now: */
bool couldBuildLocally = maxBuildJobs > 0
&& ( neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0)
&& allSupportedLocally(*store, requiredFeatures);
/* It's possible to build this locally right now: */
bool canBuildLocally = amWilling && couldBuildLocally;
/* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777);
while (true) {
bestSlotLock.reset();
AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
lockFile(lock.get(), ltWrite);
bool rightType = false;
Machine * bestMachine = nullptr;
uint64_t bestLoad = 0;
for (auto & m : machines) {
debug("considering building on remote machine '%s'", m.storeUri);
if (m.enabled &&
m.systemSupported(neededSystem) &&
m.allSupported(requiredFeatures) &&
m.mandatoryMet(requiredFeatures))
{
rightType = true;
AutoCloseFD free;
uint64_t load = 0;
for (uint64_t slot = 0; slot < m.maxJobs; ++slot) {
auto slotLock = openSlotLock(m, slot);
if (tryLockFile(slotLock.get(), ltWrite)) {
if (!free) {
free = std::move(slotLock);
}
} else {
++load;
}
}
if (!free) {
continue;
}
bool best = false;
if (!bestSlotLock) {
best = true;
} else if (load / m.speedFactor < bestLoad / bestMachine->speedFactor) {
best = true;
} else if (load / m.speedFactor == bestLoad / bestMachine->speedFactor) {
if (m.speedFactor > bestMachine->speedFactor) {
best = true;
} else if (m.speedFactor == bestMachine->speedFactor) {
if (load < bestLoad) {
best = true;
}
}
}
if (best) {
bestLoad = load;
bestSlotLock = std::move(free);
bestMachine = &m;
}
}
}
if (!bestSlotLock) {
if (rightType && !canBuildLocally)
std::cerr << "# postpone\n";
else
{
// add the template values.
std::string drvstr;
if (drvPath.has_value())
drvstr = drvPath->to_string();
else
drvstr = "<unknown>";
std::string machinesFormatted;
for (auto & m : machines) {
machinesFormatted += HintFmt(
"\n([%s], %s, [%s], [%s])",
concatStringsSep<StringSet>(", ", m.systemTypes),
m.maxJobs,
concatStringsSep<StringSet>(", ", m.supportedFeatures),
concatStringsSep<StringSet>(", ", m.mandatoryFeatures)
).str();
}
auto error = HintFmt(
"Failed to find a machine for remote build!\n"
"derivation: %s\n"
"required (system, features): (%s, [%s])\n"
"%s available machines:\n"
"(systems, maxjobs, supportedFeatures, mandatoryFeatures)%s",
drvstr,
neededSystem,
concatStringsSep<StringSet>(", ", requiredFeatures),
machines.size(),
Uncolored(machinesFormatted)
);
printMsg(couldBuildLocally ? lvlChatty : lvlWarn, error.str());
std::cerr << "# decline\n";
}
break;
}
#if __APPLE__
futimes(bestSlotLock.get(), nullptr);
#else
futimens(bestSlotLock.get(), nullptr);
#endif
lock.reset();
try {
Activity act(*logger, lvlTalkative, actUnknown, fmt("connecting to '%s'", bestMachine->storeUri));
sshStore = bestMachine->openStore();
sshStore->connect();
storeUri = bestMachine->storeUri;
} catch (std::exception & e) {
auto msg = chomp(drainFD(5, false));
printError("cannot build on '%s': %s%s",
bestMachine->storeUri, e.what(),
msg.empty() ? "" : ": " + msg);
bestMachine->enabled = false;
continue;
}
goto connected;
}
}
auto builder = std::get_if<BuilderConnection>(&result);
assert(builder);
connected:
close(5);
auto ac = context.getResults().initResult().initGood().initAccept();
RPC_FILL(ac, setMachineName, builder->storeUri);
ac.setMachine(kj::heap<AcceptedBuild>(store, drvPath, std::move(*builder), buildLogger));
} catch (...) {
RPC_FILL(context.getResults(), initResult, std::current_exception());
}
}
assert(sshStore);
kj::Promise<void> AcceptedBuild::run(RunContext context)
{
try {
const int logFD = (co_await buildLogger.getFd()).orDefault(-1);
if (logFD < 0) {
throw Error("build-hook needs a logFD from the builder to build");
}
std::cerr << "# accept\n" << storeUri << "\n";
auto logThread = builder.startLogThread(logFD);
KJ_DEFER({
// drop any existing ssh connection so the log thread can exit
builder.sshStore = nullptr;
if (logThread.valid()) {
logThread.get();
}
});
auto & sshStore = builder.sshStore;
auto & storeUri = builder.storeUri;
auto inputs = rpc::to<std::set<StorePath>>(context.getParams().getInputs(), *store);
auto wantedOutputs = rpc::to<std::set<std::string>>(context.getParams().getWantedOutputs());
auto inputs = readStrings<PathSet>(source);
auto wantedOutputs = readStrings<StringSet>(source);
auto lockFileName = currentLoad + "/" + makeLockFilename(storeUri) + ".upload-lock";
@@ -446,24 +277,20 @@ kj::Promise<void> AcceptedBuild::run(RunContext context)
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));
auto result = TRY_AWAIT(
AIO().timeoutAfter(15 * kj::MINUTES, lockFileAsync(uploadLock.get(), ltWrite))
);
if (!result) {
if (!unsafeLockFileSingleThreaded(uploadLock.get(), ltWrite, std::chrono::minutes(15)))
printError("somebody is hogging the upload lock for '%s', continuing...");
}
}
auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri));
TRY_AWAIT(copyPaths(*store, *sshStore, inputs, NoRepair, NoCheckSigs, substitute));
copyPaths(*store, *sshStore, store->parseStorePathSet(inputs), NoRepair, NoCheckSigs, substitute);
}
uploadLock.reset();
auto drv = TRY_AWAIT(store->readDerivation(drvPath));
auto drv = store->readDerivation(*drvPath);
std::optional<BuildResult> optResult;
@@ -471,7 +298,7 @@ kj::Promise<void> AcceptedBuild::run(RunContext context)
// stores), we assume we are. This is necessary for backwards
// compat.
bool trustedOrLegacy = ({
std::optional trusted = TRY_AWAIT(sshStore->isTrustedClient());
std::optional trusted = sshStore->isTrustedClient();
!trusted || *trusted;
});
@@ -490,60 +317,74 @@ kj::Promise<void> AcceptedBuild::run(RunContext context)
//
// 2. Changing the `inputSrcs` set changes the associated
// output ids, which break CA derivations
if (!drv.inputDrvs.empty()) {
drv.inputSrcs = inputs;
}
optResult =
TRY_AWAIT(sshStore->buildDerivation(drvPath, (const BasicDerivation &) drv));
if (!drv.inputDrvs.map.empty())
drv.inputSrcs = store->parseStorePathSet(inputs);
optResult = sshStore->buildDerivation(*drvPath, (const BasicDerivation &) drv);
auto & result = *optResult;
if (!result.success())
throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
} else {
TRY_AWAIT(copyClosure(
*store, *sshStore, StorePathSet{drvPath}, NoRepair, NoCheckSigs, substitute
));
auto res = TRY_AWAIT(sshStore->buildPathsWithResults({DerivedPath::Built{
.drvPath = makeConstantStorePath(drvPath),
.outputs = OutputsSpec::All{},
}}));
copyClosure(*store, *sshStore, StorePathSet {*drvPath}, NoRepair, NoCheckSigs, substitute);
auto res = sshStore->buildPathsWithResults({
DerivedPath::Built {
.drvPath = makeConstantStorePathRef(*drvPath),
.outputs = OutputsSpec::All {},
}
});
// One path to build should produce exactly one build result
assert(res.size() == 1);
optResult = std::move(res[0]);
}
auto & result = *optResult;
if (!result.success()) {
throw Error(
"build of '%s' on '%s' failed: %s",
store->printStorePath(drvPath),
storeUri,
result.errorMsg
);
}
auto outputHashes = staticOutputHashes(*store, drv);
std::set<Realisation> missingRealisations;
StorePathSet missingPaths;
auto outputPaths = drv.outputsAndPaths(*store);
for (auto & [outputName, outputPath] : outputPaths) {
if (!TRY_AWAIT(store->isValidPath(outputPath.second))) {
missingPaths.insert(outputPath.second);
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) {
for (auto & outputName : wantedOutputs) {
auto thisOutputHash = outputHashes.at(outputName);
auto thisOutputId = DrvOutput{ thisOutputHash, outputName };
if (!store->queryRealisation(thisOutputId)) {
debug("missing output %s", outputName);
assert(optResult);
auto & result = *optResult;
auto i = result.builtOutputs.find(outputName);
assert(i != result.builtOutputs.end());
auto & newRealisation = i->second;
missingRealisations.insert(newRealisation);
missingPaths.insert(newRealisation.outPath);
}
}
} else {
auto outputPaths = drv.outputsAndOptPaths(*store);
for (auto & [outputName, hopefullyOutputPath] : outputPaths) {
assert(hopefullyOutputPath.second);
if (!store->isValidPath(*hopefullyOutputPath.second))
missingPaths.insert(*hopefullyOutputPath.second);
}
}
if (!missingPaths.empty()) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
if (auto localStore = store.try_cast_shared<LocalStore>())
if (auto localStore = store.dynamic_pointer_cast<LocalStore>())
for (auto & path : missingPaths)
localStore->locksHeld.insert(store->printStorePath(path)); /* FIXME: ugly */
TRY_AWAIT(
copyPaths(*sshStore, *store, missingPaths, NoRepair, NoCheckSigs, NoSubstitute)
);
copyPaths(*sshStore, *store, missingPaths, NoRepair, NoCheckSigs, NoSubstitute);
}
// XXX: Should be done as part of `copyPaths`
for (auto & realisation : missingRealisations) {
// Should hold, because if the feature isn't enabled the set
// of missing realisations should be empty
experimentalFeatureSettings.require(Xp::CaDerivations);
store->registerDrvOutput(realisation);
}
context.getResults().initResult().setGood();
} catch (...) {
RPC_FILL(context.getResults(), initResult, std::current_exception());
return 0;
}
}
void registerLegacyBuildRemote() {
LegacyCommandRegistry::add("build-remote", main_build_remote);
void registerBuildRemote() {
LegacyCommands::add("build-remote", main_build_remote);
}
}
+1 -1
View File
@@ -3,6 +3,6 @@
namespace nix {
void registerLegacyBuildRemote();
void registerBuildRemote();
}

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