Compare commits

..
Author SHA1 Message Date
Jade Lovelace dad8a30906 release: 2.95.0 "Kakigōri"
Release produced with releng/create_release.xsh

Change-Id: I9d78b7d65053fb1d4a00dfd0d7ce9c93eba68365
2026-03-13 09:06:49 -07:00
Jade Lovelace dc7d5c45a4 release: release notes for 2.95.0
Release created with releng/create_release.xsh

Change-Id: I4cb4c81a440787fe5417369e5a058c8bb51c0cb1
2026-03-13 09:06:04 -07:00
Jade Lovelace fc5ab134d9 2.95.0: release name
Change-Id: I20fe0119cb3f011c3ea2f8355a120a8c2fecb610
2026-03-13 09:02:05 -07:00
rootile a05dbd2d7f docs: fix typo in distributed builds
Change-Id: Ie0bf1e6f2cecade786647aab1030279b57b7efb7
2026-03-13 16:24:51 +01:00
Jade Lovelace fada71a749 Update nixpkgs and nix2container
Fixes: https://git.lix.systems/lix-project/lix/issues/1152

Change-Id: I29ccfe46d7de43f521b88beff73a782a1fdb8d8c
2026-03-11 11:21:11 +00:00
Raito Bezarius 7c53a2cf9c manual/rl-next/f1-lang: reduce CLs to 1 in the chain
This avoids a large list of CLs when a user can discover all the CLs by
browsing the chain.

Change-Id: I1890eb87e8bf6f930d3d00c3f7156690bb8de068
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-10 17:09:22 +00:00
Raito Bezarius 5789f4b0a9 manual/rl-next: fine-tune the release notes
Follow up of https://gerrit.lix.systems/c/lix/+/5346?tab=comments for
the obvious pieces.

Change-Id: If0f640f786b0778d016187cb24c0513a48b5a30b
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-10 17:09:22 +00:00
Qyriad ca40ce8671 repl: always reload, but restore on failure
This might do more copies than are necessary. I think that's fine.

Sorry, :reload not reloading has been bothering the shit out of us.

Fixes #1115.

Change-Id: I7f4caca3dad39696ce66ce57b1a520836a6a6964
2026-03-10 15:05:25 +00:00
Qyriad 7f9b734aa5 repl: refactor initEnv into init+swap
Change-Id: Ica451fd95f55fe7893579c09eeca77db6a6a6964
2026-03-10 15:05:25 +00:00
rootile 03edd9f75d release-notes: add horrors to deprecated features credits
Change-Id: I73ed3198cfdbab15edddc9393010cafdf5050176
2026-03-09 22:44:29 +00:00
rootile e00ee5954e maintainers: unify issue references
So far, we had both `fj#` and `lix#` issue references in our release
notes, due to supporting both in the md files.
This commit unifies those in order for all references to be consistent.

Change-Id: I67c75784b460bfe4ebf214c2f6ac105cc60a7bad
2026-03-09 22:16:50 +00:00
Qyriad 861e5a7471 add misc/upgrade-lix.sh wrapper script, for nix-daemon@.service checks
Change-Id: I073b753f24e24eefe9d8f68543c4d1be6a6a6964
2026-03-09 22:28:51 +01:00
eldritch horrors 8c03cc961f nix/daemon: fix more stdio forwarding errors
kj can and will throw exceptions immediately without wrapping them as
promise results, and we must take care of these as well to not crash.

fixes #1150

Change-Id: Ifa29d0f3da4a6490f3e45d4c04a8fa49eaa20f43
2026-03-09 14:41:56 +01:00
K900 35fbfea6f8 package.nix: fix build with latest nixpkgs
mdbook-linkcheck was dropped from nixpkgs and replaced with mdbook-linkcheck2,
which is not entirely a drop-in replacement, but drop-in enough for us.

Change-Id: Iab03efab89ebae70811e0de3ea7cf0a9a059a9e4
2026-03-08 13:35:28 +03:00
Alois Wohlschlager fb9a575766 libstore: fix builder launch failure on older kernels
Since commit ac64c727b5, during launch of the
builder it is attempted to raise all capabilities into the ambient set.
Specifically, what "all" means here is determined by the Linux API headers Lix
was built against.

Occasionally, new capabilities are added in the Linux kernel, leading to
PR_CAP_AMBIENT_RAISE failing with EINVAL on the newly added capabilities if the
API headers are from after the change but the running kernel is from before.
Similarly to how capset already silently ignores nonexistent capabilities, we
ignore this error so the builder doesn't fail to launch unnecessarily.

Unfortunately it is very hard to test for this situation currently, since the
last time a capability was added was CAP_CHECKPOINT_RESTORE in Linux 5.9, and
all kernel versions in nixpkgs are newer than that.

Change-Id: Ibeb2f0757729b877bd3ca9f02e1aa4536a6a6964
2026-03-07 12:02:41 +01:00
eldritch horrors c914b9fc53 nix/daemon: wrap kj stdio forwarding errors nicely
not doing this has lix crash if stdio forwarding fails for odd reasons,
such as ssh failing to set up a connection due to transient dns errors.

cf #1148

Change-Id: I543b7444236e69d3c13b47fb6c6eb37c65b96763
2026-03-05 21:43:52 +00:00
Katalin Rebhan 981dd6e9b2 Add missing <sys/time.h> include
This is necessary for utimes and lutimes.

Change-Id: I352784606768f2b8a7de3c652e2a197e6a6a6964
2026-03-05 19:11:45 +01:00
Raito Bezarius 31a4f4547a Revert "libexpr/primops: allow storePath in pure evaluation mode"
This reverts commit 37ccd28c3b.

Reason for revert: https://git.lix.systems/lix-project/lix/issues/1147
More impurities were introduced than we wanted.

Fixes #1147.

Change-Id: Iec3b1d0e9a77484a68c6d9307a7a527fda236ed2
2026-03-05 17:09:46 +00:00
b7cf773540 libexpr: warn when encountering IFD with warn-import-from-derivation
This is intended to be a softer version of
`allow-import-from-derivation`, allowing for users to only flag when IFD
is encountered rather than error out

Based-on: https://github.com/NixOS/nix/pull/13279
Co-authored-by: gustavderdrache <alex.ford@determinate.systems>
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
Change-Id: I879a444e3a24b4e82a8cea3a5a94834c78c3924a
2026-03-05 13:39:12 +00:00
Qyriad 6f25c5468d cli: factor out and cleanup hasContent() for flake-show
Change-Id: I15c2df9a207639e81ff9030b737268526a6a6964
2026-03-04 19:44:21 +00:00
skye 8b38edaf1e libexpr: Migrate emitTreeAttrs to return a Value
Part of #1136 and progress towards #744

Change-Id: Iaa011161b26bda237bcf4424bf8262726a6a6964
2026-03-04 11:53:34 -05:00
Raito Bezariusandeldritch horrors 37ccd28c3b libexpr/primops: allow storePath in pure evaluation mode
`builtins.storePath` allows you to use "external" knowledge of present
store paths in your store to be used in your expressions.

This is sometimes used to avoid double wrapping store paths, for example
when dealing with nixpkgs sources (`builtins.storePath pkgs.path` is a
frequent pattern).

Unfortunately, using your external knowledge of present store paths is
technically impure because Flakes is about not depending on the *STATE*
of your store, no matter what you know about it or what you do to ensure
that your knowledge is accurate.

That being said, `builtins.storePath` is already possible in the
fragment of "pure Nixlang" via a clever use of `builtins.appendContext`.

Precisely:

```
  storePath = path:
  let path' = builtins.unsafeDiscardStringContext path;
  in
  # NOTE: merging the context set in all generality is impossible
because getContext on a pure path doesn't work.
    builtins.appendContext path' { ${path'} = { path = true; }; };
```

works in pure contexts.

Because of this, we deem that storePath should be allowed in pure
contexts and users do not have to come up with a `storePath` polyfill.

Fixes #402.

Change-Id: I5fff750a4feed082745431835db451f945249cfb
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-04 11:33:30 +00:00
Raito Bezarius e8015836e3 libcmd/profiles: keep derivations if keep-env-derivations = true
nix3 CLI never honored that setting.

When we update a nix3 profile element with new built store paths for
which we know the deriver (the derivation path which built it), we add
the derivation paths to the profile element to prevent garbage
collection the same way the nix2 CLI logic does.

Fixes #1095.

Change-Id: Icc236d174c5ce5ffe042d1c8e1968f6cb5b50359
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 22:13:02 +00:00
isabelandRaito Bezarius fc649250ec libexpr/flake-config: collect untrusted settings into one prompt
Instead of showing untrusted configuration items one by one, collect all
of them into one batched ask with 4 options:

- apply the configuration wholesale **for now** (yes)
- apply the configuration wholesale and trust it permanently (allow
  permanently)
- selectively choose subset (no)
- rejecting the configuration wholesale (no to all)

Note that we do not offer options to reject permanently a configuration,
that's what `--no-accept-flake-config` is for.

Individual prompts gain a new option to distinguish "yes for now" and
"yes forever".

Fixes #682.

Change-Id: I2492717ac277af33ea4ac9b1a11bd7d6d1bfe0db
2026-03-03 21:57:03 +00:00
Raito Bezarius b28723c5b9 libexpr/eval: do not confuse path and string with contexts in messages
In messages printed by the evaluator, we use showType(.) to say things
like "expected X, got Y" where X, Y can be string, string with context,
etc.

After changes in the Lix data model (pointer tagging and friends), paths
got squished inside a internal string type.

We missed updating `showType` to take this fact into account which
caused an unfortunate:

`error: expected a string but found a string with context:
/nix/store/wjf8rdpp63rhyasbzc7zfms1agf7pwyd-source`

while using a path on `builtins.getContext`

A test is added.

Change-Id: Ifb0129ead2ea1973fc17dc0133f8a694995536b1
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 21:36:13 +00:00
Raito Bezarius da37164630 libutil/strings: add partitionString
This partitions a string into two parts based on the first occurrence of
the separator.

This function handles the case when the separator never occur in the
target string by returning an optional<T> in the second argument of the
pair.

Change-Id: I9ad44375dbaa137a4d21d2408bc2ffa34fab62a7
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 20:54:08 +00:00
Raito Bezarius 135c28be53 libcmd: introduce enum traits for CLI parsing
Parsing and completing enumerations on the CLI was usually done by hand.

With this enum trait, the parsing and completion is automated away.

Change-Id: Icd49729564355d4c79e2c8050ce7e8b9d8e7eda3
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 20:54:08 +00:00
Raito Bezarius a2f1369d18 libmain: drop categories for dry-run and json args
36c4d6f592 introduced it commented. Zero
explanation why.

horrors suggested to drop it entirely because it hide the options in
categories but they are pretty common and we should make as much visible
as possible.

Change-Id: I09894b5ba0f2b2cce5869136914289fed034fce3
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 20:54:08 +00:00
Raito Bezarius b55260ce4a package/devshell: add pkgs.tree
Fixes #823.

Required for releng scripts.

Change-Id: I876784ffc868541924c2bb957aec58b704fd7dd2
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-03 20:22:34 +00:00
eldritch horrors 7a0a85b543 libstore: recursively delete cgroups
fixes #1143

Change-Id: I9f5cf5c127ac23e60e3232d85f338e467ed4f170
2026-03-03 15:49:52 +01:00
Raito Bezarius 092064db4c libstore/build: allow preferLocalBuild = true to bypass max-jobs = 0
When `max-jobs = 0`, our async semaphores have null capacity and
therefore no slot token can be acquired.

In addition, a derivation with `preferLocalBuild = true` with `max-jobs
= 0` which is not a built-in derivation is not considered suitable for
being possible to build.

Our documentation in `max-jobs` writes:

> `0` is useful when using remote builders to prevent any local builds
(except for preferLocalBuild derivation attribute which executes locally
regardless).

A valid interpretation is that `preferLocalBuild` derivations (all of
them) will always execute even if `max-jobs = 0`.

This CL achieves this promise by enabling `preferLocalBuild = true`
derivations to draw in priority capacity from a `preferLocalBuild`-only
pool and then fall back to the build pool (`maxBuildJobs`).

If there's non-zero max-jobs, we make the `preferLocalBuild`-only pool
empty.

If there's zero max-jobs, we make the `preferLocalBuild`-only pool
non-empty (capacity: 1).

Remark 1: if `max-jobs = 0`, no non-`preferLocalBuild = true`
derivations can be built without a remote builder and `preferLocalBuild
= true` derivations can be built one at a time if `extra-local-jobs` is
not overridden.

Remark 2: if `max-jobs != 0`, no `preferLocalBuild = true` derivations
can bypass capacity limits, i.e. `max-jobs` unless `extra-local-jobs` is
overridden.

Fixes #855.

Change-Id: I00a0acac7375a881aec6281ebb13a4530b26e460
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-02 23:46:38 +01:00
Raito Bezarius bd108b7e61 libutil/config: support optional<uint32_t>
This is going to be used in the extra-local-job future setting.

Change-Id: Ied76f32b8fa97cb71691d76167103001aa14fa01
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-02 20:20:06 +01:00
Raito Bezarius ac6c9a9c0a libfetchers/github: distinguish ref/rev provenance
When ref/rev are very similar looking, e.g. a revision SHA1, the logic
to reconstruct whether we had a ref or rev initially cannot work.

This regression was introduced by
I2c72d5a32e406a7ca308e271730bd0af01c5d18b which passed the information
as an attribute field called `refOrRev`, instead, we pass `ref` or `rev`
but not `refOrRev`.

We apply the same post-processing logic to distinguish rev/ref in
path-style flake references: `github:owner/repo/$refOrRev`.

Fixes #520 #841.

Change-Id: I2b1985cd5f351f43fea84232c1972715e2408fb1
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-02 13:14:42 +00:00
eldritch horrors 6ddc59de47 launch-builder: don't limit sandbox setup data size
the channel we're using is fully trusted, we don't need the traversal limit.

fixes #1121

Change-Id: I2833a7459cec1e2392e8740d8cab213685d3e2b3
2026-03-02 12:10:12 +00:00
skye 9a408cbeb7 libexpr: Replace Value::mkPrimOp with constructor calls
Change-Id: I19b05e260945e237f7856b5d644a43076a6a6964
2026-03-01 18:02:58 -05:00
Raito Bezarius 74300fd0a7 libexpr/primops: reject __json in structured attrs derivations
In structured attrs derivations, __json is used to serialize the `env`
attribute into a JSON object.

If the derivation enables structured attributes AND specify its own
`__json`, one of the field will take precedence (the reader can have fun
by guessing which one).

To reduce underspecification, we disallow `__json` in structured
attributes derivations.

Fixes #380.

Change-Id: I51c3b2af1ff9449471ba81d4c72df6a7a263eef7
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-03-01 19:05:54 +00:00
skye 12cee5cb22 libcmd/repl: Migrate evalString to return a Value
Change-Id: I41cd79b71106474d048d447befac16676a6a6964
2026-03-01 01:01:47 -05:00
skye 8623dade34 libexpr: Migrate callFlake to return a Value
Change-Id: Ibdac6eb1c9dfda894d783a7b6e333f486a6a6964
2026-03-01 01:01:47 -05:00
skye 2be998eeb4 libexpr: Migrate Evaluator::evalLazily to return a Value
Change-Id: I9f778407d454e141cb9b7959bbc02ed26a6a6964
2026-03-01 01:01:47 -05:00
skye c6b4f30be9 libexpr: Migrate EvalState::autoCallFunction to return a Value
Change-Id: I426c3d413b18848090dd05674a08e5fb6a6a6964
2026-03-01 01:01:47 -05:00
skye 27bf276304 legacy/nix-env: Migrate loadSourceExpr to return a Value
Change-Id: Ia1e1ac6fe9fd00d7a2fa4a39a3ce21e86a6a6964
2026-03-01 00:04:28 -05:00
eldritch horrors 30e9387cf9 testing: migrate path-from-hash-part.sh
Change-Id: Ied00671595d82c6d446f117d6aa9c42a0c758cb6
2026-02-28 22:09:44 +00:00
eldritch horrors 8d389fcccf testing: migrate selfref-gc.sh
Change-Id: Ibead4030448fb9251be78b3c876c7f054154c83c
2026-02-28 22:09:44 +00:00
eldritch horrors f4c92f8872 testing: migrate function-trace.sh
Change-Id: I44bd28165070f55f21b052bc02ba6f2ea5787a1d
2026-02-28 22:09:44 +00:00
eldritch horrors fae0242f69 testing: migrate ssh-relay.sh
Change-Id: I520c8be1c30b4ee7660c8ceeba62a6d0757c337b
2026-02-28 22:09:44 +00:00
eldritch horrors e8cb30b11c testing: fix f2 NIX_BIN_DIR determination from meson
`nix.full_path()` is the *built* path, not the *installed* path. in the
sandbox this point to a location that contains *only* `nix`, not any of
the old-cli symlinks. any test that needs them in path would thus fail.

Change-Id: Ia651db8d1151a84f8d1b52e8993f6db61b0fe104
2026-02-28 22:09:44 +00:00
skye f856d4fd25 libexpr: Migrate EvalState::evalFile to return a Value
Change-Id: I19ce8623477dd96628476b3e3dd58cfd6a6a6964
2026-02-28 15:53:10 -05:00
skye debf5554e0 libexpr: Consolidate implementation between Value string constructors
Change-Id: I5bf8d58b534cd652d89f7b93019378b66a6a6964
2026-02-28 15:53:10 -05:00
skye be3a40e5dc libexpr: Replace Value::mkString with constructor calls
Change-Id: I55bba546eb090728a71734450a2a5f496a6a6964
2026-02-28 15:53:10 -05:00
Tom Hubrecht d52033fc77 nix/develop: Don't ignore SSL_CERT_FILE when its value is meaningful
Change-Id: I31e85a5995edc40ed2e687077ffdf563e717abb4
2026-02-28 12:32:45 +00:00
benaryorg 052d04512e libfetchers: Provide gitDir for rev-list operation
Without the `--git-dir` git will attempt to figure out which the git directory is on its own.
This causes issues when the `GIT_DIR` envvar is set in the environment for other reasons (such as being part of a `git rebase`).
Providing this parameter overrides the environment and thus makes sure the revs are always coming from the intended repository.

Fixes: #1135
Change-Id: Ibd43cfd8e0278463c0e1ccf86779982947a6038a
Signed-off-by: benaryorg <binary@benary.org>
2026-02-28 09:06:18 +00:00
eldritch horrors dda934965d testing: migrate build-jobless.sh
Change-Id: Ica9a0c5b8bea50d302ad633d3801431adcdba5e7
2026-02-27 17:43:07 +00:00
eldritch horrors 378c86eadf testing: migrate compute-levels.sh
this test wasn't even run

Change-Id: I735c8b2d2c63a65c665d6344a98ddb3bbbf94f43
2026-02-27 17:42:17 +00:00
eldritch horrors 298373615e testing: migrate impure-eval.sh
Change-Id: Ifd2b6c117511461ce08fa3f9e63635857cb5b015
2026-02-27 17:42:17 +00:00
eldritch horrors 14d8209198 testing: migrate output-normalization.sh
Change-Id: I51a021b27fa27b531bb49b8529bae2e9bf74641a
2026-02-27 17:42:17 +00:00
eldritch horrors b2ae7c3965 testing: migrate pass-as-file.sh
Change-Id: I9c3a940ede9353e977e60e0650eaa5a64cc6fa5e
2026-02-27 17:42:17 +00:00
eldritch horrors 32a96169d6 testing: migrate optimise-store.sh
Change-Id: I900183e11ba1405c9aa72028a8902ad8cf023e69
2026-02-27 17:42:17 +00:00
eldritch horrors 5fb0dd156d testing: migrate build.sh
Change-Id: I9d2da21cc226e0c1ef2dfa4d475c1989bbbfaf79
2026-02-27 17:42:17 +00:00
eldritch horrors 5f2c771b5a testing: migrate placeholders.sh
Change-Id: Iad6a6f53dac23cc5e49961571dd4c0545d616d7e
2026-02-27 17:42:17 +00:00
eldritch horrors b8b69dde05 testing: migrate local-store.sh
Change-Id: I5172fc2611a56b19f55d5c05dacdfef5cf330739
2026-02-27 17:42:17 +00:00
eldritch horrors 26f1397b75 testing: migrate suggestions.sh
Change-Id: Iad28262035aa96c5ef6fa33e2a830b5fa8a9ae50
2026-02-27 17:42:17 +00:00
eldritch horrors 8cf21fcf75 testing: migrate case-hack.sh
Change-Id: I552dd596764a779e1485a6326363d4f4283110f3
2026-02-27 17:42:17 +00:00
eldritch horrors 4caa622d78 testing: migrate fetchMercurial.sh
Change-Id: Iab81ea161e3be69bf7753b3ed9cd8f59cd8fe0ed
2026-02-27 17:42:17 +00:00
Qyriad f13566a3f6 repl: fix 'tokens-no-whitespace' in :use's Nix expression
Change-Id: Ifa2bc6b1204cc5a85422128c76b192296a6a6964
2026-02-27 08:51:40 +00:00
eldritch horrors 0bcdfe2c43 testing: migrate fmt.sh
Change-Id: Icc593b57a06c7fdf75762094982788f6351dcadc
2026-02-26 19:43:39 +00:00
Raito Bezarius bcab3d5da3 libstore/build: set impure environment variables only if they are set
To stop spurious warnings, we will stop this bizarre behavior of setting
empty values to impure environment variables.

On the warning side, we verify that the presence of the environment
variable.

The corresponding test is updated to "there is a warning" to "there is
no warning".

Change-Id: I12f5c6445ef00a83d269488d7aed0b0f61aeec12
2026-02-26 15:33:22 +00:00
Raito Bezarius 72a6d5ff48 tests/functional2: test spurious warnings for certificates
All impure environment variables are initialized as part of `initEnv()`
to an empty value if they are unset.

Whenever `NIX_SSL_CERT_FILE` is set, this cause a spurious warning.

Let's document it here as a test before we fix it.

Change-Id: Iccba8ccb487d9cc25490e940ff09c1c5a13ae097
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-02-26 15:33:22 +00:00
Raito Bezarius 0741e24266 tests/functional2: migrate (un|)sandboxed CA tests
CA tests have grown quite complicated and are hard to debug and
manoeuver for new needs.

They are a prime target for F2 migration and they were extremely
pleasant to write.

Most functionality is preserved or improved with additional behaviors
asserted on warnings and the full set of reports.

Change-Id: I70cd52abbe5ff13f56744b966ab00962ad3a49d6
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-02-26 15:33:22 +00:00
eldritch horrors dde7bddbd4 f2: fix Nix::add_[dx]p_feature type hints
Change-Id: I743b3ac821315465d1d22700ca9b06d8cc1985f0
2026-02-26 14:16:13 +00:00
eldritch horrors f2df62439c testing: migrate flakes/flakes.sh (part 18)
nonflake inputs

Change-Id: I5017ece5028652e3ae19c5e00e67358fc9c0253d
2026-02-26 13:11:25 +00:00
eldritch horrors 30ce32e2f6 testing: migrate flakes/flakes.sh (part 17)
symlinks in flake dirs, recursive lookups, update with override

Change-Id: I1491ca8e618ff5e06a06d3cc3648ae0750a1ffde
2026-02-26 13:11:25 +00:00
eldritch horrors b92f1aa865 testing: migrate flakes/flakes.sh (part 16)
input overrides during locking

Change-Id: I20e8e8bc2579f2f9bbaf7b522647a520d010ec43
2026-02-26 13:11:25 +00:00
eldritch horrors cbe4d1b339 testing: migrate flakes/flakes.sh (part 15)
flake follows handling during locking

Change-Id: Ia3f2b7a8df1d0ec51fd97d14d49788b33dda7754
2026-02-26 13:11:25 +00:00
eldritch horrors 2634585a48 testing: migrate flakes/flakes.sh (part 14)
flake clone

Change-Id: I6697d109465eaededfb2ac8ee552b6ac971d2e8a
2026-02-26 13:11:25 +00:00
eldritch horrors f0f8117d5b testing: migrate flakes/flakes.sh (part 13)
builds with incomplete lockfiles

Change-Id: Ibf386ec98208d5b706236277e2eae9e144d9bdb0
2026-02-26 13:11:25 +00:00
eldritch horrors 93af25a706 testing: migrate flakes/flakes.sh (part 12)
gc rooting behavior

Change-Id: I7b3aa765b8e08aa8a4ce96988629ee76c76b46a0
2026-02-26 13:11:25 +00:00
eldritch horrors c45e34bbc5 testing: migrate flakes/flakes.sh (part 11)
input updates with cli commands

Change-Id: Idddfe77a285f9c2cbc4f1463454af539042bc23e
2026-02-26 13:11:25 +00:00
eldritch horrors f864626a1c testing: migrate flakes/flakes.sh (part 10)
getFlake behavior

Change-Id: Iff9bb6e834ff2545db11b72f5a6ab3ddf42e5662
2026-02-25 12:47:08 +00:00
eldritch horrors c090a9d1ec testing: migrate flakes/flakes.sh (part 9)
bulk of build tests

Change-Id: I2b357162e16e2d14bb8ae6247ad126ad452c0825
2026-02-25 12:47:08 +00:00
eldritch horrors 3327a1fcae testing: migrate flakes/flakes.sh (part 8)
eval-system influences attribute choice

Change-Id: I02d611ed17748c73d5c77ebd0a44f558ab63d1c8
2026-02-25 12:47:08 +00:00
eldritch horrors 7976f9fb6e testing: migrate flakes/flakes.sh (part 7)
registry maintenance and queries

Change-Id: Id0aef61ce91972417ba3a941aba7b2c9ca05bf7c
2026-02-25 12:47:08 +00:00
eldritch horrors b4846d4e51 testing: migrate flakes/flakes.sh (part 6)
flake attr matching

Change-Id: If5a1f01f9939740636482d2755eb836e2166ce97
2026-02-25 12:47:08 +00:00
eldritch horrors 5d11ed07f5 testing: migrate flakes/flakes.sh (part 5)
build bare repo, build tarball, lock path urls without repo

Change-Id: I7cb7494dcf29ec9b88c923c54a798685725785a1
2026-02-25 12:47:08 +00:00
eldritch horrors 4ef9fb3aee testing: migrate flakes/flakes.sh (part 4)
metadata query functionality

Change-Id: I8f3866316994426664468edfbe154505ed2428af
2026-02-25 12:47:08 +00:00
eldritch horrors 126ef6321d testing: migrate flakes/flakes.sh (part 3)
add-path and path-info interactions

Change-Id: I8649442eb54d539957d4339a00b948e1173d2da7
2026-02-25 12:47:08 +00:00
eldritch horrors 987a906317 testing: migrate flakes/flakes.sh (part 2)
legacy cli interactions

Change-Id: Ibdefbbf4b10ea8554a75caf589bb1f5a26639f4a
2026-02-25 12:47:08 +00:00
eldritch horrors 1df00b7db0 testing: migrate flakes/flakes.sh (part 1)
handling of alternate lock file locations

Change-Id: I402fa3b1a48805e571eecc6772f2656e93c68086
2026-02-25 12:47:08 +00:00
eldritch horrors e76c6afd8d testing: migrate flakes/follow-paths.sh
Change-Id: I825445a51f496dbe2efde684a0045e6fb56d9c0a
2026-02-25 12:47:08 +00:00
Thomas MiedemaandQyriad 6182a5e659 nix-daemon: source nix-profile-daemon.sh only once
Cherry-picked-from: https://github.com/NixOS/nix/pull/12805
Co-authored-by: Qyriad <qyriad@qyriad.me>
Fixes: #1134
Change-Id: I0c575f6b974e06b5064564bb084829fa6a6a6964
2026-02-24 18:36:39 +00:00
skye 53c0e884d8 Migrate EvalState::eval from out param to return a Value
Instead of taking in a final argument `Value &` out parameter which it
writes to, it now returns its result

Change-Id: Iab6bc3a3ac6a4b17c6d31115a766a6ea6a6a6964
2026-02-24 13:00:30 -05:00
skye d14613459b libexpr: Migrate EvalState::callFunction to return a Value
Previously it had an out parameter. Now it has a return value.

Change-Id: I9ec465a7d23b99da9132f1ab0fcc5cf16a6a6964
2026-02-24 13:00:30 -05:00
eldritch horrors 3b0e2ddd0a libutil: don't report DecompressionStream shutdown errors
we already report errors that happen during reads via exceptions
rethrown from read. reporting errors during destruction too is a
source of confusion for users since these errors are not usually
relevant and just the decompressor thread reporting short reads.
shorts reads during shutdown are not an error, they're expected.

fixes #1138

Change-Id: I7983ef0ed7722460f1d683bc8171a454b3d06e90
2026-02-24 15:28:56 +01:00
Qyriad 6b4de44461 nix-env/query: don't use RAII for closing xml tag
I could instead add the right braces or manually ensure the
XMLOpenElement destructor is run at the right time. Or I could just
write what I actually want to happen.

Fixes #1137.

Change-Id: Ie1f157de1632571fb0c21e26d8e3cae56a6a6964
2026-02-24 12:28:45 +01:00
skye 1ef7ccfc72 libexpr: migrate Expr::eval to return a Value, take 2
This is a rebase of CL 1626 after the performance problems that blocked
that change are no longer an issue.

Change-Id: I4a17f7606c5fdc9a924933a860eb401f6a6a6964
2026-02-23 18:11:47 -05:00
skye 62a2663436 libexpr: Replace Value::mkBool with constructor calls
Change-Id: I714271f6cbd2f5b2d6e1e7fe7eb7feab6a6a6964
2026-02-23 15:12:35 -05:00
rootile d641a829bb tests/functional2: migrate brotli.sh and zstd.sh
Change-Id: I5f1252e8f29a9551f3d6b2ed8f0598f524906aed
2026-02-23 20:44:46 +01:00
skye 864c5e7507 libexpr: Replace Value::mkInt with constructor calls
Change-Id: I09b8e3aa61042a60c2ae767fc44c26b66a6a6964
2026-02-23 11:55:02 -05:00
skye 23a0b78a16 libexpr: Replace Value::mkFloat with constructor calls
The pseudo-constructor `Value::mkFloat` would previously be called on an
default-constructed (under-initialized) `Value` to create a properly
initialized `Value` that represents a float. This change removes mkFloat
and constructs float `Value`s directly.

Change-Id: I48ae3a836842ce5e5eda6323404ba7576a6a6964
2026-02-23 11:51:29 -05:00
skye 492d7bbe1f libexpr: Convert Value::mkStringMove to a constructor
The pseudo-constructor `Value::mkStringMove` would previously be called
on a default-constructed (under-initialized) `Value` to create a
properly initialized `Value` that represents a string, reusing an
existing GC allocated Str. This change turns that method into a proper
constructor

Change-Id: I8d7a97e2afce231a04ecf56fdd6d22d06a6a6964
2026-02-23 11:40:02 -05:00
rootile 6b9a121637 testing: throw an error when a command object has not been run
it sometimes happens that one forgets to add `.run().ok()` to a command,
leading to things not actually being tested, potentially even slipping
though code reviews!

This commit adds a check at fixture teardown time, checking that all
commands have been run. Sadly, due to when this check happens, we cannot
add a test checking for this behavior

Change-Id: If3df2c20c267b9f03ae0ca099b77c57e2310f335
2026-02-23 17:21:01 +01:00
eldritch horrors b015654133 testing: also report tests that fail teardown as failures
this includes tests that fail teardown when *skipped*, which confuses
the tap parser by reporting more tests than advertised in the header.
not sure what to do about this though, and it is better than nothing.

Change-Id: I4fc6badacbfa3b3d5f5f4a4ad76b177379bb4a30
2026-02-23 16:57:35 +01:00
eldritch horrors 3c1c130c59 testing: disable progress reports in tap mode
pytest-tap didn't get it right in combination with xdist. we need to
replace the reporter *completely*, which is just incredibly weird :/

Change-Id: I2e35b9dc8ea4b24563b9b3306312778781eb674e
2026-02-23 15:26:18 +00:00
skye e8f161ead1 libexpr: Replace Value::mkPath with constructor calls
The pseudo-constructor `Value::mkPath` would previously be called on an
default-constructed (under-initialized) `Value` to create a properly
initialized `Value` that represents a path. This change
removes mkPath and constructs path `Value`s directly.

Change-Id: I9021de1ff59490828f9fec6866e083996a6a6964
2026-02-23 09:37:40 -05:00
skye d07bbb109e libexpr: Replace Value::mkAttrs with constructor calls
The pseudo-constructor `Value::mkAttrs` would previously be called on an
default-constructed (under-initialized) `Value` to create a properly
initialized `Value` that represents an attribute set. This change
removes mkAttrs and constructs attr `Value`s directly.

Change-Id: I11cd801eefecd454a7a5b6229d6770d06a6a6964
2026-02-23 03:54:35 +00:00
eldritch horrors c2b61c5da3 testing: migrate flakes/mercurial.sh
hg is *so fucking slow* omfw

Change-Id: I0f4d1d2a546a75f965ff017c9451fb1d441990b1
2026-02-22 20:46:06 +00:00
eldritch horrors 7a3f352105 testing: migrate flakes/flake-in-submodule.sh
Change-Id: I9dcf63a2f63b54de541536a00dbd5d8df941ea33
2026-02-22 20:46:06 +00:00
eldritch horrors 8b1ca49fef testing: migrate flakes/develop-r8854.sh
Change-Id: Ib993d30edb97d7705acbf5d94f1831ffbe191d92
2026-02-22 20:46:06 +00:00
eldritch horrors d69048e92b testing: migrate flakes/develop.sh
Change-Id: Ibd97c54efb72285a4b969fe11e6e6adf3a2d5511
2026-02-22 20:46:06 +00:00
Jade Lovelace 01ff67595b nix3-add-path: add references-list argument for ca with references
This is not ca-derivations. We don't care about self-references or any of the
rewriting or stuff like that; if you want something like that, write
your user code so it figures out where it is.

The reason I want to do this is for integrating other build systems with
Lix: if you're importing something built *outside the store* with a
non-Nix build system, it makes no sense to put it in an input-addressed
path since it's not possible to come up with a derivation for it.
But you need *some* hash, so the output hashing is the most sensible option.
It is also nice because of not needing trusted user privileges to import
it, since the hash describes the exact contents of the output path.

We use this feature (implemented externally to Lix; this CL eliminates
that step) at Mercury to integrate buck2 with Nix on the output side: we
import things to the Nix store as ca paths with references.

These can then be consumed by Nix language with:

```
# Hack from https://git.lix.systems/lix-project/lix/issues/402#issuecomment-5889
path:
builtins.appendContext path {
  ${path} = {
    path = true;
  };
}
```

Test plan:
```
$ nix store add-path --references-list xx-refs-list ./README.md
/nix/store/szcwnm13d9gmxx8fly0bz82l42jgysw6-README.md

$ cat xx-refs-list
/nix/store/g9hhwjbkdrw0wnbd3axfs4icyb37nr6b-bash-interactive-5.3p3

$ nix path-info --json /nix/store/szcwnm13d9gmxx8fly0bz82l42jgysw6-README.md | jq .
[
  {
    "ca": "fixed:r:sha256:1pj59fy7zcrn949ry9kgv4ba17h2sy3z2is469abj912cvbl14n3",
    "narHash": "sha256-w5JA12YiJLlUMkRH8YfXAp6gFtlvJp8TSTazf7xLRd4=",
    "narSize": 1384,
    "path": "/nix/store/szcwnm13d9gmxx8fly0bz82l42jgysw6-README.md",
    "references": [
      "/nix/store/g9hhwjbkdrw0wnbd3axfs4icyb37nr6b-bash-interactive-5.3p3"
    ],
    "registrationTime": 1771266146,
    "valid": true
  }
]
```

Change-Id: I005a03003dfc24108e018e599dbe0b5d6a6a6964
2026-02-21 22:50:13 +00:00
eldritch horrors ff8a10f9cd testing: move shell-hello.nix from global assets to flakes
Change-Id: I0039e82cd5ed069d901f4dd96cf33102216a11ea
2026-02-21 16:36:44 +00:00
eldritch horrors 46f99487de testing: use TAP for when running f2 from meson
this requires some hacks to make error reports visible, but hey. it's
better than no progress reports at all, and successful runs no longer
spew huge amounts of useless log output onto the developer's terminal

Change-Id: I9e4766b2f825a4ec451e117eb4609db65f328785
2026-02-21 16:36:44 +00:00
vczf 86268bd618 meson: fix broken build when using custom build directory
Fixes path resolution issue with meson-embedded bash script when
`build` is a symlink, or a custom build directory is passed as a
argument to `just` or `meson`.

Change-Id: I67b13c524d196241bb9a8a3b8ad2c17c2c094ed8
2026-02-20 23:32:33 +00:00
eldritch horrors c040a9d8e4 libstore: only check cgroup support when actually building
not all operations that involve workers need to build. for example nix
copy --from calls instantiate thir worker with the *origin* store, not
the store they copy *into*. for binary cache stores this is not likely
to ever work if cgroups are enabled and the copy is run on normal user
credentials, even though no cgroups will ever be needed to copy things

fixes #1088

Change-Id: I065e29e1a1d0f58d81823609ef0701ff82cdd1d5
2026-02-19 22:26:59 +01:00
eldritch horrors 4fcb434998 testing: migrate flakes/registry.sh
Change-Id: Iba7dd30efc19075a63c505db497b3c0967b47f57
2026-02-18 15:25:08 +00:00
eldritch horrors 4deed5ab35 testing: migrate flakes/build-paths.sh
Change-Id: Ia7f15abd8f5444c69fef4da0d080a2933ac264d8
2026-02-18 13:00:37 +00:00
eldritch horrors 03b8a6dcc2 testing: migrate flakes/flake-metadata.sh
Change-Id: I8370a279bbfa224f27cdba0cf9e79ade6d58644f
2026-02-18 11:32:33 +00:00
eldritch horrors fedb4d5ead testing: migrate flakes/inputs.sh
Change-Id: I4446441cb7eea51a42f055f042cceb3e63b84b92
2026-02-18 11:32:33 +00:00
eldritch horrors 28e1cccb49 testing: migrate flakes/init.sh
Change-Id: If132a14e3d10578489cdca03f67c2166f1362d6e
2026-02-18 11:31:40 +00:00
eldritch horrors fc7165401f testing: migrate flakes/symlink_paths to git fixture
Change-Id: Ieb6eb4b9b91c920fa5ee395dc0f7308965355045
2026-02-17 17:22:24 +01:00
eldritch horrors b1776ce4e2 testing: migrates flakes/subdir-flake.sh
Change-Id: I9ac02056d490473dd751f7ec7857840290f5afc5
2026-02-17 17:22:23 +01:00
eldritch horrors fa7edb9e01 testing: migrate flakes/bundle.sh
Change-Id: I734b52da3c62d6f562d6c843b89cb55ba6bd70d2
2026-02-17 17:21:44 +01:00
eldritch horrors 9adc840eda testing: migrate flakes/unlocked-override.sh
Change-Id: I101c96860e0a025a066880d952d2f24f9b92571e
2026-02-17 17:21:42 +01:00
eldritch horrors 899c5fe9f0 testing: migrate flakes/absolute-paths.sh
Change-Id: Icb9f7e1c8bf17327e32e1ad81f2bfdb4246ba2d7
2026-02-17 16:01:00 +01:00
eldritch horrors 2d73b59679 testing: migrate flakes/search-path.sh
Change-Id: I69c3efe2a33cfb216ffecf5b4bd7f57abb80acfd
2026-02-17 16:01:00 +01:00
eldritch horrors 8500339d95 testing: migrate flakes/config.sh
Change-Id: I7f19b33c30330ccd1f01b72b2e36a542f03f4e49
2026-02-17 16:01:00 +01:00
eldritch horrors 762a28a698 testing: migrate non-pty bits of flakes/show.sh
Change-Id: I4884fd34fa485f9f91281dc3efd69dedd3aad3d9
2026-02-17 16:00:59 +01:00
eldritch horrors ffefebd9f4 testing: migrate flakes/check.sh
Change-Id: I4cb9c675ccfc1763e54ce80f8521300b608bb0eb
2026-02-17 14:20:50 +01:00
eldritch horrors c6931c4176 testing: migrate flakes/circular.sh
Change-Id: Ia9eb3631278957c449dd8791e9cf02cb47705a63
2026-02-17 13:53:26 +01:00
eldritch horrors 04988fa318 f2: add git and git_cmd fixtures for calling git
Change-Id: Icdc03c76164d0db503a2f6c90f2bcb2377d9ced5
2026-02-17 13:53:26 +01:00
eldritch horrors f31ece23da testing: migrate flakes/run.sh
Change-Id: Id953cd257c3831d67531ffa4a131607519361227
2026-02-17 13:53:25 +01:00
Max Siling f1ce35f53c libfetchers: produce a proper error when both ref and rev are set
Affects `github`, `gitlab` and `sourcehut` fetchers.
Previously this was an assertion, which crashed the evaluator
with SIGABRT.

Fixes: #1133
Change-Id: Ia9bb8dd29ac8b9c97bf048827f62c5076a6a6964
2026-02-16 14:25:40 +03:00
eldritch horrors 9520e663c8 libstore: send all changed settings to builtin-builder
this includes logger verbosity, which isn't a setting for some reason.

fixes #1111

Change-Id: Ib078205b41069628010273645e26baf33b1c6d14
2026-02-12 18:00:33 +00:00
eldritch horrors 6e3a7711ca libutil: allow retrieving all *changed* settings too
overridden-ness can be reset, and is usually reset such that setting
value taken from a config file are not considered as overriden. when
launching builtin builders we *do* want to send config file settings
changes to the builder, so we'll need one more getter method for it.

Change-Id: I861538a469121c77ebc1898a276439e6b756797d
2026-02-12 18:24:25 +01:00
eldritch horrors 9723dc2c89 testing: migrate nix-profile.sh test
Change-Id: Id7b4b1c36943123c9d5f538b05cd67408c1cb269
2026-02-11 20:46:18 +00:00
eldritch horrors bffbe73493 f2: remove unused build arguments
they're no longer used since non-diverted stores are the default now.

Change-Id: I277b819340c2b69e1fd06607e562221469b77926
2026-02-11 20:46:18 +00:00
eldritch horrors b34f136f10 f2: don't use diverted stores unless specifically requested
diverted stores are only necessary when the logical store paths of
objects matter for the test itself, such as for derivation hashes,
substitution from golden sample nars, or actual tests of the store
diversion functionality. all other tests can use undiverted stores
to run, especially since only linux can build in diverted a store.

Change-Id: I62f0907bdef9961609af22b610195fcec54c1e57
2026-02-11 20:46:18 +00:00
Raito Bezariusandeldritch horrors 505d0669dc libstore/build: fix starvation during substitution
When the destructor of PathSubstitutionGoal is run, this happens in a
sync context and can cause starvation of all ongoing IO w.r.t. to other
substitutions, including our own substitution.

While there's only a decompressor thread per stream, the other side of
the IO runs on the event loop.

In order to fix this, it is sufficient to remove the thread indirection
and inline the async code.

Fixes #1126. Great thanks to horrors' patience.

Co-authored-by: eldritch horrors <pennae@lix.systems>
Change-Id: I3eb37bc37d156f0f5528364e568fdaa2ced58011
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-02-11 14:18:00 +00:00
piegames ef2fd27467 deprecated-features/rec-set-dynamic-attrs: Downgrade to warning for now
Looks like too much stuff is breaking on this, so let's make it only a
warning for now to ease transition

Change-Id: I52d50ceb1fe1fbe9f4e28d0aabf3537f7e4d52d1
2026-02-11 12:24:35 +01:00
piegames ae4a000576 deprecated-features/broken-string-escape: Improve warning message
Explicitly catch common errors (trying to escape line breaks, badly
escaping interpolations) to provide better messages and user guidance
for these cases.

Change-Id: I3dd1b2ad3bca33be393e65be5e72f4fb9544a46a
2026-02-11 12:24:35 +01:00
rootile a2c91c000e f2: migrate build-delete.sh
Change-Id: I457620a33514477eccb449d4a6237a5ea43fe73d
2026-02-10 21:36:39 +00:00
rootile 45dfadeafa f2: move multiple-outputs.nix to global assets
Change-Id: I666af75a29727a6ea0c207e016d4723d19cbaa6f
2026-02-10 21:36:30 +00:00
eldritch horrors 51f1294bfc packaging: add asan libraries to closure-info if needed
devshells and asan build may fail to run builtins otherwise

Change-Id: Ia9a909671a00ff03822d9847aa086338a4763e86
2026-02-10 16:03:08 +01:00
eldritch horrors 95ac829cf3 libexec: unlazify launch-builder capnp message reading
StreamFdMessageReader reads message data *lazily*. if you don't access
all segments of the message before you close the underlying stream you
may find yourselv reading from something *very* different, and in this
case that something is The Void™. this causes reads to fail, writes on
the other side to fail to match, and finally our build launch to fail.
this does not lead to happy outcomes, so we will copy the full message
into a fresh new buffer *before* we try to access any of its contents.

fixes #1118

all-analysis-by: deprekated <kate@lix.systems>
Change-Id: I105540831fde855817194e9e539acf177f54a6f4
2026-02-09 17:30:05 +00:00
rootile a99b6f18c8 f2: migrate toString-path.sh
Change-Id: I862f532e94e385aa0f14c03e38e7e003c7bc83c3
2026-02-09 15:37:41 +01:00
rootile f761785099 tests/functional2/nix: refactor NixSettings
This is the long awaited refactor of the NixSettings.
It allows one to set, unset and update any and all settings with a neat
and easy-to-use interface

closes #846

Change-Id: Id4cfb5f853cc1168b506a1f6f405076f3a7cab65
2026-02-09 15:37:40 +01:00
eldritch horrors 2b4f1e076c build-remote: catch exceptions in Instance::build
this was just forgotten when the migration was done.

fixes #1083

Change-Id: I7a94edf304323b0c43e0a1cff39e5a52696c50e3
2026-02-09 11:43:56 +00:00
eldritch horrors 879b07fd3d libstore: treat more substituter failures as recoverable
if a substituter is entirely offline and cannot be queries at all we
should not be failing if other substituters are configured. likewise
if a substituter goes offline after querying but before we try using
it we should attempt to fetch that path from some other substituter.

ideally we'd treat all substituters as a single entity instead of as
one store each, then have that single entity take care of fallbacks,
retries, error reporting, etc. that requires larger rewrites though.

fixes #1061

Change-Id: I9d8fc0544ff380bf017256e8fcc82823dc634f10
2026-02-08 19:14:31 +00:00
eldritch horrors b983c15336 libutil: remove startProcess
it's only used by runProgram2, and runProgram2 can do something much better.

Change-Id: Idba563e1adbe3fd8ce07a0bb8ad4fc1b0cc057b9
2026-02-07 22:34:18 +01:00
eldritch horrors 6063ffead9 libutil: remove unused functions
Change-Id: I2b1c42460de50aff1f742856654c59fc4ce88e04
2026-02-07 20:23:33 +00:00
eldritch horrors 2cc49da1ec libmain: remove explicit std::cerr buffering
we don't use std::cerr often enough to want this, and since cerr flushes
after every operation anyway it never did anything useful to begin with.

Change-Id: Ia54be340826da5073e9a1786c463555f4f0e491c
2026-02-07 20:23:27 +00:00
eldritch horrors 909cbb0e40 libutil: improve runProgram2 log message
include argv0 if needed and program path at all times.

Change-Id: Icc5e28e32334e22f67fd58bd88784d4ddd5e583a
2026-02-07 20:34:49 +01:00
eldritch horrors 684aba046a libstore: *actually* always report launch-builder failures
kj exceptions get wrapped as Error instead of passed through as is.
luckily this also means that we can add context to them very easily

Change-Id: Icedab6c016f4434447dd38ba14138c102fc6149a
2026-02-06 15:55:53 +01:00
eldritch horrors ba4f4f917a libstore: always report launch-builder stderr on setup failures
Change-Id: Iac5d5ffe4df05714554766e591bc331405a8a108
2026-02-04 22:35:50 +00:00
eldritch horrors 8b73cbbb67 libstore: correctly initialize build request union members
oops. we have to use init* here, not get*. get returns a discarding
builder for something that was not inited previously, but the linux
cause worked anyway because the first member is created by default!

Change-Id: I40f8a12a04eef2f4e3a80d1537ac9b975490a027
2026-02-03 21:21:30 +01:00
eldritch horrors aa896041e0 libstore: asyncify build child setup completion wait
Change-Id: Ica70af2a1205830f1ca4bb48f42d09923cff2e58
2026-02-03 14:11:59 +00:00
eldritch horrors ac64c727b5 libstore: move build child launching to libexec
this allows us great flexibility in how children are launched (since the
actual launching is done by a separate executable), makes fork no longer
needed in the core codebase (outside of runProgram, anyway), and we even
get to use linux vfork to its full potential to decrease the launch cost
of sandboxes to a constant factor (previously it was O(#drvs + #deps) of
the build graph, which obviously goes to n² quickly if you are unlucky.)

Change-Id: I66e2d1b20242dc24d708666ef325fb8725bd9296
2026-02-03 14:11:33 +00:00
eldritch horrors 1079fe9884 libutil: kill process groups properly
we can have a ProcessGroup for a pid that *should* be a process group
but hasn't gotten around to setting its pgid yet. in such cases we do
want to be killing the thing anyway, not shoot into the void and hope
the right thing falls over. so far this has not been a problem due to
a mixture of just not having done this and being slow enough to work.

Change-Id: I4e0e54513252d8e18256b9286b819bfa957d70dc
2026-02-03 14:51:01 +01:00
eldritch horrors b8a9eaf1c8 libstore: don't use libutil as much for linux sandox setup
if we move this out of libstore and don't want to pull in all of libutil
with its myriad side effects std::filesystem is our best option, by far.
most notably we don't replace pathExists because std::filesystem::exists
behaves like `stat()` on symlinks, not like the `lstat()` as we require.

Change-Id: I1e488418dcabb33f2ebb73d8c3d1b43528aa51f1
2026-02-03 14:51:00 +01:00
eldritch horrors adf17a7b39 libstore: catch all exceptions in builder setup, not just lix errors
this lets us use std::filesystem and other apis to make builder setup easier.

Change-Id: Ie0303139171161887b610f845e2948fe07c143e0
2026-02-03 00:27:40 +01:00
eldritch horrors 8bd344718b libstore: transfer derivation build setup errors as strings
we will soon not have "proper" lix exceptions to report back any more.

Change-Id: I5061f289bcae64bf26d29cc9d0ec9af61315084e
2026-02-03 00:27:40 +01:00
eldritch horrors e575a3a930 libstore: reformat DarwinLocalDerivationGoal::execBuilder
it'll make diffing later a little bit easier.

Change-Id: I57b62fa0977648cf6948a07c1a103b0e1d6b6624
2026-02-03 00:27:40 +01:00
eldritch horrors 3d77ee8d94 libstore: move macos sandbox config to capnp
Change-Id: I0bc7c60329e0f24e15649c526386ba2466314b18
2026-02-02 19:30:52 +00:00
eldritch horrors 3896e265da libstore: move linux sandbox config to capnp
Change-Id: I3394353ed3f738976132c00973231af70dcffad4
2026-02-02 18:26:57 +01:00
eldritch horrors 0cc9d01ad0 libstore: move tmpDirInSandbox, enable-core-dumps, buildUser into capnp
since we're using tmpDirInSandbox as the working directory for the new
process we also rename it accordingly. buildUser likewise turns into a
different Credentials type because exposing user lock state seems odd.

Change-Id: Id4a1a6eb733f774c893f373b91c2a271a4b84185
2026-02-02 18:26:57 +01:00
eldritch horrors ac7a622b38 libstore: move builder/args/envs to capnp build request struct
Change-Id: If558e5b5ba9b195e31927ca5b5d0c2be743ce3f2
2026-02-02 18:26:56 +01:00
eldritch horrors ced825791a libstore: add capnp build request parameter struct to builders
there's nothing in here yet, we'll add that piece by piece.

Change-Id: Ib276d9e8281bb08013197db0f2bbfd8eec76b5ce
2026-02-02 18:26:56 +01:00
eldritch horrors f09ed729b5 libstore: generate darwin sandbox profile outside of sandbox process
Change-Id: I1a82e1dfa3709e1513d7acbdff50dc594cbc2323
2026-02-02 14:20:54 +00:00
eldritch horrors 9a31cc7da0 libutil, libstore: move closeExtraFDs to derivation goal
it's only used there.

Change-Id: I61ee47d37214c59c073cc9ed671ac1c82430227c
2026-02-02 14:20:54 +00:00
eldritch horrors 52590089df libutil, libstore: move bindPath to libstore linux platform bits
it's only used for linux sandbox setup, and can't be used elsewhere anyway.

Change-Id: I3560e141e5250cf9e72dc1576f87384a8e01f446
2026-02-02 14:20:54 +00:00
eldritch horrors dd54f45bc7 libstore: fix linux sandbox parent death signal handling
setting the signal is not enough, we must also check that the process we
expect to be parent to actually *is* our parent, not another process (eg
init if the daemon exited). we also have to set the death signal *after*
all set[ug]id calls, otherwise it will be cleared again by such changes.

Change-Id: I4e8c9102ea407576ed85b3203c8bb9bfb56762de
2026-02-02 14:20:54 +00:00
eldritch horrors 61e57329eb libstore: inline setupSyscallFilter
it's only used this once, and it accesses a (cached) global variable for
the filter. we want to move all sandbox setup state into a single object
soon, moving filter setup will make it a little bit easier to deal with.

Change-Id: I234d92d5ca044a16644b70bd303bfb7956c120f0
2026-02-02 14:20:54 +00:00
eldritch horrors ab6d8f513b libstore: always unmask all signals when launching build processes
when starting builders we want the inner processes to run with a blank
slate. if some signals are masked for any reason the builder processes
may attempt to send signals to each other that are never delivered; we
avoid this by unmasking all singals. since every build tree also has a
session and process group of its own we are not in danger of sending a
signal to a builder by accident from any source, so unmasking is okay.

Change-Id: I90720ed2bd44502ffb6d2bb848c05369809abeba
2026-02-02 14:20:54 +00:00
eldritch horrors 9ad8136825 libutil: always restore mounts from restoreProcessContext
daemons only need to restore the signal mask anyway, nothing else.

Change-Id: Id2a91f33ccf68f4d1af1bc526973a4bee066ff0b
2026-02-02 14:20:54 +00:00
eldritch horrors b908f9135c *: only increase stack size if evaluations are done
we don't need to mess with this rlimit for e.g. the daemon. increasing
the limit later should always be safe since we don't allocate (or map)
much before constructing the eval states that ultimately fill our heap
and could thus make stack expansion impossible after some time passes.

Change-Id: Ieafda537fbc99a6a7f83a093a981e7df947da437
2026-02-02 14:20:54 +00:00
eldritch horrors c20aaf6ca7 libstore: inline commonExecveingChildInit into single user
Change-Id: Ia389ec8c5e375b8386949c5fb031a52f27e76d37
2026-02-02 14:20:54 +00:00
eldritch horrors 1d227cbe07 libstore: extract capability raising into raiseAmbientCaps
this will be needed in other places in the future, and splitting it out
also clarifies the surrounding code. the keep-caps dance launchPasta is
doing doesn't have to be moved since it is only needed to allow setuid.

Change-Id: I6baaa138c2b1bca9626971ed3266c1a971a63acc
2026-02-02 14:20:54 +00:00
eldritch horrors 576ff2f598 update nixpkgs, pre-commit-hooks
the devshell no longer worked for us due to the recent deprecations :D
let's update pre-commit too because while it doesn't fail it does warn

Change-Id: Ic2060c82e4e97bb7a96cebd29097abefabdfe733
2026-02-02 15:08:49 +01:00
rootile 64d610fddc chore: reflect account migration
Change-Id: Iee327470932e58707473e876982cf22b392c2efa
2026-01-31 20:59:02 +00:00
piegames 16bd27fb78 deprecated-features/rec-set-overrides: Upgrade to hard error
Change-Id: Ifec24ee905e821058a7259be00460bf2988429d8
2026-01-31 21:58:33 +01:00
piegames c76632e17d deprecated-features/ancient-let: Upgrade to hard error
Change-Id: Ib856a665a8175a880b3ff52dde9d34769f24713b
2026-01-31 21:58:33 +01:00
piegames adfbc836c0 libexpr: Expand shadow-internal-symbols deprecated features to code null, true and false
Change-Id: If20efb9afced8665ba5c3b45cd09542e398867aa
2026-01-31 21:58:33 +01:00
eldritch horrors 1042d26c31 libstore: remove impersonate-linux-26 setting
it's ancient, it does not do what it was added for (improving
determinism), and it probably hasn't been needed for anything
in a very long time. we can probably get away with killing it

Change-Id: I66f5c841964d9ad62726cb2dae8d6fc42095399f
2026-01-31 20:05:45 +00:00
eldritch horrors cf9735f82e libstore: don't modify pathsInSandbox while mounting stuff
mostly because this will make it easier to change the data source for
them, and especially to change to data source to something immutable.

Change-Id: Ic5f1a55d02d4c2cc928c3f8b308d07167efb467b
2026-01-31 20:05:45 +00:00
eldritch horrors f5a2251966 libstore: move rewriteResolvConf to LinuxLocalDerivationGoal
it's only used there.

Change-Id: I9e267ce8b178ef3996d55b5980475a7e914ba0aa
2026-01-31 20:05:45 +00:00
eldritch horrors b41af64d1e libstore: compile linux syscall filter in prepareSandbox
this is literally part of preparing the sandbox.

Change-Id: Ic1a574bdaa68b5f39326b91c10198b774f7b2f7e
2026-01-31 20:05:45 +00:00
eldritch horrors 0d4baa5528 libstore: don't keep tempdirs open after we need them
closing them as soon as we're done ensure that the fd table doesn't
balloon in size, which in turn lets us build larger graphs. it also
makes forking processes cheaper due to less fd table copy overhead.

Change-Id: I233d1b7358ffe1b05680f845cd99de38b179f449
2026-01-31 20:05:45 +00:00
piegamesandCommentator2.0 7e68f93ed7 libexpr: Require whitespace between certain tokens
Fixes #135, #136

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: Ia1880633c1ee3b9242487fbc30b6d781d88987fb
2026-01-31 20:44:34 +01:00
Commentator2.0androotile 98d0215ca2 tests/functional2: migrate substitute-truncated-nar.sh
Change-Id: I7225930ed6ec999b38bde8bcd23e7203fd4be1b6
2026-01-31 18:09:24 +01:00
piegamesandCommentator2.0 17f1bcfd2c libexpr: Deprecate or in non-keyword positions
Test cases courtesy of rhenrdic

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: Id8df684ddd00d07b49e1c9e68bf41ee6c0e6887c
2026-01-31 15:32:28 +01:00
piegamesandCommentator2.0 af166146ff nix::parser::State::addAttr: Forbid dynamic attrs in recursive attrsets
Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: I92656b3b27f551bf286abc0d680c4a1c542337d7
2026-01-31 15:32:27 +01:00
piegamesandCommentator2.0 51dcc6ac0d nix::parser::State::addAttr: Forbid mixed-rec merges
Fixes #350, https://github.com/NixOS/nix/issues/9020

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: If78d144dc35839b7668c0e0ad796252fcfc42ea0
2026-01-31 15:32:27 +01:00
piegamesandCommentator2.0 cbaa172775 libexpr: Warn on floating point literals without leading or trailing zero
Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: I0b58531ad091b22dc59d5717f5d1c8c814b4d2ea
2026-01-31 15:32:27 +01:00
piegamesandCommentator2.0 56dee9186f libexpr: Warn on incorrect string escapes
In Nixpkgs, there are several strings like "\d\.\d" which attempt to be
a regex but are just literally "d.d". The escaping rules are silly and
we should warn our users about that.

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: I779b0757358fc9adc34dc140e1670b83abc93b67
2026-01-31 15:32:27 +01:00
piegamesandCommentator2.0 f1fbd1d095 libexpr: Warn on incorrect string usage
The indentation stripping semantics of strings are fairly bad and have a
few gotchas where they behave unintuitively. But the good news is, that
these cases are easy to catch and can be avoided.
This commit adds a warning in the parser when such strings are detected.

Unfortunately Nixpkgs uses this kind of a lot, so we won't be able to
actually enable this warning for a while to come.

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>
Change-Id: I3b3b68c2eee4cd70959d3f4ca643cb6caf3a2217
2026-01-31 15:32:27 +01:00
piegames 4e1c216fd3 libexpr: Fix rec-set-overrides detection
Unfortunately, the previous code only detected superficial __overrides
and did not catch cases like `rec { __overrides.foo = 2; }`.

Change-Id: Ic38bdef1a6a3bdea91915aef44447f4ecc238259
2026-01-31 15:32:27 +01:00
piegames 9ad0ace8c0 deprecated-features: Rewrite feature descriptions
Changed the writing style of the descriptions, expanded with more
examples and rationale, and added the new timline metadata in the
frontmatter.

Change-Id: I218389e3504fc21f4eb45a927e77a41a1a70d4f5
2026-01-31 15:32:27 +01:00
piegames f289462c59 eval: Don't expose partially constructed sets
This turns several instances of unsoundness into runtime infinite
recursion errors

Fixes https://github.com/NixOS/nix/issues/7012,
https://github.com/NixOS/nix/issues/3241

Change-Id: Id8d352c5a78ef08d8913f07fe83f55c875684714
2026-01-31 15:32:27 +01:00
rootileandpiegames 7bd3202175 lix/code-generation: add timeline information to deprecated features
Change-Id: I5d5cf28c62cea116cb01bf433eb69a8c859809a8
2026-01-31 15:32:27 +01:00
Commentator2.0andpiegames 8c857790a3 lix/code-generation: clean up code properly
The code within the code-generation had tons of code-duplicates and was
overall quite meh to read, understand and expand.

This commit refactors the code-generation to make it more readable and
comprehensible, while also unifying its usage a bit more

Change-Id: I3a5df8b7d8d9b6c76e02ef47dfb151c7dab7d0ab
2026-01-31 15:32:27 +01:00
eldritch horrors 279926d215 meson: merge libs
lix, where modularity is made up and the patterns don't matter. merging
everything to match actual behavior of the system makes using rust much
easier because we'll have only *one* library to link, not half a dozen.

Change-Id: Ie3cb1db659798511128716402497697320bd0484
2026-01-30 17:29:51 +00:00
eldritch horrors 2e0cc67ec8 libstore: start pasta much earlier
starting pasta as soon as we have all namespaces it must be in available
lets it start up while we finish creating the sandbox. this may speed up
sandbox launches somewhat, but likely not enough to show up in practice.

Change-Id: Id6724cbdc48b99284cd7ba7b56c98829d74557c5
2026-01-30 00:29:27 +00:00
eldritch horrors a2500db977 libstore: remove unnecessary linux-specific RunOptions
Change-Id: I07303c2aea78cf9f17b89b5cea922271ce26f029
2026-01-30 00:29:27 +00:00
eldritch horrors d43c6dd100 libstore: use raw syscall for inVFork setgroups
Change-Id: Ia656d2697b883d2b058984787556915b34f44211
2026-01-30 00:29:27 +00:00
eldritch horrors ab4f8718f9 libstore: start pasta from a vfork child
mostly as a prototype for other process launching optimizations, but
also to move linux-only bits out of runProgram2. we want to stop the
fork+exec dance we do now and migrate to posix_spawn, but linux will
always need an amount special handling for launching build children.

Change-Id: Ied55dc0de95c05b52aaca923be2e3c1d101f47e0
2026-01-30 00:29:05 +00:00
eldritch horrors b6c8f412a2 libstore: generalize linux vfork infra to also allow exec'ing
we'll use this to run programs from a vforked child instead of using
runProgram. ideally we would like to have runProgram be as efficient
as possible, but our mount namespace handling makes this harder than
is worth dealing with right now. the linux derivation goal is a good
place to prototype functionality like this, especially since we need
fine control over credentials and file descriptor tables of children

Change-Id: Ibc356613ae10b06ea81de9575611948f5ee353b6
2026-01-29 19:00:56 +01:00
eldritch horrors 05fed0687d libstore: add processes to cgroups earlier
this was racy previously; a builder may have spawned processes before we
added it to a cgroup. these processes would not be registered correctly.

Change-Id: If60a64a798ee806d5701590a83d1015f55d7b867
2026-01-28 18:49:02 +01:00
eldritch horrors b23bbd5b19 libstore: fix personality setting for unsandboxed linux builds
oops. this was supposed to always happen on function exit.

Change-Id: I25465b4248c33389ca7e70b2a0b52dcc10d86a38
2026-01-28 18:49:02 +01:00
eldritch horrors 56988d8605 libstore: use vfork for linux sandbox launch wrappers
this halves sandbox launch overhead, reducing the build time for 3000
trivial runCommand derivations on our machine from 80 seconds to 44s.
as a nice side effect we also get better error message propagation in
some cases, most notably setgroups failing when run in lix sandboxes.

Change-Id: Ia7c50a844915d9b8a20475b90b2d0179fd2fff34
2026-01-28 15:01:13 +00:00
eldritch horrors bf3d4e8721 libstore: simplify user/net namespace setup
creating user namespaces early means we don't need pipes to signal that
a namespace has been created and set up. we'll also create the netns at
the same time because they're privilege-bound to the userns, and having
both available will let us launch pasta earlier to have it ready sooner

Change-Id: Ie66fe2ab7f50a520fb81dd90944384e168d94476
2026-01-28 15:00:55 +00:00
eldritch horrors c9fe3befc1 libstore: add vfork infra to linux platform bits
vfork can be a lot faster than fork on linux, and we want to use it.

Change-Id: If1665d3c49e525f2722b1e040cd7058f376bd20e
2026-01-28 15:00:43 +00:00
eldritch horrors 7e8f7d0e66 libstore: set up linux sandbox /etc earlier
permissions and ownership will be the same since the sandbox process
will not have changed uid/gid or umask by the time it gets around to
writing these files. all of these files contain some information the
host must provide, be it contents or configuration info of some kind

Change-Id: I0b57cb0699fd29e798ccf330dff99f571f3c0692
2026-01-28 12:41:26 +01:00
eldritch horrors 7d3dde851a libstore: make runPasta a function of LinuxLocalDerivationGoal
this way we can use it anywhere without fear of it being uninitialized.
only the linux platform bit uses this anyway, so we will move it there.

Change-Id: I35e207eec91daa8aa327c4f8b36c0dc8e703a7c4
2026-01-28 12:41:26 +01:00
eldritch horrors bd458f9f89 libstore: make privateNetwork a function of LinuxLocalDerivationGoal
it's only used there, and this avoids using it uninitialized.

Change-Id: I6bd84e3c441dc6750e8ab07822f896136586cd66
2026-01-28 12:41:26 +01:00
Raito Bezarius 57373cba6f nix/daemon: receive supplementary groups on macOS/FreeBSD
`xucred` already contain `cr_ngroups` and `cr_groups`, we just have to
use it properly.

Change-Id: Ic29b4c551f9d93e86e9ed2bef20889d27d5438f4
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-28 08:24:24 +00:00
Raito BezariusandTom Hubrecht c493fb668e nix/daemon: consider supplementary groups during authentication
Two things happens here:

- we consider supplementary groups that are known for authentication,
fixes #968.

- we check supplementary groups if they are our build users group and
throw an error if they are (new behavior).

Nonetheless, we did not remove the ability for `matchUser` to recurse
and check for groups that the user may have but the connection might not
have communicated as part of their groups, i.e. if a process reduces its
list of groups via a call to setgroups, it will still be authorized.
This will come in another commit.

The authorization NixOS test has been extended with a store ping test
running in systemd with DynamicUser=true *AND* a supplementary group in
allowed-users.

Co-authored-by: Tom Hubrecht <github@mail.hubrecht.ovh>
Change-Id: I25b2b8304d66a04651cea523b5585a5d15ceebe8
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-28 08:24:24 +00:00
Raito Bezarius 9e55dd6b8f nix/daemon: receive supplementary groups on Linux
On Linux, SO_PEERGROUPS is an option introduced in 2017, that is, in
Linux 4.13.

Thankfully, Lix targets 5.10+ kernels minimum.

It was chosen to allocate 128 gids by default and ramp up (2x) as needed
rather than allocate a full 65k of integers as it seems wasteful. I bet
the time to the 16 allocations should incur at most an additional
millisecond on a modern system, don't quote me on that though.

This is preparation to enable ability for the daemon to vet based on
supplementary groups.

Related to #968.

Suggested-by: alois31
Suggested-by: eldritch horrors
Change-Id: I26d698327db5d174bf70ca25b0afede132bd9169
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-28 08:24:09 +00:00
Raito Bezarius dbb3edcfea nix/daemon: clean up PeerInfo
Rather than a bunch of booleans, use optional<T> as a way to convey that
the identifier is known or not.

This is preparatory work for SO_PEERGROUP usage.

Change-Id: I0e3ce69e4103f9df5a2161c695bfc650123c1549
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-28 09:20:57 +01:00
eldritch horrors 986191534e libstore: allow config loading without a home dir set
we can already handle this case (by forbidding any ~/... paths in option
values), and since builtin builders are now run via exec we may not have
a home dir set, or even available, for them to resolve. loading a config
file in this situation will fail with an error even if the config is ok.

fixes #1109

Change-Id: I3491b31558871faa34766462747e3c15d1eccc64
2026-01-27 17:13:07 +01:00
eldritch horrors ef8a6cc5f5 libutil: add tryGetHome that doesn't throw on errors
Change-Id: Ib5bcb277e39093b303fe4a66a8903a7c5692f305
2026-01-27 17:13:07 +01:00
Raito Bezarius e083a68a9f libstore/linux: forbid xattrs syscalls
xattrs are revealing some unfortunate brittleness in real world
derivations that are getting -EINVAL errors while executing their test
code.

The reason for this is that Linux checks [1] UID delegations for xattrs
writes.

In the Lix sandbox, except if you enabled a uid-range feature, you have
exactly 3 UIDs: root, nixbld and nobody.

If your test code makes use of UIDs which have not been delegated, you
will receive an EINVAL on your operation. Test code is not resilient
with respect to the number of available UIDs in their namespace.

To avoid further issues for end users who are running into spurious
derivation build failures, we forbid xattrs again for now.

For more information about the plans, please consult or chime in [2].

Fixes #1105. Reopens #838. Fixes #1103.

[1]: https://elixir.bootlin.com/linux/v6.18.6/source/fs/posix_acl.c#L257
[2]: https://zulip.lix.systems/#narrow/channel/9-Store/topic/disablement.20of.20xattrs/with/5295

Change-Id: I864066b34cd8319d2271fac1b179cb4f950d836e
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-26 18:54:51 +00:00
eldritch horrors cfabc37828 libstore: add unix:// uri protocol argument
Change-Id: I7fc27926aa1d89e2190b1deb0252ad33f2b364a5
2026-01-26 18:17:07 +00:00
eldritch horrors bdc220b8ec libstore: allow for multiple daemon sockets with preference
this will let us configure more than one socket to connect/bind to,
which in turn lets us use posix acls on sockets for access control.
we will also need something like this for the final rpc transition.

Change-Id: I9c39f14906e9bf809055ab5c94bf687745b4f69e
2026-01-26 18:17:07 +00:00
eldritch horrors f4458b8e46 libstore: simplify netrc, cafile loading for builtin builders
Change-Id: I8370a1434729c7ff2e44ddbaf173d7068e8ace9f
2026-01-25 19:47:24 +01:00
eldritch horrors 99d674b785 libstore: despecialize sandbox launching
now that builtin builders are regular executables we no longer need to
treat them specially during sandbox launch itself, only while we build
the command line and environment for the sandboxed process. we are not
far from being able to extract platform-dependent sandbox launch code,
ideally moving all of it into (much more replaceable) libexec helpers.

Change-Id: I9b7041314683c56cd70eec9b1b4eae6de228883f
2026-01-25 19:43:13 +01:00
eldritch horrors 049c7b3369 libstore: move the builtin builders to our new executable
this means that builtinFetchurl runs in a real process now, and thus we
no longer need its workarounds for running in a forked process. forking
dropped the signal handler thread and broke the curl state via sharing,
neither of which happens any more now. we can run fetchurl builtins and
their actions straight from the main thread of our builder now, and the
temporary files and settings overrides we did are now also unnecessary.

Change-Id: I738171bc120ffcd541b7ff1424fed7924c2cdc1d
2026-01-25 19:31:38 +01:00
eldritch horrors 58c3ee4c8e builtin-builder: remove unescapeNul that snuck back in
fuck

Change-Id: I5d203fc36c4a2eb2aefde9208d6cefd3619cdf03
2026-01-25 19:30:10 +01:00
eldritch horrors 5abf26a19f add a builtin-builder command for ... builtin builders
this will let us migrate the fork+do_stuff combo of builtin builders we
have today to fork+exec of this new command. we use a subcommand rather
than a simple libexec helper because we would like to avoid linking all
of lix into the simple libexec helpers if possible. this is only hookup
for the builders, none of the buiders are migrated here to ease review.

Change-Id: I9358f1f3fee6ca640c81a7bd865128ae0d0e35a5
2026-01-25 17:26:39 +00:00
eldritch horrors c50a3a426f libutil: add simple NUL escaping/unescaping functions
Change-Id: Ia4cc7b8f1058439f312066422eebfaff1c2c0c6c
2026-01-25 17:29:32 +01:00
eldritch horrors ed6a1e58ea libstore: don't call builtin builders with derivations
call them with their individual parameters instead. this will make it
much easier to turn them into executables we can exec in the sandbox.

Change-Id: Ib49cf44715b2a480fecadabd21216c69cd730ef5
2026-01-25 15:34:59 +01:00
eldritch horrors 21e8347bb6 libstore: make netrc/cafile child args plain strings again
not having the optionals set when the builder runs (e.g. because FOD
hashes were not configured correctly) could cause assertion failures
in the builder process. while this should usually not happen we *do*
want to print a useful error message here instead of a crash report.

Change-Id: I81fb1d45fcbf660d0d9a7f0c0a12c38379ecd4c6
2026-01-25 15:34:59 +01:00
rootile 2f7644c420 tests/functional2: fix wrong usage of env var
Change-Id: I37580e0d74e26e064261c98a1162fbd9e23a9d46
2026-01-23 16:15:55 +01:00
Rebecca Turnerandrootile cb34b56fea tests/functional2: Fix Python LSP by adjusting imports
See: cl/4840

When importing Python modules, we include `functional2` in the module
path, like this:

    from functional2.testlib.fixtures.env import ManagedEnv

This means that python expects to see a file like
`functional2/testlib/fixtures/env.py`. We run `pytest` from `tests/` in
the `justfile` and have `tests/functional2/__init__.py` so `pytest` in
`meson` is able to find these imports.

However, language servers generally consider the `pyproject.toml` to be
the project root, so (e.g.) `pyright` is unable to follow any of the
`functional2` imports, leading to lots of spurious errors.

In cl/4840 I moved `tests/functional2/pyproject.toml` to
`tests/pyproject.toml`, which worked but was considered aesthetically
unappealing.

This diff is much larger but it's a more elegant solution.

Change-Id: I2983c7b87f88f59a4e3521451a9f5acd6a6a6964
2026-01-23 15:06:51 +01:00
eldritch horrors 0453be06b6 libutil: remove unused RunOptions::{chdir, createSession}
Change-Id: Ib2b9f5c094233661a01ad8cea30a44e11931c941
2026-01-22 16:59:39 +01:00
eldritch horrors b5a25f0fb6 libstore: move build hook launching to libexec helper
like diff hooks before the build hooks also use runProgram features that
aren't present in posix_spawn. just like diff hooks we do not expect the
build hook processes to be so fast that launch overhead matters somehow.

Change-Id: If3c33dbd7d2ac20c95886e06d24feda312946c78
2026-01-22 16:59:37 +01:00
eldritch horrors a7f4a675b6 libutil: remove Pid::setSeparatePG
use a wrapper type instead. whether something should be treated as a
single process or a group is a type decision more than a runtime one

Change-Id: I966e998c19e74be64ddd72ab11af809d001f61b5
2026-01-22 16:57:26 +01:00
eldritch horrors 0b03ae1a13 libutil: remove unused Pid::{killSignal, setKillSignal}
Change-Id: Ic7cceef2d82a98cf8fe23260603b1262c097cad4
2026-01-22 15:23:38 +00:00
eldritch horrors 5351518c75 libstore: add a diff hook helper libexec binary
diff hooks use uid/gid switch functionality that is otherwise only
needed for linux sandbox setup and unsupported by posix_spawn. not
doing these switches inside lix core code may let us move to using
posix_spawn for most process launching in the future, and for diff
hooks the added overhead of a wrapper program really does not hurt
at all. diff hooks are expected to be expensive in terms of output
size, process launch overhead is not likely to even be noticeable.

Change-Id: Ifa4b3eedef237632db3eb88d10e6469acae01f9e
2026-01-22 15:23:38 +00:00
eldritch horrors d7b0d322f7 libstore: make diff-hooks work for non-root users
it's kind of weird to not allow diff-hooks in single user mode unless
that user is root. maybe that's why we have no tests for them? we can
at least add a test that diff hooks are run at all when we expect it.

Change-Id: I54d623b5416acda1c205cc062b0f3a33c9f4aaa7
2026-01-22 15:23:38 +00:00
eldritch horrors 36168de584 libutil: remove {Process,Run}Options::dieWithParent
nothing except the linux sandbox actually *needs* this for correctness.
the linux sandbox only uses it to ensure that builder uids are freed up
when the sandbox is torn down, and even *then* it only works as we need
it to with PID namespaces enabled since the parent death signals is not
inherited across fork, but when pid1 of a pid namespace dies the kernel
also kills all namespace members. in all other cases this flag does not
help us that much because it actively prevents child processes cleaning
up after themselves, possibly leaving more trash around than otherwise.

Change-Id: I9ae0a9e91833a91d1011375dda402ac6c0a7ef6f
2026-01-22 15:23:38 +00:00
Raito BezariusandNiko Klanecek 728d2bfee7 contrib/plugins: add mTLS binary cache store plugin
Adds an example plugin implementing an mTLS-enabled binary cache store
(https+mtls:// scheme) using client certificates for authentication.

Darwin fix: don't link liblix* into plugins (host resolves symbols at
runtime via dynamic_lookup). Explicitly link curl so it binds to
Nix-store libcurl, not /usr/lib/libcurl. This prevents the plugin's
curl_easy_setopt calls from operating on the wrong libcurl instance.

Test portability: BSD sed -i wrapper, OpenSSL -sha256 for cert signing,
redirect test server output to log file.

Change-Id: I652b987d3ac45e31df50ff4ba1f523294438c2b6
2026-01-21 22:50:35 +00:00
eldritch horrors 7068cbf010 libstore: extract env and args rewriting from child
this really doesn't have to be here, it doesn't help very much. doing it
in the parent is cheap enough to not care and sandbox setup is not async
yet *anyway*, so we would not even notice if the old way was any faster.

Change-Id: I5a3a99af0fa5928e9a42f9c6589d98ff38b8c775
2026-01-21 15:59:30 +01:00
eldritch horrors 6da0389d0f libstore: move netrc/ca init outside of the build child process
this will make it easier to turn build sandbox processes into helpers.
the point they were at was effectivly unsandboxed except for a few fds
that were redirected by commonExecveingChildInit, which only made logs
of any errors that much harder to convey from the child to the parent.

Change-Id: I67006eb33e1e13311bb8d14e6a0c3d5e6baf0c13
2026-01-21 15:59:30 +01:00
eldritch horrors 5ba9a3961c libstore: move setupSyscallFilter to linux platform bits
setting them that little bit later really doesn't hurt us at all.

Change-Id: I6b50fbe0b58d037de729748cb4f87dd628bd111b
2026-01-21 15:59:30 +01:00
eldritch horrors 95c65ce637 libstore: move setPersonality to linux platform
it doesn't do anything anywhere else, and personality setup is not a
critical operation (all it does is change which arch uname returns).

Change-Id: I39d7fcc4916e6882e49191d2294f9b7ee0dbbcd0
2026-01-21 15:59:30 +01:00
eldritch horrors 6edbef7338 libstore: move some macos-specific bits to platform
Change-Id: I9236ffb8e098d09215067b872b5da5e210557815
2026-01-21 15:59:30 +01:00
eldritch horrors c39488d2a4 libstore: move some linux-specific child setup to platform code
best viewed with --color-moved --color-moved-ws=all

Change-Id: I3738f07fd0b39498abf253967906270dc0b215f4
2026-01-21 15:59:30 +01:00
eldritch horrors 113c6fd618 libstore: reformat bits of LocalDerivationGoal
mathbb overbar sigh

Change-Id: I9b5361ba03ff11a89773f7da2262d38fbf39b7af
2026-01-21 15:59:30 +01:00
eldritch horrors 3937eb9ecc libstore: open builder log pty in parent
there's no need to do it in the fork, we're not changing security
domains before opening the pty anyway. we do change who owns this
pty device, but since we change it via chown we can just *not* do
that before we have an open fd to the pty. in practice this isn't
even necessary because the daemon runs as root, but if we ever do
run the daemon as an unprivileged user we'd need this to be split

Change-Id: I35264ab2954c7ba2c9c24c927366d64acada6772
2026-01-21 15:59:30 +01:00
eldritch horrors 697a86c4af libutil/libstore: move namespace support checks to libexec
this also requires moving namespace support information into Worker and
out of function-scope static variables, otherwise we can't use async IO
for the libexec helper output. we could set the fd to blocking for just
one CL and extract the Worker changes into another that the reverts the
blocking fd usage, but that seems not warranted for the scope of these.

Change-Id: I6996fab1ae74693d50cefb6a6a9c21d61dada1d9
2026-01-20 22:42:53 +00:00
eldritch horrors be27e9696b libutil: move unix chdir+bind/connect to libexec
Change-Id: Ie07ece701454153d3d5c6c34e5613c0d1d5fae03
2026-01-20 22:42:53 +00:00
Justin ! 41a68f206f treewide: print* -> format* for functions not printing
Those functions have been recently refactored to return a formatted
`string` or take an `std::ostream` and only do the formatting have been
renamed to match what they're actually doing.

Change-Id: I3fe32fbe8723c2d93226370b8dd297f16a6a6964
2026-01-20 22:31:59 +00:00
eldritch horrors 761f8ab6eb libutil: fix libexec helper args span calculation
fucking hate C

Change-Id: I678c9eda32911ce7ea5e76c4274b71e45e7f3790
2026-01-20 19:16:00 +01:00
eldritch horrors 8039d69818 libutil: move killUser innards to libexec
Change-Id: Iddd3099c31c91b18c946f7ba2db79c221e7686fe
2026-01-20 16:43:23 +01:00
eldritch horrors d9187b4ee0 libmain: run pagers with a libexec helper
this is mostly a test and example for the libexec helper infrastructure,
but it also lets us simplify pager launching until we we can more easily
handle executable-not-found errors the launch fallbacks would cause when
using runProgram2 instead of fork. ideally we'd use `posix_spawn` later.

fixes #1104

Change-Id: Ia33cc12e8a9d60ffad6f5c055bb1b8b596810e64
2026-01-20 14:02:12 +00:00
eldritch horrors 9921615410 libutil: add libexec helper infrastructure
the new libexec directory is not available as a setting like other
directories (e.g. binDir) are since we consider libexec helpers to
be very internal. repointing them is like repointing a .so file we
dynamically link to; it can work, but needs much more preparation.

Change-Id: I40e64be0b32276f2864c0f2eb0b998d4c8ce7c88
2026-01-20 13:53:44 +00:00
eldritch horrors 9b334faa81 meson: use escaping functions for config.h defines
Change-Id: If7677d8040e0da0b72fc9498f2c920a0f1bb25f7
2026-01-20 13:53:44 +00:00
Pol Dellaiera 7009944370 chore: replace edolstra/flake-compat with lix-project/flake-compat
Change-Id: Ia7409ecb2f61d1ff6c8c4031025226e8549b22b6
2026-01-20 12:31:41 +00:00
Commentator2.0 eca222c7ca tests/functional2: migrate dump-db.sh
Change-Id: Ife8ff62add37f50867f55a5eaa26f7a68fad1c78
2026-01-20 10:08:36 +00:00
Commentator2.0 cdd8508bc9 tests/functional2: Provide a shortcut to clear a store
Change-Id: Ic28fb8a81ef95a1b83fa8099f5337e89f630f8e1
2026-01-20 10:08:14 +00:00
eldritch horrors d5bdc1c240 tests: remove outdated comment in test-session
we *are* using runProgram2, just not its builtin stdout stream.

Change-Id: I1766a9e443f539979f1f780a6d32294d103fb10f
2026-01-19 20:31:30 +00:00
eldritch horrors e2991e1245 libstore: use runProgram2 to launch build hooks
we don't need the full sandbox setup helpers for this: mount namespaces
do not need to be kept, loggers are not needed, and redirections can be
done by runProgram2. once the build hook is removed we will not run the
communication bits from a different process anyway, this prepares that.

Change-Id: I95d28f7c2c25e43ccd82b448d270403ce4f28852
2026-01-19 19:46:29 +00:00
eldritch horrors f2432be62d libstore: use runProgram2 for ssh connections
we do not need explict redirection management now, and dieWithParent
doesn't need an override either. we'd much prefer to kill ssh if the
process in charge exits; even ssh multiplexers are not fazed by this

Change-Id: I81e28b7605df73c887878ea4716228c7ad0f5c6f
2026-01-19 19:45:28 +00:00
eldritch horrors 39869c8b35 libutil: add setsid support to runProgram2
Change-Id: I9c023f2497cab12f1a7bfafd0baa82ffb5912d3e
2026-01-19 19:28:46 +01:00
eldritch horrors 6c7a80e449 libutil: reformat runProgram2
yeah. sorry about that.

Change-Id: I33d55d0014a53346a5c0ce07091a086374172b30
2026-01-19 19:28:46 +01:00
eldritch horrors a28dc8f77f tests: use runProgram2 for repl tests
the redirections the tests did were once not possible with runProgram2,
but they have been for a while now. we should use them instead of fork.

Change-Id: Ia422c8941ed04a9403dee68bfe938d68952253da
2026-01-19 19:28:46 +01:00
eldritch horrors 1719d60531 libutil: return pid object from RunningProgram::release
returning the pid as a pid_t instead of as a Pid raii wrapper is only
convenient for daemon use (where it'll eventually go away). using the
released pid correctly in other places is harder without the wrapper.

Change-Id: Ib42a2f357d2f0849beabd015b321bfff31334eda
2026-01-19 19:28:46 +01:00
Tom Hubrecht 7d764670c8 nix/path-info: Don't print missing paths as no fetch can be done
Fixes #323

Let's now all go an a little rant about spaghetti code...

The result of this code is that the missing paths are not printed
anymore. The basic issue was that the parent class of this command is
StorePathsCommand, which inherits from BuiltPathsCommand, and their
purpose is to work on path that are clearly in the store, building them
if needed (and ofc telling the user about what's missing), the sequance
of calls is:

- BuiltPathsCommand::run(ref<Store> store, Installables && installables)
- Installable::toBuiltPaths( *getEvaluator()->begin(aio()),
getEvalStore(), store, realiseMode, operateOn, installables);
  where operateOn is Output by default, realiseMode is Derivation, so
the only thing that can be built are the derivations for the required
installables
- Installable::build(state, evalStore, store, mode, installables)
- Installable::build2(state, evalStore, store, mode, installables,
bMode)

And that final call has the following:

```
    switch (mode) {

    case Realise::Nothing:
    case Realise::Derivation:
        state.aio.blockOn(printMissing(store, pathsToBuild, lvlError));
```

So there were two options, hack a new spaghetti in the existing
spaghetti code, or condense all those calls that are actually useless in
our case because they mostly transform a list of installables into a map
from installables to their BuiltPath which are then iterated to retrieve
the final outputs, whereas it is possible to directly get the required
paths in a much more efficient manner and without printing unrequired
stuff through a multitude of intertwined function calls by simply
replacing one method that was previously inherited from the grandparent
class

Change-Id: I1d2baaef5a099cd98b63b5346f2613914c6cd2ac
2026-01-18 20:25:39 +00:00
eldritch horrors 54180f4c35 libmain: remove RunPager
it's no longer needed now that withPager exists. also fix a
logger-never-resumed bug that never showed up in the world.

Change-Id: I7311a50896f5291364320ec4c88506dc3bb11d4c
2026-01-18 19:17:14 +00:00
eldritch horrors a7bc1be03f commands: RunPager RAII -> withPager wrapper
RunPager is weird and confusing in that it replaces what stdout *is*
depending on environmental conditions. this has not caused problems,
but it's easy to imagine situations in which it would (eg if the stl
decided to capture the stdout fd by duplicating it). using a wrapper
for this also makes clear *what* actually goes into the pager; while
the previous contract was semi-reasonable it was also very implicit,
and with the proliferation of functions we had that printed directly
to stdout it would have been easy to send wrong output to the pager.

using a wrapper also makes process management much easier because we
do not have to rely on destructors to always produce correct output.

Change-Id: Ifd3760940af1ec719fe856158c913cbb9a5bf270
2026-01-18 19:17:11 +00:00
eldritch horrors 46b86ffa49 nix-store, nix-env: reformat some bits
this will make the next commit a lot more readable.

Change-Id: I74ffad9b9f635c35d51861982558a5e020ab4687
2026-01-18 19:17:09 +00:00
eldritch horrors efd8e7cb8d nix-env: don't print to stdout from printTable
return a string instead, and write that to stdout explicitly.

Change-Id: I4a8da8ad860994f4ec05997fb226041e4da302ea
2026-01-18 19:17:06 +00:00
eldritch horrors 3194e3b6f4 nix-store: don't print to stdout from printTree
print into a provided stream instead.

Change-Id: I52495154163e40d05b6897aa129eb9b3d81348dc
2026-01-18 19:17:04 +00:00
eldritch horrors 98cb3014e8 legacycmd: don't print to stdout from printDotGraph
return a string instead, and write that to stdout explicitly.

Change-Id: I21e7a1eb22f2772e31b754823f64f941be080c56
2026-01-18 19:16:45 +00:00
eldritch horrors 49c698cf7f legacycmd: don't print to stdout from printGraphML
return a string instead, and write that to stdout explicitly.

Change-Id: Ia2d2019064da16fd35630217c445b4bcc4cdf2c2
2026-01-18 19:16:39 +00:00
eldritch horrors 7be922b3c8 libutil: remove unused blockInt
this has been unused since ab3ce1cc13,
which is now almost ten years ago. surely it was just forgotten then

Change-Id: Ib93b52d4ce5f19629432c5f91ff426582c57f99b
2026-01-18 19:16:33 +00:00
eldritch horrors 8b114520a2 libstore: make Pool::get fully cancel-safe
cancelling a get() promise could leave the pool with allegedly in use
resource handles that do not actually exist. this would cause asserts
in ~Pool to fire (and crash the entire program due to bad accounting)

probably fixes #1041

Change-Id: Ic61ab9b658f02f71e8be7577b8a1115600846f86
2026-01-18 17:22:41 +00:00
eldritch horrors 48d5e9f07d meson: remove prelinking
the issues it was solving are fixed now :)

Change-Id: I4f38d3ada22f454b57ea8245eadede0500e29451
2026-01-18 15:04:22 +00:00
eldritch horrors cef9572c24 meson: use combined library as dependency for executables
Change-Id: I1b6be3edff83c24d1c3ba3f7b4bfeb0e240039bb
2026-01-16 16:52:03 +00:00
eldritch horrors dbdc3ee28c meson: unify pkgconfig files
merge all pkgconfig-found libraries into a single one and redirect all
existing lib files to the merged variant. the clean separation between
libraries is largely fictional anyway because the main config block is
in libstore and cannot reasonably be moved out, or because libutil has
assumptions built into its behavior that libmain later establishes, or
because libexpr messes with global boehmgc configuration. nearly every
kind of layering violation imaginable can be found *some*where in lix,
and not pretending that this is not the case will let us clean up some
of them. this will also allow us to merge these libraries at the meson
level which is itself necessary to make rust code easier to integrate.

Change-Id: I172f8a08d5d90ded0a0a99fd9e0fa5d804db00a7
2026-01-15 21:50:40 +00:00
Raito Bezariusandeldritch horrors 62519f8d83 libstore/local-store: remove xattrs all the time
xattrs scrubbing was gated behind Linux platforms, but Lix can safely
assume that POSIX APIs are available.

macOS implements these APIs modulo some creative ideas.

Fixes #1008.

Change-Id: I1566df4923bf24092d3fd32ccf6a96e4256e87b2
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-15 15:53:38 +00:00
Raito Bezariusandeldritch horrors b6d5e3f05a libstore/platform/linux: allow xattrs in the sandbox
Fixes #838.

xattrs were historically disabled in 2017, since then, NFS v4.2 gained
support for xattrs and almost all filesystems support xattrs. In
addition, moving the build directory to a xattrs-supporting filesystem
is always an option. Programs may exploit xattrs (including ACLs) during
their build process and testing phase, to better serve these programs,
we will remove this limitation.

Lix will use POSIX ACLs for its UNIX domain sockets in the future and be
one of these programs which will run tests making use of xattrs, while
not writing any xattrs in the derivation outputs themselves.

xattrs are still scrubbed from derivation outputs so it is not possible
to obtain an advantage by writing a security-related xattr to a well
chosen file.

Tests were added to test these scenarios on Linux. Darwin is carefully
excluded because of #1008 and #1090, solving that is welcome. In the
meantime, they are marked xfail.

Change-Id: Ia3255eeb8442e83db4f10dcb5a51cbc368a2550d
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-15 16:40:47 +01:00
Commentator2.0andeldritch horrors 8f474399f5 tests/functional2/nix: only convert path to physical if it isn't already
Change-Id: I88e5079ef01872302aade365444d9b028088ff95
2026-01-15 16:06:59 +01:00
Commentator2.0 042a147aff f2/lang: rename the test functions to be selectable using their expected names
one would expect the lang tests to be selectable (using `-k`) using
`eval_okay` `eval_fail` etc though this was not the case so far.

This commit renames the functions to reflect the expected names

Change-Id: I4cd340c093d774feeb4d96820d28e49c665b159f
2026-01-15 15:30:34 +01:00
eldritch horrors 60dec3eeed meson: don't install repl-overlays.nix header
it's only included in a single .cc file.

Change-Id: If8ed9b1043e40ac070776470a5b49a44d181b793
2026-01-15 14:09:17 +00:00
eldritch horrors 9183c5b182 meson: move cpp_args up one level
these defines may apply to any part of lix, not just libstore.

Change-Id: Ic75098a7aab01b101f22d9c7d94ad9c5db45ab88
2026-01-15 13:55:18 +00:00
Raito Bezarius 40b5f53755 package: pass our own lix to perl-bindings
I don't know how this was missed or no one really complained about it,
but perl-bindings was using CppNix if nix was not overlaid to our own
Lix.

If you overlay Lix manually, the resulting Lix's perl-bindings cannot
really refer to Lix itself, therefore, it's CppNix.

Change-Id: Ie5ce95564cb7fb5444acbea6124619c5121e1576
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-15 11:54:20 +00:00
Commentator2.0 455724d9dc tests/functional2: rename binary cache directory for easier debugging which (cache) cache is being used
Change-Id: Id5a446422a8e1535ada723115bb2d8a10b0f2b8a
2026-01-15 11:37:02 +00:00
eldritch horrors 63b0a01d75 *: remove GlobalConfig static initializers
Change-Id: I23f8d24eb586fb4756e60a8bd5b76966a9febd31
2026-01-14 22:43:29 +00:00
eldritch horrors 8285288540 libexpr: fix app chain extension
during the value rewrite we accidentally broke extension of incomplete
primop application. this only shows up when binding on incomplete call
to a primop to a name, binding an incomplete call to *that* to another
name, and then finally calling the second binding with enough args for
a complete primop application. since this only shows up when calling a
primop with three or more args it took a while to surface. we have few
builtins that match this: foldl', replaceStrings, and substring. these
are not used incompletely in this manner very often, so this lingered.

fixes #1102

Change-Id: I218dffc14ae876efc86a86c7eb6c895e2405201c
2026-01-14 22:05:16 +00:00
eldritch horrors 6cc2ef7c6d libexpr: remove RegisterPrimOp static initializer helper
Change-Id: I0cc6d54fca26c66b13f930303086b08b2afb4d54
2026-01-14 16:22:08 +00:00
eldritch horrors 14de5fa627 *: fix non-local-dir includes
these ended up referring to different directories and would break during
source reorganization (or even just including them in different places).

Change-Id: I91e8db04e3d3565efd5920982ed5bc59d2c27058
2026-01-14 16:22:08 +00:00
eldritch horrors e0d6271fc1 libstore: fix incorrect docs for plugin-files
RegisterCommand was renamed in b30556f8f1
and de-static-ified in 4d9fe67430. adding
new settings was never possible with static instances since settings do
need an existing Config instance during construction; GlobalConfig must
be used to add settings. it is not possible to change existing configs.

Change-Id: I26af8abc375ba5883fce060ffefc710d6dfbca4c
2026-01-14 16:22:08 +00:00
K900 543bc5cf6b package: more specific warning conditions
Avoids warning spam if overridden with nixos-unstable as an input.

Change-Id: I7cc4da757371c582366bc13adcbce742e312b5c7
2026-01-14 18:09:13 +03:00
Alois Wohlschlager 58ffd67704 packaging: adjust pkg-config files after the rust-monocrate changes
Since lix-doc is no longer a separate library, the pkg-config files were broken
for static builds. Adjust them to refer to the new monocrate library instead.

Actually, since the monocrate library is static in all cases it needs to be
linked explicitly even when everything else is linked dynamically. I assume
this only doesn't break the dynamic nix-eval-jobs because it doesn't actually
use anything from it.

Change-Id: Icf29938688f4fa87425ff346a3105ef56a6a6964
2026-01-13 14:22:01 +00:00
Tom Hubrecht f431464382 libutil/hash: Simplify some parts
Use a span representing the underlying hash, this allows comparing based
on those spans. Other minor tweaks to the header file.

Change-Id: Ie05960439e60500109083c06d347d6cdf41bfda8
2026-01-12 15:56:05 +01:00
Raito Bezarius 45783a0435 lix/nix-shell: partial revert shebang mitigations for macOS
I54d04a770b8e78484815db88a8bc88776a6a6964 introduced shebangs in many
places to satisfy macOS needs.

Unfortunately, our rc shell logic is non-trivial and is exploited by
external piece of code such as
https://github.com/chisui/zsh-nix-shell/blob/master/nix-shell.plugin.zsh#L78
to keep shells intact while nix-shell-ing.

We go for a partial revert because there's no obvious fix on the short
term. This reintroduces macOS random bugs during builds until we figure
out a proper fix.

Related discussion:
https://zulip.lix.systems/#narrow/channel/7-Infra/topic/.60macos-builder02.60.20DISABLED/near/4538

Change-Id: I8245f89c10302c2b13da691e441b1c4d5c797e9a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-11 12:50:47 +00:00
Tom Hubrecht e29263b638 libutil/hash: Add default values for Hash::to_string
The sane default is to print in SRI format, and include the hash type

Change-Id: I7efcb5dcfbe56c82dbf1928e2bb35cdd3ff089c6
2026-01-10 18:26:15 +00:00
Tom Hubrecht 16d884bd1f fix(log-format): Apply the required setting with the nix2 cli
Fixes #1099

Change-Id: I658743aae7ec7a7f295c849079166a5940d93e82
2026-01-10 18:12:01 +00:00
Raito Bezarius e9cccd47e2 libstore/build: report better error messages for --check
When --check is ran with no output, this is seen as having *SOME*
invalid outputs, actually, ALL of them are invalid here.

Instead of reporting a confusing error, let's consider ALL of outputs
being invalid to be no output at all available and advise the user to
rerun the build without --check.

If there's *some* (>0) invalid outputs, let's print them exactly to give
a chance to the user to remediate this.

Fixes #485.

Change-Id: I00955ef9ea4f129e2c98d68c73b1e981f90278a0
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-10 12:42:50 +01:00
Commentator2.0 8f9ed687da code-generation: run ruff
Change-Id: I591247ed56f89feba5daf3cbb94211d72a3ba99c
2026-01-10 00:07:33 +00:00
Qyriad 0d3fdbdb54 Exorcise MORE Darwin test demons because functional1 is /awful/
Yeah uh, I don't think `$shell` is ever set in the functional1
environment. Pretty sure this has been expanding to `''` THIS WHOLE
TIME.

Also `SHELL` is `/sbin/nologin` in that builder. idk why so I'm just
passing `shell` unconditionally in functional's `mkDerivation` helper.

Maybe next we should put `set -euo pipefail` into all these test
builders?

Change-Id: Ie5fb85305932c03a901ba84ffcce48f16a6a6964
2026-01-09 18:13:29 +01:00
Qyriad 68a72d2bdf Finally exorcise Darwin Demons causing flakey functional tests
macos-builder02 in particular has been having problems for a while now
that no one could reproduce. We believe we have finally found the cause:
missing shebangs, not just in the tests themselves but *also* in the
inline scripts `nix-shell` itself writes.

Fixes #1042.
I believe this will also fix #1093.

See also: https://github.com/NixOS/nix/pull/14778

Change-Id: I54d04a770b8e78484815db88a8bc88776a6a6964
2026-01-09 12:28:19 +01:00
Qyriad 0800b1588e add release notes for the repl load fixes
Change-Id: I09bc11de2779b6a5f0372a70ba3abb716a6a6964
2026-01-08 18:35:13 +01:00
Raito BezariusandQyriad 6cbbe19b5c libcmd/repl: :load failure clean up loaded files
When `:load`-ing a file that doesn't result in a successful outcome, the
"loaded" file is removed again from the list of loaded files.

This avoids having it be used as part of `:reload` which will probably
not result in a positive outcome.

Instead, the user is expected to retry `:load` before issuing a
`:reload`.

Fixes #50.

Change-Id: I85d025cf39f79e8e02117628bffa20c81917dc3f
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-08 18:35:13 +01:00
Raito BezariusandQyriad f4be01b4be libcmd/repl: do not clear the environment on empty reloads
If `:reload` is used with no file loaded, the environment is completely
cleared.

That's a surprising behavior and one of the root cause behind #50.

Environment clear is only performed if there's files to reload.

Change-Id: Icb014f490a83aaa4d758dbf37822db16d5bb65c1
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-08 18:35:13 +01:00
Raito BezariusandQyriad 0f1208c406 libcmd/repl: reload flake references
Change-Id: I87beaf92c7fa4238452d0c82051b42f0e3ca19a5
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-08 18:35:13 +01:00
Qyriad 7be72ca667 libcmd/repl: refactor to preserve order across :l/:lf
Change-Id: I109bdd21a69aa5e6d7a8cc86350662cd6a6a6964
2026-01-08 18:19:04 +01:00
Qyriad 851c4e372e add log-format setting to release notes (oops)
This was mistakenly left out of b97b2e858bab¹. oopsie, soz

[1]: b97b2e858b

Change-Id: I1b7210143d66480b6a8a044f0db5f0cd6a6a6964
2026-01-08 11:21:48 +01:00
Tom Hubrecht 1bd381654c libutil/hash: Drop printHash16or32 function
Its only use is in nix prefetch, inline it there instead

Change-Id: Ibb60df41a205cde2a4f383e8cff05dc6d4c032b8
2026-01-07 16:04:52 +00:00
Raito BezariusandQyriad 43434d675e libcmd/repl: track loaded flake references
Only successful loads counts towards the list of loaded flake
references.

Change-Id: I04128f90e57ef8352183d72dc6def7a09d52173a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-07 16:28:30 +01:00
Qyriad 1ae5610a4e libutil: cleanup abstract-config.{cc,hh} a little
Change-Id: I472682ece81718c63cb7c9053b6249836a6a6964
2026-01-06 16:35:49 +01:00
Qyriad ed16987d47 libutil: extract out AbstractConfig
libutil config.{hh,cc} and libstore/globals.{hh,cc} contain so many
interrelated things. Hopefully we can separate them out a little bit for
clarity.


Change-Id: Ib78fc46fe305d13aada8886e2e168d446a6a6964
2026-01-06 16:35:49 +01:00
Qyriad 03780ad850 remove unused includes in libstore/globals.hh
Change-Id: I14e31b32458b5caa20cbfa9b116c08316a6a6964
2026-01-06 16:35:49 +01:00
Qyriad b97b2e858b feat: make log-format a setting
Vaguely one half of #186.
Fixes #827.

Change-Id: Ie6a296465beb089bf812ea27091648ca6a6a6964
2026-01-06 16:35:49 +01:00
Qyriad c3b70a8968 CI: -Ddefault_library=both
This makes that the default for all builds... which I'm not sure is the
right option, but it is also very cheap to do so, and adding an entire
other Lix build just for static libraries (not to be confused with
static Lix) would be prohibitively expensive.

Change-Id: Id173c77cfa62886724378ca599d21c8c6a6a6964
2026-01-06 16:35:49 +01:00
Qyriad 03dc13a314 rust support in libutil via rust-monocrate
Co-authored-by: Jade Lovelace <jadel@mercury.com>

Change-Id: I026f271b07c9e27012f9ee1c16a2a1f4ba7f6ba3
2026-01-06 16:35:49 +01:00
Qyriad 357ee01002 build: attempt to normalize Rust handling to support static linking
Co-authored-by: Jade Lovelance <jade@lix.systems>

Change-Id: Icfd3cabaa6abc0a39f501b4b6c6b73df4cb66e6a
2026-01-06 16:35:49 +01:00
Tom Hubrecht b482ebbbc8 treewide: Rename Base to HashFormat
Co-authored-by: Yueh-Shun Li <shamrocklee@posteo.net>

`base` is ambiguous, since it's not about the digital bases, but about
the format of hashes. Base16, Base32 and Base64 are all character maps
for binary encoding.

Documentation of the format is also added.

Cherry-pick of:
https://github.com/NixOS/nix/pull/7708/commits/838c70f62116328ce01cb41a01886e4f1b9a727f
https://github.com/NixOS/nix/pull/7708/commits/5043e6cf4ea537dfe599470797c5b310ab0e94b9

Change-Id: Ief5425f3c2056a4cca75838091e4dfa5cca88872
2026-01-06 11:22:06 +00:00
Raito Bezarius b730fab286 f2/testlib/env: build initial path via build_env
`build_env` is assumed to be a certain trivial environment, e.g. a
singleton search path.

An environment in general is either empty, contain one or more search
paths separated by a colon.

It seems that the intent was to set the `build_shell` first as a
prepended path in the managed environment then extend via the
`build_env` parts.

This fixes a usecase when the `BUILD_TEST_ENV` is non-trivial.

Change-Id: If5b8ab976d867a57ce0b8d29255f64695e30a8b2
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-06 10:13:01 +00:00
piegames 9588b1ad1b libexpr/eval: Split out expression evaluation
In an attempt to slowly split up and clean up `eval.cc`

The `Expr::eval` functions contain the most important logic when needing
to touch something on the evaluator, and having them spread across the
3kloc eval.cc file was really annoying. This should help, though more
cleanups are yet to come

Change-Id: I2c2d15a024ab1ec3fc5591f628d6768341a1c8ab
2026-01-05 23:54:34 +01:00
Tom Hubrecht 7b8947ea63 tests/evalNixpkgs: Split out into its own file and set NIX_CONFIG
This adds a way to control the deprecated features that need to be
enable while evaluating the specific nixpkgs version

Change-Id: Ia2b9a29f1966d4d5f32239a36ba8270330007da9
2026-01-04 23:00:24 +00:00
Tom Hubrecht cfedc951b6 tests/nixpkgsLib: Split out into its own file and set NIX_CONFIG
This avoids rebuilding Lix each time we need to modify the lib tests
(as flake.nix stays unchanged), and adds a way to control the deprecated
features that need to be enable while evaluating the nixpkgs lib
testsuite

Change-Id: I2baa1cf90effcaf9d53337c6a7a5b24d6297178c
2026-01-04 22:52:32 +00:00
Raito Bezarius f683332bb3 f2/testlib/fixtures/nix: support flags on nix.eval
Certain evaluation requires to pass impurity arguments, add `flags`
to add more arguments to the instantiation.

Change-Id: I538ca2ff12c07cc66e845b42f81baa87f11b8f0f
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 22:09:39 +00:00
Raito Bezarius f981162bf3 f2/testlib/fixtures/env: test_root cannot be None
`test_root` can never be `None`.

Change-Id: I9ed344b55a733ad92ffa79e6799e44d97285109f
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 22:09:33 +00:00
Raito Bezarius 8b5c085aca f2/testlib/fixtures/env: home cannot be None
Is there a situation where `home` can be None? This hinders the ability
to use it quickly without type gating in the test code itself.

Change-Id: Idd739ddad67e10d6f7a6aad283c0e3b7cd08106a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 20:40:18 +00:00
Raito Bezarius 5ae8f62146 lix/libutil/cgroup: remove trailing \n in cgroup.controllers
Otherwise, this result in debug traces with a \n cutting the list of
controllers.

Change-Id: I8aba6379d335c4edab9d9ddb3fb411813d8dc426
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 18:23:32 +00:00
Raito Bezarius 63871751ce linux/cgroups: rename cgroups to nix-build@$drvHash-$uid
The prior use of the UID is uninteresting in general for consumers who
wants to learn things about _what_ the build is, not what is the UID of
the build user running it.

Achieving this with a place where a mapping between cgroup names and
build requests are maintained is non trivial because there's no "global"
daemon that keeps track of this information and such a daemon would
require a persistent location to track this.

Rather than solving that, we will just encode the derivation hash inside
the cgroup name. Userspace can simply pull this apart and query Nix to
obtain the original corresponding derivation for more information.

This provides userspace with a way to map cgroup names to pnames for
example. Going further, if you have a map between attribute paths and
derivation hashes, you can power a database of cgroup metrics per
attribute paths by combining all of that.

In addition to this rename, we adopt a systemd-ish convention for
template units (`@`).

As a result, userspace tooling that will scrape cgroup metrics will
discover a consistent path as long as they filter out the UID part,
especially in context of Id6c458aad30eaa08c3609ac8280a7dde8e8f3cf9
change.

This problem is tracked under #1073.

Change-Id: I238d0568a3e4b1ff3057781c0639528d666b4d37
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 18:23:32 +00:00
eldritch horrors 56d6ac3114 *: wrap nlohmann exceptions at the source
nlohmann has customization points for exception throws. we can use these
instead and wrap json exceptions at the source instead of playing a game
of whack-a-mole with json errors all over the tree. since nlohmann needs
macros set to achieve this we can no longer precompile its headers *and*
must forbid including it anywhere without the proper defines or ordering
of include directives will break lix with ODR violations, if we see them
at all before we get another json-related bug report. a new lint will be
in charge of ensuring this doesn't happen. we also re-allow direct calls
to nlohmann json parsing since error handling is no longer a problem. we
will keep the wrapper for more convenient error context handling though.

fixes #1092

Change-Id: I54ecc14f5bec5e2177729b41c3703216e76cc6a3
2026-01-04 16:25:06 +00:00
Commentator2.0 8798cdcd30 tests/functional2: migrate compression-levels.sh
Change-Id: I4a0257f6c0dd7df9b0ec82d0164a3bae7e978c9c
2026-01-04 15:57:36 +01:00
Raito Bezarius e1f5a981ef libcmd/repl: rework command handler
It's 2026 and the command handler was entirely manual!

We introduce a basic command handler framework for the REPL that handles
all the previous (implicit) features reasonably well.

This also builds up the infrastructure for nicer features.

Most important feature is that now we can let external plugins adds
commands to the REPL.

There's slight REPL changes:

- errors for debugger commands are more explicit.
- short-hand have a long-hand version.
- help shows command sorted by std::map natural key sorting (based on aliases)
  while keeping the special syntaxes for the REPL language at the top.
- sections were introduced for Flakes commands.
- :st was merged into one command with an optional argument marker.

Change-Id: Ibd24f994491bf5d45d4b218fd84c0944ae5050fd
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-04 14:12:23 +01:00
piegames ee608784dd libexpr/eval: Refactor force* and eval*, introduce check*
Status quo: We have `force$Type` and `eval$Type`, both which first
produce a value and then do a type check. The type checking logic is not
consistently implemented, with lots of code duplication.
This change does:

- Introduce new `check*` functions which unify the logic (the error
handling unfortunately still needs some duplication for now)
- Make both `force*` and `eval*` use the `check*` function for the
actual type checking
- Inline and dismantle the `eval*` functions for being of little use and
little used. This makes the `ExprOp*::eval` implementations for binary
logic operators more verbose, but IMO that's a good thing: The
implementation now needs to be a lot more explicit about the
short-circuiting semantics, something which was previously hidden behind
the short-circuiting semantics of the C++ language, in a way that could
easily be overlooked and lead to confusion, which is something that
happened to me twice in a year.
- Changes `forceAttrs` and `forceList` to include the context in case
`forceValue` fails (compared to only when the type check fails). This
was done for code consistency, because I could not find any reason why
list and attrs had different semantics here than int, float and bool. So
far the visible change is minimal (see the diff on the err.exp), however
this needs vetting for potential performance regressions.

Change-Id: I33e5c706d46850c9e1126293ee01dab85ba07587
2026-01-03 22:37:20 +01:00
piegames d387c9113c libexpr: Replace StaticSymbols with NixSymbolTable
That struct has been annoying me since I've encountered it. There is no
reason for having to track all these symbols out of band in the state.

Change-Id: I5c2c0d8174af0a51f9b456cc3651d8203a406d09
2026-01-03 13:19:55 +01:00
piegames eac96ef6b5 libexpr/NixSymbolTable: Init
The names were prefixed with `sym_` to allow faithfully representing
names that start with __. (Previously the underscores were omitted, at
the cost of readability for people less familiar with the intricate
details of Nix. Is `toString` literally `toString` or is it
`__toString`? etc.) As a bonus, this allows to easily grep for any
symbol through the entire code base to find where it is used. I've done
exactly that and grouped and annotated the symbols based on their usage.

Change-Id: I230fecd9b0b18e0984ac8111c1e6381f45c5abf2
2026-01-03 13:19:55 +01:00
Rebecca Turner 80d88ce407 functional2/pyproject.toml: clarify pytest norecursedirs setting
I was pretty confused by this when I saw it, not realizing that `build`
meant `tests/functional2/build` and not the top-level Meson `build`
directory.

Change-Id: I4865f196e5bf029419c6b488e78cbfb46a6a6964
2026-01-02 10:57:43 -08:00
piegames 3917e6b63a clang-format: Raise column limit to 110
100 causes too much diff churn w.r.t. current code style

"120 cols would be nuisance for us because our two-column layout is
exactly 118 wide (not counting the line number margin)"
"Ours is exactly 118 too"

Change-Id: Ifc7f21003e1011a17a1d799afaee775aeb927fd5
2026-01-02 17:51:33 +00:00
piegames 406fde33eb clang-format: Don't compact ifs and loops onto a single line
Change-Id: I422c7ee2b9865f9354f327cd2f151a7ff6c612b1
2026-01-02 17:51:33 +00:00
piegames 9ab386880d clang-format: Reduce alignment
Change-Id: I8326dba369707bc2d736c7e44d256d037dad9614
2026-01-02 17:51:33 +00:00
eldritch horrors 7dff4efc4a testing: migrate build-remote-trustless-*
Change-Id: I3edc3fe5babc93833bfe1e7c4bdeb02dc6ac17cd
2026-01-02 15:37:09 +01:00
eldritch horrors cc5c62ad72 testing: migrate daemon-trust test
Change-Id: I65fcdbe8f9d2f5ca4654341ed4a8878ef67b841a
2026-01-02 15:37:09 +01:00
eldritch horrors 7cf17f56f4 tests/f2: add marker for tests requiring a full sandbox
Change-Id: Ia96651273510867524814c0ce10b08aa8d655181
2026-01-02 15:37:09 +01:00
eldritch horrors 8984fddeae tests/f2: add a daemon context manager to Nix
Change-Id: I9047ac8b2ab3d0ea03b245e86aab71ad0aa888a1
2026-01-02 15:37:09 +01:00
eldritch horrors f580444348 tests/f2: add async command execution
running commands in the background like this lets us test daemons.

Change-Id: I8bf687d62f084344e59f7f5a94aedde069f7f66a
2026-01-02 15:20:39 +01:00
eldritch horrors 02a9c784d5 tests/f2: make all nix.conf setting settable
Change-Id: I5a2401c961b4328b681f6f8efb708017c756dab0
2026-01-02 13:01:14 +00:00
eldritch horrors a7bd1a8a80 tests/f2: allow string lists as config values
not all values are sets. the search path for example is definitely ordered.

Change-Id: Ice94fe324319731ae3a83c757768c48576ba8b36
2026-01-02 13:01:14 +00:00
Raito Bezarius bdd6bd5e38 libcmd/repl: factor out buildWithProgressBar
This logic is used in the various build-related REPL commands and is
factored out to make it easier to write the handlers for each
build-related REPL commands.

Change-Id: Iaa18df489db75495b12924e9a76b3fff1975eb64
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-01 22:02:50 +01:00
Raito Bezarius e798115c76 libcmd/repl: factor inDebugger
The completions for debug commands is purposefully left out because it
is going to go away in the next changes.

Change-Id: Ibc78b7587de3f15857bb09a3a0732334693ad550
Signed-off-by: Raito Bezarius <raito@lix.systems>
2026-01-01 22:02:50 +01:00
eldritch horrors 25d8495451 packaging: fix a bunch of old-nixos leftovers
remove compatibility junk we no longer need from our packaging.

Change-Id: I4642cb354ba6c4a4b64e4730c98c2c68b03040f7
2026-01-01 18:50:19 +00:00
Qyriad 163060f4df fix Wdefaulted-function-deleted in Pos/Origin
This warning was only showing up in newer Nixpkgs but presumably
technically applies either way.

Change-Id: I9606c8ebc599538789d502a8af3388346a6a6964
2026-01-01 18:21:13 +01:00
Rebecca Turner 22b33b9d08 package.nix: set $BUILD_TEST_ENV/$BUILD_TEST_SHELL more consistently
cl/4796 introduced a bug where running `just test-functional2` would
hang forever on macOS but `meson test -C build --suite installcheck
functional2` would succeed because of a mismatch between the
`$BUILD_TEST_SHELL` environment variable and the `-Dbuild-test-shell`
build option set in `mesonFlags`.

We can move these definitions to `finalAttrs.buildTestShell` and similar
and use those values in _both_ `mesonFlags` and `env` in order to make
them consistent in all cases.

See: https://gerrit.lix.systems/c/lix/+/4796/comments/50def5b4_fa5671f2
Change-Id: If300bbe46d6269ace29b44156fb4a5196a6a6964
2025-12-30 11:34:44 -08:00
eldritch horrors 570f5b8d1f libutil: always include sys/syscall.h
linux always need this as well for capabilites.

fixes #1087

Change-Id: I57aebca5c9a381c392a87cdf4b144f1efe140d5f
2025-12-30 13:03:19 +00:00
Rebecca Turner bad5a4dcc5 gitignore subprojects/.wraplock
I'm not sure what's creating this file. But something is, so let's
ignore it.

Change-Id: If05fb0851630d827ecb7b75cf2cf0b466a6a6964
2025-12-29 21:24:05 +00:00
Commentator2.0 1c42640347 tests/functional2: fix build-shell not working properly on darwin when running tests outside of meson
Change-Id: If5068ad5460d08de69f64f924c4e86e56ac0559c
2025-12-29 21:06:28 +01:00
Commentator2.0 ac1b8e91d6 maintainers: run ruff
additionally, the issue_import has been removed, as our mirror has been
disconued

Change-Id: I8cb4c807db6c415b0fd340ead58be341a05e6a34
2025-12-29 17:55:16 +00:00
Maximilian Bosch fae54ba5a8 tests/regression-reference-checks: move to functional2
Change-Id: Iccc58b4f2341606bedcaf7ad3eda0bb7ea9d8cd7
2025-12-29 11:13:07 +01:00
Maximilian Bosch 76254181c7 tests/check-refs: move to functional2
Change-Id: Ied5a50d324ee55939886795ca29896c732c45237
2025-12-27 11:11:55 +01:00
Maximilian Bosch 8d21057d49 tests/functional2: use bash as builder
...and add both a static bash and busybox into the sandbox for building:

    $ /nix/store/fz43jxs5qfg5vldzk38y2hmrcl58qk18-busybox-1.36.1/bin/sh -c 'declare -A foo'
    /nix/store/fz43jxs5qfg5vldzk38y2hmrcl58qk18-busybox-1.36.1/bin/sh: declare: not found

The reason is that busybox's `sh` doesn't know about `declare` which
means it cannot build derivations with `__structuredAttrs = true;`.

Change-Id: Ie3ca431f862fd3e59dc649582704ae739ee5834a
2025-12-27 11:11:55 +01:00
Alois Wohlschlager fa62109164 tests/functional2: stop littering TMPDIR so much
Nearly each tests gets a fresh store (in the test root residing under TMPDIR),
which with default settings means 8 MiB of reserved space to be deleted by the
user in case of space shortages, which of course for a test suite is just
wasted. Stop doing that to considerably reduce the litter (experimentally, from
3.7 GiB to 67 MiB per run). The old functional test suite already did the same.

Change-Id: I912cdda6e796ea37cfee0b8fe0478e976a6a6964
2025-12-27 07:05:15 +01:00
eldritch horrors 1546ea0d5f tests/f2: make ManagedPath searchable
Change-Id: Idccf83a4471d76362153535125a269abbbb03c62
2025-12-26 20:56:51 +00:00
eldritch horrors 9ebe5acf39 tests/f2: don't set NIX_STORE_DIR unconditionally
this is only needed on macos, and only for tests that build anything. on
linux it can actually *break* stuff due to unfortunate interactions with
store url parsing, which is required to work for any remote build tests.

Change-Id: Ic6f7e090f15e129fc365d7edc56cdbc1a5686047
2025-12-26 20:14:39 +00:00
Steve WalkerandXYenon 4d67200b80 flake: Fix follow symlinks
Contributes towards #106.

(cherry picked from commit 24d11d22c31dd7773cbcef6ea077e62ea114e2a3)
Upstream-PR: https://github.com/NixOS/nix/pull/12286
Change-Id: I523c76e31f27fac5d73eff76b22894adcd6ee135
2025-12-26 13:01:28 +08:00
Jade LovelaceandRebecca Turner b2feecf7e7 libexpr: use MaintainCount for call depth
This was duplicate code.

Change-Id: I40697da80c3b8123c9cc3f10e5be5cc49c35629d
2025-12-23 14:18:11 -08:00
Commentator2.0 c0f177081b fix: tests/functional2/lang: remove empty file
apparently this file slipped through the code review (the actual test
does exist, no worries) but this empty file and init py exist, sitting
here empty. This commit drops them as they serve no purpose

see commit 1b7ad3a7ad

Change-Id: I64c4e03cd3ceedf9e430ae014127966bd8e4269d
2025-12-23 14:38:23 +01:00
K900 8f27c09a08 nix-eval-jobs: set meta.mainProgram
Change-Id: I77c645a4ddec4e90884942f1919a41e1e3cd66aa
2025-12-22 09:43:02 +03:00
Fiona Behrens 2b1c6b6e5e lix-doc: test: add rust tests to check suite
Add the rust tests defined in lix-doc to the check test suite.

Change-Id: I2677679d89fccef0f73fb93abf87334706492739
2025-12-21 14:11:30 +00:00
Seth FlynnandSergei Zimmerman 8eb57801a5 nix3: use pure/restricted eval for help pages
This avoids any complications that can arise from the environment
affecting evaluation of the help pages (which don't need to be calling
out to anything external anyways)

I don't think this is actively causing problems now - though it did in
Nix! - so this is largely preventative, but I don't really see a reason
why this was ever running in impure mode in the first place either

Based-on: https://github.com/NixOS/nix/pull/14086
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
Change-Id: Ice0c760562d70c09934249edc3b767473516d372
2025-12-21 13:56:58 +00:00
Max Siling 39ee6829b2 libfetchers: fix error message for bad indirect URL
It used to say "GitHub URL ... is invalid", which is wrong and confusing.

Change-Id: I89a00aee21a56710d6afdfa0510d4e9c6a6a6964
2025-12-21 00:00:13 +03:00
eldritch horrorsandkloenk fde68055df tests: fix f2 build tests
- test_check used an old version of an error message
- test_good2 did not build an unspecified dependency
- test_attribute_selection used a fixed drv path. we
  can't keep this with the current setup because the
  drv `system` makes the drv hash platform-dependent

fixes #1081

Co-Authored-By: kloenk <me@kloenk.dev>
Change-Id: Ia009740f8b5432e83467ea451a5ff53d5e141b3f
2025-12-20 20:01:08 +00:00
eldritch horrors 521b42866d nix/daemon: socket-activate single connections
the cgroups experimental feature does not work properly without this
because we do not stop subdaemons when the main daemon is shut down.
systemd needs the assigned cgroups to be empty to restart the daemon
and thus cannot cleanly restart the daemon if any connections exist.
starting a fresh unit for each connection creates a new cgroup every
time instead of sharing any delegations and thus solves the problem.

fixes #1030

Change-Id: Id6c458aad30eaa08c3609ac8280a7dde8e8f3cf9
2025-12-20 15:09:23 +00:00
Commentator2.0 c1debca36b tests/functional2: migrate tarball.sh
Change-Id: I8fb889a5723e34453597fbce2e027fb49a859319
2025-12-19 20:44:25 +01:00
Jade Lovelace 605de55fed package.nix: stop rebuilding aws-sdk-cpp
A friend reported that this is rebuilding, which doesn't make any sense
because nixpkgs also has a lix from nightly that surely has the same
dependency and thus it surely should be built on hydra, right?

Turns out no, since they were overriding the requiredSystemFeatures to
remove big-parallel. Silly, but we can match that and get cache hits.

Change-Id: I4b1c8e850c6c38b03881354e978f41a10592ec95
2025-12-18 21:26:00 +01:00
Justin !andTom Hubrecht 32d7c02b96 nixpkgs: bump to 25.11
This bump nixpkgs input to 25.11 and fix the two warnings that were
coming with the update:

1. `pkgs.system` => `pkgs.stdenv.hostPlatform.system`
2. `runCommandNoCC` => `runCommand`

also:

1. remove cppnix 2.3 compat tests (cppnix 2.3 is officially dead now)
2. remove lowdown 1.3 compat tests (nixpkgs no longer carries it)

Co-authored-by: Tom Hubrecht <github@mail.hubrecht.ovh>

Change-Id: I78526b5d8992a6c63ecd7f0c7c1fa6346a6a6964
2025-12-17 20:59:59 +01:00
Qyriad 72b120faf5 refactor LogFormat to libutil I guess
It only debatably belongs in libutil since libutil doesn't know what a
progress bar is but whatever.

It was either that or libstore. Since I'm about to make it a setting.

Change-Id: Iba59b0a190087b316ff3191a0ddd9ec36a6a6964
2025-12-17 15:50:50 +01:00
Commentator2.0 fc0073f540 tests/functional2: provide an empty repository as a global asset (needed for flake tests)
Change-Id: Icef02d7ae9594aa73a1679bed8f98be053fb693c
2025-12-16 11:15:51 +00:00
Commentator2.0 b2ee6c36a0 tests/functional2: paritally migrate test_fixed.sh
Change-Id: I3e4479b3ca718f24f604b52a6717ce18f793553b
2025-12-16 08:31:50 +00:00
Commentator2.0 a078462013 tests/functional2: refactor global assets
make the global_assets folder more readable by placing asset pack files
within a dedicated folder instead of building up a mess similar to f1

Change-Id: Ia2c16f38eb6da96e1e73584bd91391ee56acb410
2025-12-16 08:31:40 +00:00
Jade Lovelace 70319f1840 tarfile: unit test suite
This will probably get the implementation of the fixtures revised when
we land the new extraction code, but we are setting it up to be generic
against that.

The operator-> thing is kind of a crime. But it also makes the code
vastly more readable so it's impossible to say if it's bad or not.

Change-Id: Ia5aca69cefaa03cd533ad19d20d856ff7e76a546
2025-12-15 22:42:31 +01:00
Jade Lovelace 88cea98b82 refactor: use std::unique_ptr for libarchive state, remove destructor
Change-Id: Ib16eefc17ae53874b295476fae515305525a7f2b
2025-12-15 21:21:04 +01:00
Tom Hubrecht 0ebb1c524d daemon: Make the error more explicit when the sandbox group tries to connect
Fixes #1069

Change-Id: I32ece312b0a1c4fbbc21902d71a15c6ff40b3aed
2025-12-14 20:43:20 +01:00
Tom Hubrecht b2b95775bd misc: Really fix the unused-variable warning
When everything else has failed, cast it to the void

Change-Id: I8f9769e60c359a6a17151e9199749f5c7042566f
2025-12-14 20:43:20 +01:00
Tom Hubrecht 5157fbaf2c testWithNix: Don't depend on CppNix
Change-Id: Ia0903d93796c30e370d99d02877cc93c258b8f32
2025-12-14 15:20:16 +01:00
Rebecca Turner 3e3573cb58 libutil: reformat tarfile.{cc,hh}
Change-Id: I24670300157213fba787df62931776416a6a6964
2025-12-13 16:35:22 -08:00
Max Siling 6bf187537a libfetchers: use commit hash as rev for tag refs
Instead of manually reading the ref file,
which gives the tag object hash when ref is a tag,
shell out to git.

The logic for finding the ref file is left for cache TTL tracking.

Fixes: #1070
Change-Id: I490b1e62f83cf602c56232c6081a52166a6a6964
2025-12-13 23:15:18 +03:00
Qyriad 43b1b63df9 libutil: add shim to impl operator<< in terms of std::format
Change-Id: Ie749801f669c0cfcd93b8ff559add96a6a6a6964
2025-12-13 15:07:39 +01:00
Qyriad 9d6e71bd56 feat(nix3-store-delete): unlink root and delete its closure at the same time
Feel free to bikeshed the name --unlink

Change-Id: I71a44d873d88e5a2ab300af3f0a868dd6a6a6964
2025-12-13 15:05:12 +01:00
Tony Wasserka a6f0e59c2c doc/contributing: Fix typo
`--extra-deprecated-features` with `=` is not recognized, instead it must be followed by a space.

Change-Id: I2b817b7cc6fb11a3672422a1756ba87da1623b3b
2025-12-11 18:09:46 +01:00
hansemschnokeloch 227852f221 Edit doc/manual/src/glossary.md
Change-Id: I6d70112874ae22efb440aacdff0faedc89c395d6
2025-12-11 07:46:10 +00:00
Tom Hubrecht 36a61d922c lix-clang-tidy: Avoid using llvm::Twine
> A Twine is not intended for use directly and should not be stored

Change-Id: Ie243d109bc3feb75867ed748c5e4cbcddfafd3e1
2025-12-09 17:13:36 +01:00
Tom Hubrecht 5d21b8262b clang-tidy: enable bugprone-multi-level-implicit-pointer-conversion
The default clang version in nixos 25.05 was llvm 19, we are now even
past that

Change-Id: Ieb62616fb87c4d2a8d892136a7164822aa1eceb6
2025-12-09 14:51:43 +00:00
Tom Hubrecht 50c47c340f misc: Remove unused private field, move unused variable in #if, remove virtual specifier
Those are new warnings that come with a more up-to-date llvm

Fixes #1066

Co-authored-by: eldritch horrors <pennae@lix.systems>

Change-Id: I305d0d810d12a5e8d31c7d89e0cdb3a82df71556
2025-12-09 14:29:35 +01:00
Qyriad 2c68244142 build/functional2: don't require installation for tests to run correctly
Change-Id: I9a2bd83c09c8a009e683c73bf2a669036a6a6964
2025-12-09 11:13:55 +01:00
Kate Temkin 15969c51c3 legacy/build-remote: fix a missing format string argument
Change-Id: Ic3156695a7f41367d413f2da3b5791d489576d47
2025-12-09 09:47:21 +00:00
Tom Hubrecht 3db533c637 clang-tidy: enable bugprone-implicit-widening-of-multiplication-result
Change-Id: I7c7bae6c27aa59da23097ec89305cfc60ec9e8e3
2025-12-09 08:32:37 +00:00
Qyriad b2bcd99d59 functional2: fix bug in physical_store_path_for()
I guess on aarch64-darwin dirs.store_dir can be a str?

Change-Id: If4baa1f48f641775c6e3ab9ce7a58e476a6a6964
2025-12-08 19:07:44 +01:00
Alois Wohlschlager a99842e0af nix-eval-jobs: asyncify the coordinator
Change-Id: I62007ed4d43029a4c793c0152c06490d6a6a6964
2025-12-08 18:32:12 +01:00
Raito Bezarius b5a8720a47 legacy/nix-shell: export NIX_LOG_FD
As far as I can tell, there's no harm to let know a nix-shell invocation
about NIX_LOG_FD being stderr.

Fixes #336.

Change-Id: Ifdb3591813251d4bc481158d28dc18e1489de72c
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-08 09:12:40 +00:00
Raito Bezarius 908acdfa2f nix3-develop: export NIX_LOG_FD
As far as I can tell, there's no harm to let stdenv know that they can
write to file descriptor 2 which is stderr inside of a nix3-develop
shell.

Contributes towards #336.

Change-Id: I51dcbcbc19a1698a0d1255f9d943d9ebd15d115d
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-08 09:12:40 +00:00
Maximilian Bosch be3e4bf78e tests/functional/output-cycles: move to functional2
Change-Id: I682f62a695ba7722e2b3063bf831fc50a19eb153
2025-12-07 21:47:10 +01:00
Maximilian Bosch 0a5f474a25 libstore: fix reporting output cycles on drvs with references to other drvs
Closes #1064

The culprit here is that `genGraphString` is only invoked with the
store-paths associated with the outputs of the derivation, so when
filling `dependents`, the `graph_data.find(p)` call would return the end
of the iterator when doing this for references to other store-paths.

As a result, the code wrote information behind the graph data-structure
causing a corruption. For me, this resulted in a SIGSEGV most of the
time and in a few cases in an uncaught `map::at`-exception as reported
by Niklas.

This patch changes two aspects of the original implementation:

* When filling `dependents` in the node-set, use `map.at()` instead of
  `map.find()->second`. The latter doesn't make any sense and was the
  cause of corrupting memory. The `at` would've made it far easier to
  spot this in the first place.

* Filter out store-paths that don't belong to a different output of the
  derivation when creating `outputGraph`. This variable is used on two
  places, `genGraphString` and for topological sorting.

  The latter already filters out store-paths from a different drv, so
  this is happening now when creating the variable in the first place
  such that `genGraphString` never ends up with corrupt data in the
  first place. This is the actual bugfix.

Implemented a regression-test for this case to be sure.

Change-Id: Ie02144d89c32b0a776cb1ece0601d0229315ebc3
2025-12-07 21:47:09 +01:00
eldritch horrors 6410748c9f libcmd: add raw arg access to legacy commands
we'll need this to modify argv for socket-activated daemons. this is our
replacement for the old savedArgv mechanism that was unscoped and fucky.

Change-Id: Ie048eb8ea99f1c9cd627a051292c836c83197068
2025-12-07 18:49:34 +00:00
eldritch horrors aba740a276 libcmd: remove unused savedArgv
this was only used in the pre-exec daemon days.

Change-Id: I3bbb113f9940e6980f01af60e6614a9656b0fd03
2025-12-07 18:49:34 +00:00
eldritch horrors 1e8f7c7c76 nix/daemon: remove settings copy from parent
the parent daemon does not change any settings before starting a child,
so there's nothing we may want to change that is not already set by the
config file. this also doesn't prevent changes of the config file being
applied to daemons where we do not expect it since it'll only restore a
setting to the parents' value if the child also has an override for it.

Change-Id: Ic5a9ef13458c103ec9979cb187ba8d3ce5e1e719
2025-12-07 18:49:34 +00:00
Qyriad 400b55a410 nix-eval-jobs: use C++23 to match Lix
Change-Id: Ia770f849fd43b360fc641d478abe084e6a6a6964
2025-12-07 18:34:24 +01:00
Qyriad 0714a21b03 perl-bindings: use C++23 to match Lix
Lix changed to C++23 in 4ea8c9d61¹, but the perl subproject wasn't
updated with it. This commit corrects that.

[1]: 4ea8c9d643

Change-Id: I5464138d206d87cf25762720b147487d6a6a6964
2025-12-07 18:34:24 +01:00
Commentator2.0andQyriad 0bcaffa640 functional2: add a hash_path shortcut to Nix
Co-authored-by: Qyriad <qyriad@qyriad.me>

Change-Id: If0b9213d264b60e687ceb2d4d232d23f6a6a6964
2025-12-07 15:34:03 +01:00
Qyriad f6f03d0a52 functional2: add helper to get actual store paths to Nix fixture
Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>

Change-Id: I13f8ba9d59ae863cf08109a01c638c7f6a6a6964
2025-12-07 15:34:03 +01:00
Tom Hubrecht 8ebe893854 clang-tidy: enable lix-fixincludes
The reorganization has been done

Change-Id: Ib8eec6656f375f8329fe4caefd009369aa36d8f2
2025-12-07 14:05:39 +00:00
Tom Hubrecht 1a304964aa package: Add libllvm to the inputs when linting
This should allow better stacktraces when clang-tidy fails miserably on
aarch64 machines

Change-Id: Ia795cf1dc012bd8f06b429d97184b88c80dd72cb
2025-12-07 11:40:03 +01:00
Tom Hubrecht 543ae33d26 functional2: Increase timeout in the cycles detection test
On a busy CI the 1s timeout is not always enough

Change-Id: Ie39be01ae8818df8c9026d28907f5b145a452e3b
2025-12-06 22:33:19 +00:00
Raito Bezarius 6928c6f952 libstore/store-api: offer more information about drv parsing errors
We offer the three usual options: verify, repair then delete and direct
people to report us corruption so we can fix if this is induced by us.

Fixes #447.

Change-Id: I0df61769d732d227333c206f312857c0593f7bce
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-06 20:30:38 +00:00
Raito Bezarius 7f32b71b6b libstore/derivations: expand error message for the first misparse
If the derivation does not start with D, do not return a simple
"expected string 'D'" error but a full error message.

This contributes towards #447.

Change-Id: Iee05f3918e4cc43e79f244ab2fd64a52cf2bb6d2
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-06 20:30:38 +00:00
Raito Bezarius d2ca1810b1 nix/upgrade-nix: disallow daemon connections for the store
Prior to I6a6a6964d2b5ad47ae5ea9eb11af9b6373ce2141 — `sudo nix
upgrade-nix` would perform direct store access.

This ensured a certain number of desireable properties for upgrading the
Lix binary itself.

We re-introduce direct store access for upgrading Lix binaries.

Fixes #1060.

Change-Id: I523c4d3023ed5fe9eff8fde9a266c56a0de47d8c
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-06 20:30:15 +00:00
Raito Bezarius 7fbb366ce2 lix/legacy/nix-build: save up 30ish chars in $NIX_BUILD_TOP
Alternative to cl/4661 discussed in #1044.

It can be assumed that `$tmpdir/build-top` can be created safely without
any risk, this way, we don't need to reuse the random directory creation
primitive.

Fixes #1044.

Change-Id: Iec52477f3047fc40959b183c607312d5a40fc8c9
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-06 19:48:08 +01:00
Maximilian Bosch 74f5d66b39 perl: unset NDEBUG after loading Perl headers
Otherwise, loading Perl bindings fails early with[1]

    undefined symbol: Perl_pad_sv at /nix/store/h2jsb5i4yfblr2f3ac2c7zpmlmj7zjym-perl-5.40.0/lib/perl5/5.40.0/XSLoader.pm line 94

Apparently, it's expected behavior by Perl that this symbol only exists
with `DEBUGGING` being set, hence it's used by the headers. However,
`pkgs.perl` from nixpkgs is apparently not built with `-DDEBUGGING`
causing this error.

Now, `NDEBUG` is manually unset after loading the Perl
headers rather than setting `DEBUGGING` causing the error mentioned
above.

I confirmed that this not only fixes the problem described above, but
running the Hydra tests with

    diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs
    index dfdd64d28..14788266c 100644
    --- a/perl/lib/Nix/Store.xs
    +++ b/perl/lib/Nix/Store.xs
    @@ -27,6 +27,7 @@ using namespace nix;

     static AsyncIoRoot & aio()
     {
    +assert(false);
	 static thread_local AsyncIoRoot root;
	 return root;
     }

still results in assertion errors.

Finally, added a small install-check that importing `Nix::Store` works
fine.

[1] https://git.lix.systems/lix-project/hydra/issues/69

Change-Id: I58521777eb0f94b766a9813aa4bbd06f9052bd35
2025-12-05 18:36:35 +01:00
Commentator2.0 07dccd67d6 treefmt/ruff: remove EM rules as they cause unnecessary work with no real upside
As discussed in the F2 matrix channel, not being able to put the error
message inside of the thrown exception just results in one assigning an
additional variable to immediatly throw it. The original reason for
these rules to exist are that the message isn't printed twice, though
the line above the thrown exception is printed anyways in the
stacktrace, so we still get the error message twice but now with
additional work.

Hence this commit removes the said rules

Change-Id: I0b37c0b0861334703a5772c36353d31441f19dcd
2025-12-05 13:45:59 +00:00
Commentator2.0 f65b83df3b treefmt/ruff: extract ruff config from f2 to global state
So far, our ruff config was confined to the f2 package. This meant, that
when one added additional paths to the ruff formatter, those wouldn't
get the same rules applied as f2, resulting in inconsistent styling
thoughout the project.

Due to how configs are resolved, only the "closesed" pyproject toml is
considered. This means, we need to tell f2 to extend its configuration
with the base level one. Though no change is required for other parts of
the project, as long as they don't have their own pyproject.toml

Change-Id: I145c764e7b850194020b5560e1025f4aa80411ae
2025-12-05 13:45:47 +00:00
Commentator2.0andQyriad 85443e0fd8 tests/functional2: migrate completions.sh
Change-Id: I186a1ddd8d56386f9d1308430f517cdec483af14
2025-12-05 13:33:20 +01:00
Raito Bezarius 1e98c01912 libutil/users: support service cache directories
Nix daemon runs in a service context, usually with systemd.

If the Nix daemon unit adds `[Service] CacheDirectory=nix-daemon`, it should
successfully use `/var/cache/nix-daemon` automatically.

Instead, it uses `/root/.cache` right now, which is really bad.

By default, we add `[Service] CacheDirectory=nix` now which means that
caches are moved into `/var/cache/nix`.

Fixes #634.

Change-Id: I854b1045bfdce8f60110aea70bda1bf6657dfd7b
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-12-05 00:14:42 +01:00
Commentator2.0 8f5bf1e905 libstore/machines: add enable flag for toml machines
Provide a way to statically disable a machine.
This is fully static and not dynamic.

Change-Id: I394433ad533bca5dbf6a2f7fea22b8aa0f5aad3f
2025-12-04 12:11:23 +01:00
Commentator2.0andQyriad 3fcfedc216 libstore/machines: add toml parser
implements #854

Co-authored-by: Qyriad <qyriad@qyriad.me>
Change-Id: I958d082ccdf03179b35d5ab8a810ebafcff3b6c5
2025-12-03 21:36:53 +01:00
Commentator2.0 23c341d76d libstore/machines: move legacy parser to own namespace
Change-Id: I4ecf1e56e713cd32b6a443f9d195c1beb0cb2f7f
2025-12-03 20:10:35 +01:00
Commentator2.0 d0a655fc8a libstore/machines: refactor machine parsing
Change-Id: I216592e089328d68f9ca48203a19fd964356249b
2025-12-03 20:10:35 +01:00
Alois Wohlschlager 00dfcc81b4 doc: fix substitution with mdbook 0.4
Recently, in 54df89f601, support for mdbook 0.5
was introduced, including some logic to handle the `sections` -> `items`
rename. However, compatibility with 0.4's `sections` was only kept on the read
path, while writing 0.5's `items` unconditionally, which ends up in the bit
bucket on 0.4, effectively disabling substitution fully and leaving the include
directives in the final documentation. Restore writing into the `sections` when
they were there so that substitution works again.

Change-Id: Idd4d7653012660f3f7fc27f81f29b82d6a6a6964
2025-12-03 10:01:55 +00:00
Commentator2.0 8353b3cc6a tests/functional2: fix non-working failsafe and resulting warning
Silly me forgot to add the dependency responsible for handling
`@pytest.mark.timeout` failsafes to kill a test if it takes too long,
which results in a warning when running f2.
This commit adds the required dependency and hence removes the warning

Change-Id: I281cad05bb0cf50208f72080cb2bfd8cbfb09d0c
2025-12-02 19:52:38 +00:00
Zoe Zuser 06f987fb0c meson: fix libstore.pc
typo of aws-cpp-sdk-transfer as aws-cpp-std-transfer prevents linking
against lix

Change-Id: Id847eab2601698696030d31fcd51288aa5f3d274
2025-12-02 10:45:50 +00:00
K900 716a885def nix3: show logs by default
That's it, that's the change.

Change-Id: I00c55265ee0e9982b91626601236fe238edf480c
2025-12-02 01:02:44 +00:00
eldritch horrors 2ae74802c4 libexpr: AST-dump non-utf8 strings as byte arrays
our strings need not be utf8. json requires utf. -sigh-

fixes #1052

Change-Id: I50ecd9882252370bb81845b099b11a7190475d48
2025-12-01 21:11:25 +01:00
Justin ! 084a8c3711 libexpr: add a deprecation warning for builtins.importNative
First step for: https://git.lix.systems/lix-project/lix/issues/795

Change-Id: If375723c6829f4fb9c7c1c5bff6be3c9e164c2be
2025-12-01 13:02:13 -05:00
K900 97dd9ba1e2 flake: minimal fix for lowdown override failing on nixpkgs master
All of this can be yeeted once 25.05 is gone.

Change-Id: Id8d9528cf5d09d7697203dc7dde4be1f0ac5f5d1
2025-12-01 16:29:04 +00:00
Alois Wohlschlager f3ed72f30b tests/functional: include mount and PID namespaces in the sandbox check
Running the sandbox (as unprivileged user) requires all of user, mount and PID
namespacing. Previously, only the user namespacing support was checked.
Unfortunately, newer Ubuntu kernels impose restrictions on capabilities within
unprivileged user namespaces [1]; as observed by experimentation, in particular
(re-)mounting filesystems or changing mount propagation is prohibited even
inside a mount namespace, making it impossible to use the Lix sandbox. So any
tests requiring sandboxing should check for this breakage and be skipped if
detected.

`unshare --mount` performs the same problematic operations, so that's what gets
used for the test. PID namespaces are included as well for completeness, even
though currently no instance of breakage due to them specifically is known.

This fixes [2] for the functional test suite only.

[1] https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
[2] https://git.lix.systems/lix-project/lix/issues/545

Change-Id: If95b527bf965ccb06371bbef7b6007666a6a6964
2025-12-01 14:25:47 +00:00
Alois Wohlschlager 31b6c823ae tests/functional: mark the remaining test requiring sandboxing
Diverted (chroot) store requires sandboxing, so the relevant test needs to be
marked as such.

Change-Id: I5c8ad5f90bb26f8e7088c7141066a18a6a6a6964
2025-12-01 14:25:47 +00:00
Alois Wohlschlager afd7faf385 libstore/build: disallow sandbox-fallback when using a diverted store
Builds using a diverted store strictly require sandboxing. Explicit disabling
by the user is already handled properly by force-enabling the sandbox anyway
(with a warning), but sandbox-fallback was still honored, predictably leading
to hilarious breakage (like the "confusing output" in [1]) when it actually
triggered. Cause a hard failure instead.

[1] https://git.lix.systems/lix-project/lix/issues/545

Change-Id: I61ea32c3bd8bca4e5ba278312b0a49326a6a6964
2025-12-01 14:25:47 +00:00
Alois Wohlschlager 7f176002c6 libstore/build: warn when the sandbox is force-enabled due to a diverted store
Builds using a diverted store strictly require sandboxing. It therefore makes
sense to automatically enable it even if otherwise explicitly disabled by the
user. However, they should still be informed that their choice is not being
respected.

Change-Id: Ia2cbdc24a4c55d8ecc49094e35e698e16a6a6964
2025-12-01 14:25:47 +00:00
Alois Wohlschlager b4e2abdf5c libstore/build: upgrade the sandbox-fallback message to a warning
Disabling build sandboxing is a significant change to build isolation. If this
is done automatically due to namespacing issues (and sandbox-fallback not being
disabled), show the user a loud warning without the need to opt into a lot of
other log spam.

Change-Id: I52daccdd6934873234223c798ca3dcff6a6a6964
2025-12-01 14:25:47 +00:00
Tom Hubrecht 1bfbbe2415 nix-shell: Add NIX_SHELL_LEVEL variable
This contains the depth of nix shells nesting.

Fixes #826

Co-authored-by: Qyriad <qyriad@qyriad.me>

Change-Id: If584c9d02730d6c857636dafdeab0c01f4ec8e0f
2025-12-01 12:02:45 +00:00
Tom Hubrecht 0c6d299e16 libexpr/eval: Deprecate shadowing <nix/fetchurl.nix>
If the NIX_PATH shadows internal files, this will often break things,
hence we forbid it.

Fixes #998

Change-Id: I70e5d389532ada1c9f910c60281abe565e3ce6bb
2025-11-30 12:28:54 +00:00
Alois Wohlschlager 3981458d8c nix-eval-jobs: make the tests independent of the evaluation order
Some of the tests depended on the evaluation order chosen internally by
nix-eval-jobs, which will break when that order changes. In practice the order
is not guaranteed, and already not deterministic with multiple workers.

Change-Id: I2e85d096f4439a8075a6f4a08d31c0f16a6a6964
2025-11-29 12:01:20 +01:00
Alois Wohlschlager ecf0d4c5a4 nix-eval-jobs: compile with Clang
GCC still ICEs on coroutines, while Clang works properly. Use the latter, just
like for Lix itself.

Change-Id: I802d6df7279550a5f5355e6c1ea0533c6a6a6964
2025-11-29 12:01:20 +01:00
Alois Wohlschlager 7440c4ef75 nix-eval-jobs: split the collector loop
Previously the collector-side implementation of the worker interaction protocol
was a bunch of spaghetti code. Split it apart at places where it makes sense to
be easier to follow.

Change-Id: If3cc6b6fbf289dd778856b40b55316c76a6a6964
2025-11-29 12:01:20 +01:00
Alois Wohlschlager 24497d08bc nix-eval-jobs: use std::thread
As the worker processes are now properly spawned using fork-exec, they no
longer inherit the stack size from the non-main coordinator thread, but get a
main thread with reasonable stack size on their own. For this reason the
coordinator threads can use the default stack size, and turn std::thread can be
used as the only reason for the custom wrapper was to enlarge the stack.

Change-Id: I1192474885abe9b0625ac483840b6e1a6a6a6964
2025-11-29 11:25:19 +01:00
Alois Wohlschlager 258c5b76eb nix-eval-jobs: fork and exec the workers
Similar to how 7b37d5ea6a switched the subdaemons
from fork-only to fork-exec, do the same for the nix-eval-jobs workers. This is
the promised change that causes the signal handler thread to appear.

Change-Id: I590a5eb6bddfb546a331a01191fd788b6a6a6964
2025-11-29 11:25:19 +01:00
Alois Wohlschlager 9baa4b5b74 nix-eval-jobs: wait for the crashed worker synchronously
The retry added in 4c5efd4548 has never worked
properly, as releasing the pid the first time causes it to be -1 and thus
waiting for a random child on retry. While there is a good chance that this
really catches the crashed worker, this is by no means guaranteed, and it could
just as well have caught different restarting worker. Wait synchronously
instead. The worst possible outcome is a hang instead of an error message if
the worker manages to close its pipe but then fail to exit, which is not
supposed to happen in the first place.

Change-Id: I4e4c3f532ec15c3118f6f77821ab820a6a6a6964
2025-11-29 11:25:19 +01:00
Qyriad d5d03cd8de undefined behavior: -Wembedded-directive
warning: embedding a directive within macro arguments has undefined behavior

????? CLANG? why does this take -pedantic to show??

Change-Id: I6f4a9f3db1b89448f9f5d00d82b551e46a6a6964
2025-11-28 21:29:44 +01:00
Jade Lovelace 0423f0ef38 docs typo: ssh-keyscan takes a hostname not user@host
Change-Id: Ib823165bcababed2808a602368d6ab57762a49b3
2025-11-28 12:06:20 +00:00
Qyriad 94c9b43b4a docs/hacking: fix typo from LLD commit
Thank you horrors

Change-Id: Id792cfd19efd3f99b55809cdaae420c06a6a6964
2025-11-27 12:58:07 +00:00
Qyriad b92c85848f functional2: fix on macOS if user has PATH elems that don't exist
This change brought to you by my uninstalling go but forgetting to
remove ~/.local/opt/go/bin from my PATH.

Change-Id: I937675bab11ac7e0678c896cba78204b6a6a6964
2025-11-27 10:51:08 +00:00
helle 54df89f601 docs build system: Fixed manual to be compatible with mdbook 0.5.x
Maintains compatibility with mdbook 0.4.x.

Includes comments for what to remove once 0.5.x is the only we care
about. Some other changes technically could be changed at that point,
but currently serve to enable universal support of 0.4.x and 0.5.x

Fixes #1051.

Change-Id: Ic5b405038d180bcd357bbd9e5716879e0c26e5f5
2025-11-26 23:50:28 +01:00
Tom Hubrecht cb0f9b9590 libstore/transfer: Warn by default instead of throw for destination changes
Fixes #1004

Change-Id: I2d583fbad40b3c95e37b70167a81c8fb492d5668
2025-11-26 14:42:52 +01:00
Tom Hubrecht 0c70cc6259 libutil: Reintroduce compile assertion that was mistakenly dropped
https://git.lix.systems/lix-project/lix/commit/74513483bc5572d988a059b8e964662d66f1667f
removed this check which is actually load-bearing for Lix (c.f.
https://git.lix.systems/lix-project/lix/commit/96a36833084f66b79ba778e719862b8219557773
).

Fixes #677

Change-Id: I3cc9a16c64c5189f788c510609afcf8bad997741
2025-11-26 01:56:00 +00:00
Qyriad 9f12981b30 parser: improve error message for missing } in attrset
Change-Id: I2846dbd8d0c1beb23c885a2d6d388a4f6a6a6964
2025-11-25 19:50:24 +00:00
Qyriad 6bb532ed03 parser: improve error message for missing semicolon in let/{}
In the same vein as be18b7dc2¹.

Before:
  error: syntax error, expecting ';'

After:
  error: syntax error, expecting ';' to end binding

[1]: be18b7dc25

Change-Id: Iffbcb113d2b892a50c646c9875e970376a6a6964
2025-11-25 19:50:24 +00:00
Commentator2.0 3661f34aba tests/functional2: fix --accept-tests not propagating to infra tests correctly
gotta make sure to do things in the correct order next time -_-

Change-Id: I84ba6495100e658aa35fac0a0917fae9363fe4dd
2025-11-25 13:43:01 +01:00
Alois Wohlschlager df607dd39e nix-eval-jobs: print evaluation results using writeToStdout
Lix blocks SIGPIPE, and std::cout ignores EPIPE (actually it probably stashes
an error code in some flag that no one ever reads, with the same end result).
Consequently, nix-eval-jobs would waste resources by continuing to evaluate
even when the reader interested in the results has long gone away. Instead, use
writeToStdout, which throws an error on EPIPE, leading to the process
terminating as desired.

Reported-by: Winter <winter@winter.cafe>

Change-Id: I962c09bab582a8ed27dd41c01b1519876a6a6964
2025-11-25 11:50:59 +00:00
Alois Wohlschlager 441f7db5f1 nix-eval-jobs: handle worker interruption properly
Right now, the worker will not receive interrupts, as it has no signal handler
thread due to the way it forks, but this will change soon. Prepare to handle
worker interruption properly, by letting the worker exit successfully in this
case and adjusting the coordinator to handle this exit gracefully.

Change-Id: I9f79670b0d2004e7e2d8bf36cf67108e6a6a6964
2025-11-25 11:50:59 +00:00
Qyriad 9d01255046 build: use lld in devShell on Linux
Change-Id: If270e824cab74337c6c71fe92fd376c76a6a6964
2025-11-25 11:02:32 +01:00
piegames 27a94369a9 nix::parser::State::addAttr: Deep attribute merging
Closes #845

Change-Id: Ie14d0e5a7a9fb778325c4ad30d1e1bd73c60b4f9
2025-11-24 19:16:27 +00:00
piegames 8765266dae nix::parser::State::addAttr: Improve error message
For some reason that eludes me, it used to only print the last attribute
instead of the full chain.

Change-Id: I2f5f6e85e2b1ab3ab20a9c99bf06d1e45a4d09bb
2025-11-24 19:16:27 +00:00
piegames 5484351523 nix::parser::State::addAttr: Sanitize
`e`, `ae`, `j`, `jAttrs` … holy fuck this function was so much worse
than it needed to be. This refactoring includes:

- Descriptive variable names where possible
- More code comments indicating what even is happening
- Shuffled the control flow around to be more linear (move early return
conditions up, etc.) and have less rightwards-drift, to increase
readability
- Extracted `mergeAttrs` function for future changes and readability

Change-Id: I7253b47ce4910fdc67aa7d6edff2f3c0bb8fa55b
2025-11-24 19:16:27 +00:00
piegames 4ce8d809ea libexpr/parser: Fix small error position mistake
In one of the cases it pointed to the first instead of the second
occurence, which is a bit confusing

Change-Id: Ie508d1f84feb434708804d45aa8a9c8b1e3c5f69
2025-11-24 19:16:27 +00:00
piegames 6da3519297 tests/functional2/lang: Move some tests around
Change-Id: I7d87c6c210015b33091876e6656f7c0116bc12ea
2025-11-24 16:31:29 +01:00
piegames 45e4bec59e tests/functional2/lang: Refactor test outputs
How long do we have the value printer already? It's time to stop
concatenating strings like it's 2005

Change-Id: I3f5074de2439a1ad78af94de877bb141bc9f1d82
2025-11-24 16:31:29 +01:00
Tom Hubrecht 0167bf56f5 libstore/getDefaultSubstituters: Add information when a substituters cannot be setup
Fixes #1034

Change-Id: Ic65ef955c4eb44766926e9b3ef4dcb4b94820a16
2025-11-24 12:08:30 +00:00
Tom Hubrecht 26de2b79c2 nix/develop: Set default outputs attribute
When using `builtins.derivation`, the `outputs` list can be omitted, and
in that case, it defaults to `[ "out" ]`, set this default when building
the shell derivation for `nix develop`

Fixes: #556
Change-Id: I4dc77d060f30ee499e186ec919de30bd3e5c53bb
2025-11-24 09:56:14 +00:00
Tom Hubrecht 395fe68127 tests/clang-tidy: Run on all supported platforms
Fixes #1013

Change-Id: I7388e4eb4728c34f2e21756438020e28b4f1cfca
2025-11-24 07:22:15 +00:00
Alois Wohlschlager 0f3a66f856 libstore: stop duplicating the unit in the retry message
Commit 5dc847b47b introduced usage of
std::chrono::milliseconds, which prints with the unit, leading to its
duplication. Remove this duplication again. Specifically, the explicitly
printed one is kept, due to better typography.

Change-Id: I724ea6be6f2a1349fe799602c3429f096a6a6964
2025-11-23 11:45:34 +01:00
Tom Hubrecht 748a975aa0 libexpr/builtins: Fixup scopedImport documentation
Change-Id: I01cbc628a0334a1d1e6347d987089262c08e7cee
2025-11-23 08:58:17 +01:00
Tom Hubrecht ea99f26b25 libexpr/builtins: Document fetchMercurial
Change-Id: Ic849bd6dd10374b717d3fc257da25208f2c45525
2025-11-23 08:58:17 +01:00
Tom Hubrecht 3cf5ad0164 libexpr/builtins: Document unsafeDiscardStringContext
Co-authored-by: eldritch horrors <pennae@lix.systems>

Change-Id: I4ebbbc9d32152f296a2553f2fd324dacf8af02d8
2025-11-23 08:58:17 +01:00
Tom Hubrecht fd273186c6 libexpr/builtins: Document appendContext
Change-Id: Ic45e0d4f6f1646552a7162bd8916f63fc11e5e62
2025-11-23 07:26:15 +00:00
Qyriad be18b7dc25 parser: improve error message for missing semicolon in inherit
Before:
  error: syntax error, expecting ';'

After:
  error: syntax error, expecting ';' to end 'inherit' bindings


Change-Id: I47c633cb5c696b646840c58e03270a7d6a6a6964
2025-11-22 16:48:53 +01:00
Qyriad b3e24cb3e5 new option: abort-on-warn
Co-authored-by: Emilia Bopp <contact@ebopp.de>

Change-Id: I3c3347e51d8543fbeb2b4e6ed12b0f556a6a6964
2025-11-22 16:48:53 +01:00
Qyriad 2d85d4c7b6 new option: debugger-on-warn
Co-authored-by: Emilia Bopp <contact@ebopp.de>

Change-Id: I5e20304538dd3e27fb36c32c0a6133cd6a6a6964
2025-11-22 16:48:53 +01:00
Tom Hubrecht 94ca4fd7b4 treefmt: Add meson/clang-tidy to the list of files checked by ruff
Change-Id: I3141286069844588a721cd4e523a284ef3a359c8
2025-11-22 13:19:40 +01:00
Commentator2.0 b707403a30 tests/functional2: migrate eval.sh
Change-Id: Ib5fb9e3b5d76612e7259ec17fb890298198fc885
2025-11-21 17:35:47 +00:00
Commentator2.0 40416d103f tests/functional: remove the now fully migrated lang framework
We have done it!
The functional/lang framework has fully been migrated to functional2 :D

closes: #856

Change-Id: I63ad8d7dbcd9b5267ca04af68df73b1ffa3d6461
2025-11-21 17:02:35 +00:00
Tom Hubrecht 8558cf781a libexpr/builtins: Document derivationStrict
Co-authored-by: eldritch horrors <pennae@lix.systems>
Co-authored-by: Qyriad <qyriad@qyriad.me>

Change-Id: I4cf95683da54efe830514f3a6795057cadd223c6
2025-11-21 14:59:03 +01:00
Tom Hubrecht 428a0bcb5e nix/run: Move argument parsing in the ifdef
Most of the arguments are only used on linux platforms

Change-Id: Iab79a3edf346257a2cd1c6e18ead2f1f77c7cc6d
2025-11-21 11:56:38 +00:00
Commentator2.0 9be0c2ee15 releng: issue references are now lix issues by default
After multiple cycles of deprecation, we now use the lix repositorty as
a default, when no prefix is defined

Change-Id: I29b445fee39fb20c0ff024e3b95402f459144b62
2025-11-20 18:03:45 +00:00
Qyriad 6192cbebac libexpr: refactor fallibly doing stuff on debug traces (NFC)
Change-Id: I009ce2ea424938507223fc6b3cf3b1236a6a6964
2025-11-20 17:52:29 +01:00
Emilia BoppandQyriad 0ade82d23a libexpr: add builtins.warn
Added builtins.warn` which takes two arguments: a message that is
displayed as a warning during evaluation which must be a string and a
value that is returned from the expression.

The next commits add new settings to control the behavior of the new
builtin: `debugger-on-warn` allows the user to start the debugger and
`abort-on-warn` aborts evaluation with an error.

Unlike upstream, I chose not to mark evaluation warnings from
`builtins.warn` as distinct from other warnings because that breaks the
commonly expected logging format `level: message`.

Co-authored-by: Qyriad <qyriad@qyriad.me>
Upstream-PR: https://github.com/NixOS/nix/pull/10592
Fixes: https://git.lix.systems/lix-project/lix/issues/579
Change-Id: I8658c88e5c27952b65e8b9f5525a572e0680cc1f
2025-11-20 17:52:29 +01:00
chris dd3ba39384 docs: fix broken link in basic package management section
Change-Id: I278e46b77a53af9ac1a65b213d5289fb6e63e7c2
2025-11-20 14:47:51 +00:00
Tom Hubrecht 170f092ce2 gc: Unify UX across the 3 cli ways to collect garbage
There are currently 4 different ways to run garbage collection using
lix:
- `nix-collect-garbage`
- `nix-store --gc`
- `nix store gc`
- (using the daemon directly)

As they were written all at different times, their output varies (and is
broken in some case). This unifies the display of informations in the
following ways:

- The list of paths in the results is always printed (in the nix3 cli it
is hidden unless `-v` is passed)
- The number of paths in the result set is always displayed
- The size of deleted paths is only shown when actually deleting things
(as it would have been 0B in any case)

Fixes #905

Change-Id: I40d9ec7c6d76795f6c6dd30df196d1e855bdb9db
2025-11-20 11:53:18 +00:00
Tom Hubrecht ff231b9b52 libexpr/builtins: Document addErrorContext
Change-Id: I94eee0ccba3fcdc587783800d59ac572ed44f69a
2025-11-20 09:25:10 +00:00
Tom HubrechtandEelco Dolstra f01555105a libexpr/builtins: Document scopedImport
This also allows removing a static initialization of a primop.

Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
Change-Id: I74da68205630f658b239e4327bf5e27bfc1b91da
2025-11-20 09:25:10 +00:00
Justin ! 2a308bca00 libexpr: remove fetchClosure exp feature
fixes #1010

Change-Id: I149cd01bf08655c91dc2d3817954937c6a6a6964
2025-11-20 08:45:29 +00:00
Lunaphied 2c73f3c492 cq: improve derivation printing configuration
Change-Id: I7f16afa921cf2a33f750cb0f5cc53fa36a6a6964
2025-11-19 20:52:38 +01:00
Lunaphied f3b2f3496b repl: allow :p to print derivation attrs.
Change-Id: I6a6a6964a58c3340acca9272c616c079c5218d6e
2025-11-19 17:46:52 +01:00
Tom Hubrecht 04a4b15991 libcmd/copy: Check the validity of the options if required
This is done at the start of the command call, which allows not building
expensive things if the arguments are incorrect anyway.

Fixes #687

Change-Id: Ic924fe2115cf760684c6fdf7987279e96ab00286
2025-11-19 14:45:52 +00:00
Qyriad 1fa8df82df libutil: include LIX_MAJOR, LIX_MINOR, and LIX_PATCH macros
Fixes #1038

Change-Id: I7d8a4648890fce7ff15695876c9b9d3a6a6a6964
2025-11-19 11:47:20 +01:00
Commentator2.0 1b7ad3a7ad tests/functional2: Migrate symlink-resolution
the newly added f1/lang tests is required for the f1/lang framework
dismanteling to happen in a separate commit

Change-Id: Ic419c515262294c51a46d1513daa7848e4b71405
2025-11-18 20:01:23 +01:00
Commentator2.0 2497e0101e tests/functional2/lang: Migrate builtins.pathExists
Change-Id: Ib31b7dddc71ae36924822f300b028bf354f63874
2025-11-18 20:01:23 +01:00
Commentator2.0 3eeb5d10ba tests/functional2/lang: fix warnings
While the err file should always be empty, we prefer not have (easily
avoidable) warnings in the log, in order for actual warnings to be
spotted more easily.
Additionally this way no additional changes are required in case they
make use of some depreacted features in the future.

Change-Id: Ie078e2a851b2035d839f6b95d4188e475eb96b2d
2025-11-18 20:01:23 +01:00
Commentator2.0 c589a95546 tests/functional2/lang: Migrate builtins.getEnv
Change-Id: I9e30d9bf897854e8843194779034fd98d172bcf1
2025-11-18 19:52:17 +01:00
Commentator2.0 4da70ab3bd tests/functional2/lang: Migrate eval-okay-xml
Change-Id: Ib626c3f4ca38b618bab368f0d23829debc5ec38b
2025-11-18 19:52:17 +01:00
Commentator2.0 68a39b1d6e tests/functional2/lang: Migrate builtins.derivationStrict
Change-Id: I42781af8b5b4a2352e867a07712a752ddfdeaa35
2025-11-18 19:45:15 +01:00
Commentator2.0 86964fb440 tests/functional2/lang: Migrate path-string-interpolation
Change-Id: I6f5d1830363c8dff4fa6b368550c8c4247766609
2025-11-18 19:45:15 +01:00
Commentator2.0 8d75a61f73 tests/functional2/lang: Migrate builtins.addDrvOutputDependencies
This also marks the end of eval-fail-* migrations

Change-Id: If06a60cd9d222bba5fc4f9a9b93de125e7fa2994
2025-11-18 19:45:15 +01:00
Commentator2.0 89a9d6e529 tests/functional2/lang: Migrate string coersion for integers
Change-Id: I428c8935119b3184109b3e3f760ed72054b0cd00
2025-11-18 19:45:15 +01:00
piegames daefbb8a44 tests/functional2/lang: Migrate more builtins
Change-Id: Ib981a5c544748475cf98a8daae0609a52c9c6eb9
2025-11-18 13:48:32 +00:00
piegames 2df8dc1178 tests/functional2/lang: Migrate string-context tests
Change-Id: I8c8f691f77eb87b52343d52a1c2a8a255ea2c887
2025-11-18 13:48:32 +00:00
piegames dbb6098ff4 tests/functional2/lang: Migrate attrs tests
Change-Id: I8eee261d76d34c4a138bc24d9c2b9a0dfb944c7f
2025-11-18 13:48:32 +00:00
piegames a852ceb0c8 tests/functional2/lang: Migrate autoargs
autoargs get their own folder and are not allowed with the other
function args tests, just like they deserve their own ring of hell

It shall be noted though that this test is particularly pointless, as it
merely tests the normal argument passing (which is fine), and not the
magic autoargs actually provide

Change-Id: Ia2dc00754a13c02e4926200141f90bc797820a15
2025-11-18 13:48:32 +00:00
piegames d470530ec7 tests/functional2/lang: Migrate lists
That one is a bit confusing, as I renamed the old `in` test to `in-2`
(file identities in Git when)

Change-Id: Id0e17de414dbc1b1b616d456175704f98657a16a
2025-11-18 13:48:32 +00:00
piegames 68fdce3548 tests/functional2/lang: Migrate eval-okay-patterns
Change-Id: I46e155ed2cc1ffcb75935fc1744c7938af22c0c6
2025-11-17 22:10:11 +00:00
piegames db59bb63c8 tests/functional2/lang: Migrate eval-okay-print
Change-Id: I70936bcf324dbb8b45a3c65567b6c25f409d7953
2025-11-17 22:10:11 +00:00
piegames 1dc174b4df tests/functional2/lang: Rename ind-string → string-indented
To make it easier to find them and increase locality

Change-Id: I6365e91d2c79362c05b766415cc1972346d7a610
2025-11-17 22:10:11 +00:00
piegames 7a005ebe5d tests/functional2/lang: Migrate eval-okay-backslash-newline-*
It's a string test, so in the string ~~hole~~ folder it goes

Change-Id: Id70da8a7a3de328bc94d2106a53eb7484c4ef122
2025-11-17 22:10:11 +00:00
piegames e6a672d024 tests/functional2/lang: Migrate builtins.toXML
Change-Id: I31f47b9953ef0370dd8e57f6e43ee32d278c3663
2025-11-17 22:10:11 +00:00
piegames ab764d9831 tests/functional2/lang: Migrate builtins.compareVersions, builtins.parseDrvName
Change-Id: I82bbe7f406aa37bc5493c58a8f8bfa5820503632
2025-11-17 22:10:11 +00:00
piegames 776bb81e28 tests/functional2/lang: Migrate builtins.readFile
Change-Id: Ib4d6b0af7e012297692b602cbaafef6a0480129b
2025-11-17 22:10:11 +00:00
piegames 4aedfd346f tests/functional2/lang: Migrate builtins.readDir
Change-Id: Ic70e4ef7780281f403d0421d63ecf849e083c01e
2025-11-17 22:10:11 +00:00
piegames c350bf8b5e tests/functional2/lang: Migrate builtins.readFileType
Change-Id: I7f6c4cddb8d969cb45652e1f72c0001a0ebd2d38
2025-11-17 22:10:11 +00:00
piegames e7bd41ece6 tests/functional2/lang: Migrate search-path test
Change-Id: If7513252cff92831822438753a78c2e9f80ac06b
2025-11-17 22:10:11 +00:00
piegames ca41ea5e3b tests/functional2/lang: Migrate builtins.seq
Change-Id: Ifeb975c0569b196e44054d23c20d22c0481ea3af
2025-11-17 22:10:11 +00:00
piegames 8b33caa506 tests/functional2/lang: Migrate builtins.path
Change-Id: Iefe96d38f89bc730b8e673069f9eb0bd3546accf
2025-11-17 22:10:11 +00:00
piegames 449ddbe324 tests/functional2/lang: Migrate builtins.toJSON
Change-Id: Ic740ab1fe0792c7e7596ae8a9beb9e76b37d6284
2025-11-17 22:10:11 +00:00
piegames eba84b51d6 tests/functional2/lang: Migrate builtins.fromTOML
Change-Id: I80d4058f3b74e9815425499e21afce5fc5dc6375
2025-11-17 22:10:11 +00:00
piegames 721db28037 tests/functional2/lang: Migrate eof tests
Call it a bug, call it a feature, but the old testing framework
ungracefully shits itself when it has no tests to run … in other words,
we finally migrated all the parse-fail tests 🎉

Change-Id: Ibd7f1c04d9a396a20f14361af7924f0074d1ac23
2025-11-17 22:10:11 +00:00
piegames cbac63cfe5 tests/functional2/lang: Migrate builtins.fromJSON
Change-Id: I7828e006eb31f7e4976fcac10ca3529b6b29a700
2025-11-17 22:10:11 +00:00
piegames cb29f3b060 tests/functional2/lang: Migrate merge-attrs tests
Change-Id: Ib8b8e4505454c5061d596dd490db43471bfb754b
2025-11-17 22:10:11 +00:00
piegames 5f7e032d28 tests/functional2/lang: Migrate eol tests
Also slightly refactor the existing crlf test to better fit in

Change-Id: Ib4dfa4b3318b3dd55a12d99a9f4908cdf1bce08b
2025-11-17 22:10:11 +00:00
piegames b912f91f62 tests/functional2/lang: Migrate with tests
Change-Id: I3a6c2fb38569711d717f8488c7a949a4afbea675
2025-11-17 22:10:11 +00:00
piegames 1a5fddbf99 tests/functional2/lang: Merge tests
Change-Id: Ia62b1b558e67b18c1998207824271826b9a707db
2025-11-17 22:10:11 +00:00
piegames 59dd03bc39 tests/functional2/lang: Migrate undefined-var tests
The second test has also been fixed. I'd do it in two commits if
functional1 wasn't such a PITA (guess why we're doing the migration …).

Basically, the introduced syntax got changed later on, but the test
never got updated, and back then tests didn't test the output so nobody
ever noticed it now failing for a wrong reason.

Change-Id: I5b66127d507c65676b8dd4a82d1e1f2857fef145
2025-11-17 22:10:11 +00:00
piegames 108beda9ae tests/functional2/lang: Migrate another weird regression test
A link to an issue would have come really handy …

Change-Id: I44495a5e193c0bfbf9e905271025b7321daa84c6
2025-11-17 22:10:11 +00:00
piegames fef822494e tests/functional2/lang: Drop trivial "parse-okay-1"
This really looks like one of the first tests ever written, it doesn't
seem to be actively testing anything interesting

Change-Id: I442840db932203c25da2d8400ada791f8aed04ce
2025-11-17 22:10:11 +00:00
piegames d864159f34 tests/functional2/lang: Migrate url-literals test
Change-Id: I9096037b3e246dc6e63adcc8f327398bf14518a5
2025-11-17 22:10:11 +00:00
piegames 5bbd2946fa tests/functional2/lang: Migrate let tests
Change-Id: Ia3fc85dafbfd706d719f1766544f836df23ef7c9
2025-11-17 22:10:11 +00:00
piegames ad5d044b35 tests/functional2/lang: Migrate builtins.foldl'
Change-Id: I244751eee4881794f7a5b810e19e7d19f1257999
2025-11-17 22:10:11 +00:00
piegames 7bb79d0ae6 tests/functional2/lang: Migrate rec-set-overrides tests
Change-Id: I2ffc949773188d9b98629df87ac0d2fbf7b2ee6f
2025-11-17 22:10:11 +00:00
piegames fdfe21954f tests/functional2/lang: Migrate builtins.unsafeGetAttrPos tests
Change-Id: I6b1bd29bd03467715c985ae7ecb50c584ed48e11
2025-11-17 22:10:11 +00:00
piegames d0ef150349 tests/functional2/lang: Migrate builtins.hashFile tests
Change-Id: I2e1c1af59daf8c976877f5ec09153464e7480aea
2025-11-17 22:10:11 +00:00
Jade Lovelace 08b0ce8736 Begin the 2.95 window
Change-Id: I4ea8a649248a692deb73b40048a219ed61c1ae91
2025-11-17 13:33:35 -08:00
Jade Lovelace 54118efaf6 release: merge release 2.94.0 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: Ida5959473ec469dd5e5e977ebdc8aab6e694b0de
2025-11-17 11:42:20 -08:00
Jade Lovelace fd38f625e6 release: 2.94.0 "Açaí na tigela"
Release produced with releng/create_release.xsh

Change-Id: If2ac30e569759c9035a6fc999c631ec545d190fa
2025-11-17 11:42:19 -08:00
Jade Lovelace 49a5495cbc release: release notes for 2.94.0
Release created with releng/create_release.xsh

Change-Id: Id7c776dc0ed46b1f6f09db2c77e04166469f5710
2025-11-17 11:42:12 -08:00
Jade Lovelace b6a8e312e7 2.94: release name
Change-Id: I18f5abe00130b53053e3a04074617071c0f884a2
2025-11-17 11:41:57 -08:00
WeetHet 7d46e9db7e libstore/build: extend DNS configuration access in network sandbox
https://github.com/NixOS/nixpkgs/pull/451579 PR
enabled c-aresSupport for curl on darwin which ended up breaking
DNS resolution in FOD sandboxes:

```
nix-run> exporting https://tangled.org/@weethet.bsky.social/nix-run (rev 73d7bf6b58848fb8f42e3a69816e0847f041c689) into /nix/store/m4m951648wmipxgwrgsml9gzjwfpfhm7-nix-run-73d7bf6
nix-run> Initialized empty Git repository in /nix/store/m4m951648wmipxgwrgsml9gzjwfpfhm7-nix-run-73d7bf6/.git/
nix-run> fatal: unable to access 'https://tangled.org/@weethet.bsky.social/nix-run/': Could not resolve host: tangled.org (Could not contact DNS servers)
nix-run> fatal: unable to access 'https://tangled.org/@weethet.bsky.social/nix-run/': Could not resolve host: tangled.org (Could not contact DNS servers)
nix-run> fatal: unable to access 'https://tangled.org/@weethet.bsky.social/nix-run/': Could not resolve host: tangled.org (Could not contact DNS servers)
nix-run> Unable to checkout 73d7bf6b58848fb8f42e3a69816e0847f041c689 from https://tangled.org/@weethet.bsky.social/nix-run.
```

with these sandbox failures:
```
deny mach-lookup com.apple.SystemConfiguration.DNSConfiguration
deny file-read-metadata /private/etc/hosts
deny file-read-data /private/etc/hosts
```

We allow those so that DNS resolution work fine

Change-Id: I9102293691972feb085adf8e9b1ad915bb3a36ab
2025-11-17 19:37:08 +00:00
Raito Bezarius 7e193f962e libstore/filetransfer: support HTTP/3 transfers if the user requests it
This adds the enablement code to support HTTP/3 if the user requests it.

We leave it disabled because h3 is not onpar with h2 performance.

Change-Id: I1fd3d4c97b972dcf36bccacc6c9a8290e22b31e0
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-11-17 19:11:32 +00:00
adam fb4cc15f39 chore: update nixos channel URLs
Channels have moved from `nixos.org/channels` to `cnannels.nixos.org`.
This udates all relevant links (excluding release notes) to use the new
canonical URLs and replaces HTTP with HTTPS.

Fixes #1031.

Change-Id: I212821c44ac5e482c8e9eaa415c7d8ee17ff8341
Signed-off-by: adam <me@adamperkowski.dev>
2025-11-15 18:21:47 +00:00
Alois Wohlschlager 243836ed0a libutil: remove the no-url-literals experimental feature
URL literals were deprecated in 278fddc317,
effectively stabilizing the experimental feature. Enabling it has no effect any
more. Remove it.

Change-Id: I8fbca03b1a2be6a8cddfce644043ac0a6a6a6964
2025-11-15 15:54:39 +01:00
Raito Bezariusandeldritch horrors 5fd9c65a8f doc/manual/known-issues: init
We start this section with shortcomings of unsandboxed builds.

Fixes #1018.

Co-authored-by: eldritch horrors <pennae@lix.systems>
Change-Id: Ieb17e4340beab0c1197951813ae602de453a3fd9
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-11-14 21:36:48 +01:00
EmilyandQyriad 82463616f9 libstore: skip the nested build directory on Darwin
This is unnecessary because Darwin builds already cannot create
`set{u,g}id` files due to the minimal sandbox policy, because we can
forbid messing with the top‐level build directory directly in the
sandbox rules, and because Darwin builds can trivially avoid isolation
through temporary directories right now anyway.

This does regress the build directory isolation for builds with
`sandbox = false`, but I can’t imagine that mattering given the
above. The sandbox change prepares us for a world where we close
off shared temporary directories for `sandbox = true` builds and try
harder to achieve proper isolation on Darwin, but probably doesn’t
have a meaningful security impact one way or another for now.

With this change, we get down to 41 byte build directory paths on
Darwin, a ~2–3½ byte improvement over the old status quo. We can
also restore the 0710 permissions on Linux.

Change-Id: I6a6a6964a681c0365241fe7234831db656b76799
2025-11-14 14:58:15 +01:00
EmilyandQyriad e87e547a36 libstore: default to /nix/var/nix/b for build-dir
The minimum build directory length on Darwin with default settings
when we were still using `/tmp` was 22 bytes. Deriving build directory
names from my local store, the median and mode were 43, the mean was
around 44½, and the maximum was 127.

The switch to `/nix/var/nix/builds` over `/tmp` added a 15 byte
penalty, and the additional `/b` directory added another 2.

Now that we use opaque build directory names, the length is 48, so
we’re still at a ~3½–5 byte penalty over the previous status
quo. This change brings us down to 43, matching the previous median.

Note that these calculations do not take into account the fact that
`/tmp` is a symbolic link to `/private/tmp` on Darwin. Anything
that was canonicalizing paths would have had an additional 8 byte
penalty in the previous status quo that is not applicable here,
so we may already be ahead even without this change. If the more
opaque directory name here is undesirable, then that factor could
potentially help us squeeze by without. Alternatively, in combination
with dropping the `/b` on Darwin we could use `/nix/var/nix/bld` or
similar, but I feel that the paths in general are sufficiently opaque
that it should be okay to go with the shorter option here. Given that
some projects already had to reduce filename lengths to avoid this
limit even before the recent changes, I think it is best to try and
improve on the previous status quo.

Note that `/nix/var/nix/builds` will unfortunately not be cleaned up
on Darwin. However, we don’t clean up the directories inside it on
Darwin anyway, so hopefully that’s okay for now?

Closes: #913
Change-Id: I6a6a6964bffce7194bcddcaefb4c4a37569c7df5
2025-11-14 14:58:15 +01:00
EmilyandQyriad 13a37f1246 libstore: don’t include derivation names in build directories
They have variable size, which is bad for #913.

Change-Id: I6a6a6964870e984c66277c7556ff3c2bc34ddca1
2025-11-14 14:58:15 +01:00
EmilyandQyriad 1102cc180a tests: remove obsolete code to create custom build directories
We now do in fact do this and decide this.

Change-Id: I6a6a696493b288ed76d809122bda259dc0225846
2025-11-14 14:58:15 +01:00
EmilyandQyriad ea0a2c8e74 libstore: make temporary path prefixes optional
This is not the same thing as passing an empty string, because it
avoids the `-` separator.

Change-Id: I6a6a696451667cbf500914e2dfbca2a4646ff20b
2025-11-14 14:58:15 +01:00
EmilyandQyriad c5221e508f libstore: simplify createTempDir interface
We always use the default temporary directory, because
`createUniqueDir` has an interface nice enough to use directly for
the few bespoke uses.

Change-Id: I6a6a696450b7c0a0bd76655632fb14d7c5e38199
2025-11-14 14:58:15 +01:00
EmilyandQyriad b1cfb58187 libutil: use makeTempPath in createTempSubdir
This makes the paths more nondeterministic, but more reliably unique,
and lets us remove the retry loop.

Note that this adds random entropy to the build directory visible
inside derivations on Darwin and unsandboxed Linux. It was already
non‐deterministic in the presence of concurrent builds and similar,
but now we can reliably expect it to be different every time. On the
whole I think that’s a good thing, as it is impossible to ensure
a single consistent build directory and derivation outputs should
not depend on it.

Package reproducibility isn’t great on Darwin to begin with,
though, and the reproducibility bugs this will turn up in packages
will be more urgent to fix than when the build directory was mostly
consistent. A quick survey of my local store shows that many C, C++,
and Rust binaries contain build directory references, likely due to
use of `__FILE__` and its equivalents; non‐binary offenders include:

* Install logs included in the Rust and Cargo bootstrap compilers
* Example errors in the Rust documentation referencing build paths
* Configuration information installed with CPython itself
* Python 2 metadata from resholve’s closure
* Cython metadata
* Generated headers in Facebook libraries referencing source paths
* Generated CMake files in Facebook libraries referencing source paths

I haven’t built that much in this store since the last GC, so this is
probably only a small sample of the problems across the tree. These are
all instances of <https://reproducible-builds.org/docs/build-path/>,
though, and should probably just be treated as general reproducibility
bugs outside of contexts like the Linux sandbox where we can normalize
them away entirely.

I have implemented away build directory paths for C/C++, applied some
additional fixes for non‐`__FILE__`‐related issues in binaries
from ATF and LLVM, and fixed the derivation bug causing the CPython
3 issue, and will work on upstreaming these changes. Rust is working
on the problem upstream, with some temporary workarounds we can
potentially apply in Nixpkgs for now. The rest will require some
distributed effort.

Change-Id: I6a6a69645b4915c56c0fdef904aa81684e4136c6
2025-11-14 14:58:15 +01:00
EmilyandQyriad 6e7212bad7 libstore: simplify fallback build directory logic
This does change the behaviour when the global temporary directory
does not exist, but other uses of the global temporary directory are
already broken in that circumstance, and it should be fixed centrally
if the use case is considered desirable. The logic was not present
before the recent churn around build directories – it was added now
that Lix is taking ownership of the build directory in the store –
so this should not be a meaningful regression.

Change-Id: I6a6a6964e345ea6803226c5ad759e836de7cb0ed
2025-11-14 14:58:15 +01:00
EmilyandQyriad d23bf515a7 libstore: use makeTemp{,Sibling}Path more
Change-Id: I6a6a6964c885be6dea0a69ee3162fbf4b812471f
2025-11-14 14:58:15 +01:00
EmilyandQyriad 0b2fcd1bcd libstore: simplify makeTemp{,Sibling}Path callers
There is now no risk of race conditions on a system with a functioning
entropy source, and the bespoke prefixes are either redundant to the
default or unnecessary.

Change-Id: I6a6a69641211c6bb979ea48ad30aecb1a53d03f0
2025-11-14 14:58:15 +01:00
EmilyandQyriad d03b1eca57 libutil: use OS‐provided entropy for temporary filenames
Relax the constraints on keeping the exact same filename format to
provide a more robust source of entropy with a simpler interface
(as previously suggested by eldritch horrors). Using 128 bits of
OS‐provided entropy ensures global uniqueness and allows us to
skip any thought of gracefully handling the case where these files
already exist.

My microbenchmark that repeatedly constructed paths like this and
printed them out showed that this takes about 1.23× the time of
the previous implementation, both taking on the order of a couple
microseconds for one iteration. Since everything that uses it is doing
things more expensive than printing to standard output, the actual
performance delta is likely to be lost in the noise. If it somehow
becomes a bottleneck, it can be optimized without sacrificing the
guarantees by reading from the system RNG only to seed a thread‐local
CSPRNG like [ChaCha8Rand], but I think that’s very unlikely.

We also tweak the recommended way of creating a temporary file inside
a directory in anticipation of later changes, and rename the `suffix`
parameter to `prefix` (it’s a prefix to the random characters and
a suffix to the root, but this way is more consistent).

[ChaCha8Rand]: https://c2sp.org/chacha8rand

Change-Id: I6a6a69648502c746d13d8c3bd2768cbbf1b90466
2025-11-14 14:58:15 +01:00
EmilyandQyriad 9f3ba30783 libutil: extract Base32 helpers from Hash
base32Encode now takes std::span<std::byte>, with a base32EncodeStr
convenience wrapper which takes std::string_view.

Co-authored-by: Qyriad <qyriad@qyriad.me>

Change-Id: I6a6a6964f799dc84ecbfb55c7ca03a064cff71d9
2025-11-14 14:58:15 +01:00
eldritch horrors 2fa40c9de4 libstore: bring back some pointer equality nonsense
the change to shareable thunks also removed a few cases of pointer
equality checks that allowed structures containing functions to be
considered equal to other sets containing the same functions, even
if the sets themselves were pointer-equal themselves. *so* busted.

Change-Id: If87fdab658f9037ce2a654f69a9e3da6ae2f53e5
2025-11-14 02:56:53 +00:00
Qyriad 78bdc60c11 libutil: refactor Pos::getSource to Origin
Change-Id: I1501fceb9ff1e768c8f5c45b65d5638568babf63
2025-11-12 10:40:21 +01:00
Qyriad 3ad1af8a98 libexpr: add trace for if 'foo' errors in 'or foo'
Change-Id: I59365e4c1bf4aed71c008554eca0c9e6d085219d
2025-11-07 14:54:02 +01:00
Qyriad 2806613954 libexpr: refactor ExprSelect::eval
Change-Id: Ibb21dbd3c25649b3b301bc7baaa52a8aa938ebe0
2025-11-07 14:54:02 +01:00
Qyriad 2e7bfa4474 libutil: impl <=> for Pos::{Stdin,String}
Change-Id: Ieb5016a261f5a90bbf08b2afb69bb1c288d07ca7
2025-11-07 12:07:23 +01:00
Qyriad f39cbc5d60 libutil: replace Pos operator< with <=> and constexpr ==
Change-Id: I60080c416b2ee2b0efce4584cf13f37c0596d73d
2025-11-07 12:07:23 +01:00
Qyriad f00d720d83 libutil: refactor trace types and functions into their own file
Change-Id: I00fba6b382991322a083bedeaf169eb5a86f5aeb
2025-11-06 19:19:36 +01:00
eldritch horrors 1e386c3780 libstore: add usage hints to repairPath on daemons
we can't change the protocol to allow daemons to do this, and we should
not try to guess what the `auto` store uri means depending on whether a
command was run by root or not due to copious side effects and not even
being able to tell whether the `auto` store uri was given explicitly or
not. while `auto` may *technically* allow this via its naming we should
resist the urge to add a hack and fix the underlying protocols instead,
especially since repairPath should be a rare, superuser only operation.

fixes #888

Change-Id: I1b53245db226199f827a89a237a2ab9907c3f766
2025-11-06 15:10:34 +01:00
eldritch horrors 24054c1107 libutil: restore process context before subcommand exec
fixes #1028

Change-Id: Ic50b9cc0c65607cd96dd81fd770cda34b4caf9d5
2025-11-05 13:56:09 +00:00
eldritch horrors 0d24aee673 testing: drop compression from truncated nar test
some versions of zstd enable checksumming, some don't. don't use it.

fixes #1027

Change-Id: I06811072d9e56a682a792f084cf76a81c7b5b4ce
2025-11-05 00:02:10 +01:00
eldritch horrors f369c711dd libutil: prefer reporting libarchive source errors
if curl fails during a transfer and said transfer is piped through
libarchive we see very strange errors (#1009). in such cases we'll
want to prioritize reporting the source errors to allow debugging.

Change-Id: I8cc231257eca5b749471ecd38df15071170decc2
2025-11-03 23:35:42 +00:00
hexchen 57658b2146 tests/functional/daemon-trust: fallback to uid
The test would fail if the identity cannot be determined
(as is the case e.g. when using auto-allocate-uids under darwin).
Instead we use the uid when the user name is not available.

Fixes: #1025

Signed-off-by: hexchen <hexchen@lilwit.ch>
Change-Id: I12f35840b78f989b5fd09bbd44c833dc6a6a6964
2025-11-03 18:24:07 +01:00
Raito BezariusandQyriad d4f404ded3 nix/doctor: test whether the current profile generation points somewhere
This helps users to debug whether their current profile symlinks are
correctly set.

Expected outputs look like this:
```
❯ sudo ./outputs/out/bin/nix doctor
[snip]

[PASS] All profiles are gcroots.
[PASS] Client protocol matches store protocol.
[INFO] You are trusted by store uri: local
[FAIL] Error: current generation cannot be discovered for profile:
'/nix/var/nix/profiles/default'
```

```
❯ ./outputs/out/bin/nix doctor
[snip]

[PASS] All profiles are gcroots.
[PASS] Client protocol matches store protocol.
[INFO] You are trusted by store uri: daemon
[PASS] You have 28 generations for profile
'/nix/var/nix/profiles/per-user/raito/profile'
The current generation number is '290'
```

Change-Id: I50c69cbeac3291d668f4c2332803411579adc944
Signed-off-by: Raito Bezarius <raito@lix.systems>
Co-authored-by: Qyriad <qyriad@qyriad.me>
2025-11-03 14:41:47 +00:00
Qyriad a30d87eadc nix/doctor: skip inaccessible PATH elems for duplicate nix
Inaccessible-but-extant PATH elements can't be executed anyway, so we
can skip them as if they didn't exist, instead of erroring like before.

Change-Id: I9288c3ecb6768171e62a3088122d98421558eb03
2025-11-03 14:41:47 +00:00
Qyriad d15b99f489 libstore/static-init: don't crash if nixBinDir exists but isn't accessible
In d2696cdd¹, libstore was made to prioritize NIX_BIN_DIR/nix (over
/proc/self/exe) if it exists. But `pathExists()` throws an exception if
lstat() returns any error other than non-existence.

Because this check happens in libstore's Settings constructor for the
static-initialized global `nix::Settings`, this case would abort Lix
well before main().

[1]: d2696cdd1e

Change-Id: I62e44c8a33b28c234900df3e4790c1badefee358
2025-11-03 14:41:47 +00:00
Commentator2.0 acf6e1c6b7 tests/functional2/file_helper: add a way to interpolate environment variables into files
So far it was impossible to put absolute paths into files, as one
wouldn't know whre the test would be placed.
This commit adds a new Fileish variant called `EnvTemplate` which uses
the given string as a template and replaces the `@ENV_VARIABLE_NAME@`
placeholders with the according value of the environment variable.
This way one can use `@HOME@` or `@TEST_ROOT@` to build absolute paths

Change-Id: I425cb6408dceb8d7f26d136ace4ac98b1ca31ec3
2025-11-03 12:58:37 +00:00
Raito Bezarius 85db5e3bf4 libstore/store-api: rate-limit concurrent copies based on system limits
Since we have async, we are unleashed and therefore we started to cause
people to run into system limits like number of open files.

We introduce an async semaphore which uses max(25 % of max open files,
max number of cores) which should lead to 256 maximum concurrent copies.

We believe that the copy operation is the only one that can cause issues
given that the daemon already runs with obscene fd limits.

Fixes #1022.

Change-Id: Iec433d10d5c5003962ea749cf8e32bafb314f0d9
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-11-01 23:47:13 +00:00
eldritch horrors f5ae0d1eff libutil: fix EBADF when cancelling decompression streams
relying on the sink/source code is a mistake. no exceptions.

Change-Id: Ied4ffc4065ce628ed7f8397526cdb68c8ac652d8
2025-11-01 20:42:12 +00:00
Raito Bezarius df862c1655 libstore/s3: attach more information to error messages
In case of empty messages, it is good to print the raw error code.

Additionally, we print request IDs which can help users to reconcile
what happened with the service provider.

Change-Id: I4d83c011c1b7a5514e3d1b21123df38308279044
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-11-01 21:17:26 +01:00
Raito Bezarius ccf196d7f4 libstore/s3: resolve completion status via the transfer status callback
Completion status can be updated in two ways:

- progress callback
- transfer status update callback (esp. important in multipart
transfers)

It's guaranteed that one of the two will provide progress for our
promise.

This fixes #945.

Change-Id: Iac9e92df34f82fbc1facae7a411ccabf1688da52
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-11-01 21:17:26 +01:00
Raito Bezarius 91867941fa libstore/s3: sign payloads if the request demands it
This fixes problems with S3 implementations that have mandatory payload
signing, e.g. Garage v2, AWS S3 itself, etc.

The problem manifested itself when the AWS SDK threw some error codes 99
(NETWORK_CONNECTION) with no messages and retried until it finally came
to a moment where the state machinery decided to send a
`Transfer-Encoding` header in a `Content-Encoding`/`Content-Length`-set
request with signed headers (even though payload signing is disabled),
causing the server to reject the transfer and crash the copy.

I did not debug super far what went wrong in AWS SDK, but I can confirm
this change makes transfers possible to finish with Garage v2.

Change-Id: Icc9e6a9f2afb0d760cf2d1e27816decd385a1d85
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-31 20:01:14 +01:00
Commentator2.0 9ed75192ec tests/functional2: fix crash on empty nix.nix([]) calls on darwin
Calling `nix.nix` with an empty argument list, would crash on darwin due
to a Index Out Of Range Error, as the build="auto" functionallity would
try to access the first element of the provided arguments (second
element at the place of call) resulting in a crash

Change-Id: Ia678109808b3f75a30182114baa421cedaa8759b
2025-10-30 18:53:11 +00:00
Raito Bezarius 95f15cf94f libstore/binary-cache: default to zstd for compression
libarchive's xz offers single threaded xz compression which is very slow
and provides ~10-20Mbps compression speed in addition to maxing a core.

In exchange, it achieves optimal compression ratios among all our
compression methods.

Nonetheless, xz prevent the saturation of 1Gbps+ connections and slow
down significantly decompression for end users. As these connections and
faster hardware is becoming prevalent for cache servers and clients, we
offer to default to zstd.

Lix is a "compress once, decompress many times" application. To avoid
incurring a high penalty to end users very sensitive to compress ratio
(very slow Internet connections), we dampen the consequences of
switching to zstd by increasing the default zstd level to 12.

On one example, xz will compress a 4.4GB file to 632MB, zstd on 12 will
compress it to 775MB, that is a ~18 % increase over the optimal xz
compression. zstd took 18 seconds to produce this file.

Increasing to level 14 leads to a 773MB file while taking 37s.
Increasing to level 16 leads to 735MB file while taking 66s.

Finally, xz took 77s, so a 50 % reduction in time taken to compress in
exchange of an increase of 18 % of the compressed size.

This change will reduce issues encountered in #945 but is probably not
the root cause.

References:

- https://discourse.nixos.org/t/switch-cache-nixos-org-to-zstd-to-fix-slow-nixos-updates-nix-downloads/23961

Change-Id: I7beda2bf2c1fed146dcb797b8f85dc290c486ab2
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-30 15:10:10 +01:00
eldritch horrors 047aad9992 libstore: fix s3 promise fulfiller lifetimes
if a promise for an async s3 operation is cancelled is inner fulfiller
will be destroyed, but the s3 operation may still be running. once the
operation finished and attempted to fulfill the promise we'd segfault.

Change-Id: I603c75d6cc39a1aee465b3ceee06b638f7f7f596
2025-10-30 13:57:15 +01:00
Raito Bezarius 1f08eaeb55 doc/manual: provide more information about Pasta and its shortcomings
As we saw actual users running into them throughout the debugging of
#920 and #1014.

It's best to document and point end users to this so they can take
measures for themselves.

Change-Id: I7d08407f4354055bf65fc6dd7d1624c5a9304402
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-30 00:04:21 +01:00
Raito Bezarius 480c8e52b6 libstore/linux/pasta: always list an IPv4 & IPv6 nameserver
Fixes #1014.

Address family detection is performed by Pasta, we influence Pasta into
enabling dual stack by listing both an IPv4 & IPv6.

Change-Id: I4121e0eae7d5185c287957106adc36edf3f82a40
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-29 21:44:12 +00:00
Raito Bezariusandeldritch horrors 12b87538e3 lix/nix-shell: cleanup of shell directories happens in Lix itself
Instead of letting inner shell perform the cleanup, we will fork/execvp
and finish the work ourselves. Once an interruption arrives, we wait
again and return the exit status code of the inner shell.

This idea was suggested by eldritch horrors.

Fixes #1020.

Co-authored-by: eldritch horrors <pennae@lix.systems>
Change-Id: Id38af7ac33874aa1c4b7ca9c6123e3cbd8c3cd8c
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-29 20:13:23 +01:00
Raito Bezarius f6d723b22f lix/main: return the legacy command statuses
This was forgotten which should have been part of 64b9247f.

Change-Id: I3cf83d8699f2c1963ce530bbea6a511075202a79
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-29 18:53:00 +01:00
Raito Bezarius 64b9427f98 legacy/nix-build: return exit codes
Legacy commands "main function" will now return an exit code.
Fun fact: `main_nix_build` was the only one not returning integers
already.

Change-Id: Ia43a16c3c3fb9a670e8889aefc4ee9b6528a7df4
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-28 20:38:39 +01:00
Raito Bezarius 56b4ed3908 libmain/main: propagate status codes via return values for mainWrapped
This also prevent `legacy` to return nothing as it's void.

Change-Id: Ic797544a59b04b41ad9e1c46af4cad3a1cb6fdc8
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-28 20:38:39 +01:00
eldritch horrors 2c176afa7a libutil: don't allow interactive runProgram2
realistically only runProgram is ever called for interactive reasons,
and even those calls seem to be rather ill-advised in many cases. the
chance of multiple interactive processes interfering with each other,
whether for input or for output, must be very low to make this in any
way reasonable: if e.g. git calls ssh for multiple fetched inputs and
ssh requests passphrases for both we can otherwise not guarantee that
*any* input is routed correctly. misrouted output is merely annoying.

Change-Id: I794e3fdf0a3238cb9292003a89ac267f0de7a939
2025-10-28 11:53:33 +00:00
Qyriad 9523446901 libexpr/libutil: summarize derivations in stack traces regardless of --show-trace
Eval errors will now print a simple, no frills chain of involved
derivations at the bottom. For example, trying to evaluate
`pkgs.xonsh.override { python3 = pkgs.python2; }` has the usual

Package ‘python-2.7.18.8’ in /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/pkgs/development/interpreters/python/cpython/2.7/default.nix:398 is marked as insecure, refusing to evaluate.

message, but now also includes the following:

       note: trace involved the following derivations:
       derivation 'xonsh-0.19.9'
       derivation 'python2.7-xonsh-0.19.9'
       derivation 'python2.7-setuptools-44.0.0'

To give the user information about why the erroring derivation was
involved in the first place.

We would like more structured information in the future, but this should
still be a significant improvement.

Change-Id: Icf6da52abd0a043cfb63943bf0b0c160c21ee59e
2025-10-27 20:28:27 +01:00
Commentator2.0 73c019c57b tests/functional2/lang: allow adding requiring of global assets like config.nix
Change-Id: Ia740b91fb3d18f7d01c0d551196b71e7f3e46384
2025-10-27 17:07:47 +01:00
Qyriad 836caf1173 libutil: add concepts for constraining iterables ("ranges")
Change-Id: I5d75abb9d3713a3fab863666786aa8d38cc93dbd
2025-10-27 13:16:29 +01:00
Qyriad b8462562f2 libutil: allow moving Trace into Error
`pushTrace` now move-constructs or copy-constructs, instead of always
copy-constructing.

Change-Id: Ie5f02643e98b7a6c1adbe58b0d46d9e116eba28e
2025-10-27 13:14:50 +01:00
eldritch horrors 18efc848fe libstore: move curl-multi wrapper into own class
the wrapper is needed by transfer streams to restart a failed transfer
if desired. curlFileTransfer itself is more of a fancy handler for the
thread we're dedicating to curl io handling. the thread will stay with
the multi handle for now because quit handling needs to stay there. we
could have CurlMulti keep only a flag, but that does not help us much.

Change-Id: I99550f0bbb635b75898ca7260f08275df86050e3
2025-10-23 22:52:09 +00:00
eldritch horrors b460a7a38b libstore: move curlFileTransfer::TransferItem up
we have anonymous namespaces and no other scoping requirements, we can
move it out. this will also make it easier to move *other* things out,
such as the transport streams and all the shared multi state handling.

Change-Id: Iafa1eaeb69e096e98c4667f0531b17d5fe7c78a6
2025-10-24 00:16:15 +02:00
eldritch horrors 253ed1cc05 libstore: abort all transfers when shutting down curl thread
waiting for them to finish leaves us prone to deadlocking, e.g. if some
active transfers is blocked and hasn't been destroyed before our thread
was asked to exit. aborting transfers is the safer option here; even if
we cause use after frees we'll at least have a crash, not hang forever.

Change-Id: I333dcced810e8a85e2ded1f377962a0176798098
2025-10-22 17:36:21 +00:00
Raito Bezarius e0d2fa89d3 libstore/build: resolve symlinks beneath settings.caFile
This behavior existed before I32f8b5ce20fe9b6a911768114c92f95fc886cc07
was introduced.

It was remarked in
https://gerrit.lix.systems/c/lix/+/3765/comment/1ff0b2b7_ae67ab1b/.

Change-Id: I7a72e7c36c6043a6c2cb8cab57ad45a552d5e2b6
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-22 13:23:48 +00:00
Alois Wohlschlager 7a0b8834a4 Reapply "functional2: fix in the development shell"
This reverts commit 3ef7e0711b.

Change-Id: I5b76d2c2e9b0dd669818c7218493d3e76a6a6964
2025-10-22 07:41:46 +02:00
Alois Wohlschlager 0e0853cc70 functional2: handle unset or empty BUILD_TEST_SHELL properly
If BUILD_TEST_SHELL is not set or empty, None or the empty string respectively
should not make it into the PATH. Ensure this property.

Change-Id: I4ce9b0c06c407b465308b63b9cb64e7d6a6a6964
2025-10-22 07:41:46 +02:00
eldritch horrors 5346b2bc68 libstore: simplify worker child handling a bit
we no longer need the optional wrapping.

Change-Id: I742cca23753c6e0a97ada0b301bb42f442803ea8
2025-10-20 12:43:22 +00:00
eldritch horrors 31b6eb2786 libstore: convert build-hook logging to rpc
Change-Id: I0c20f89de113dce6032c93a32e9fcd43b4478f55
2025-10-20 12:43:22 +00:00
eldritch horrors 5b7ed433d6 libutil: add logging rpc definitions
this is still somewhat experimental and should be considered in flux. we
will have to nail down a logger interface once we start moving the store
protocol to rpc, but until we do that we can use build hooks to test it.

Change-Id: Id20cd346c9520f45871799c31b0af040adde56ef
2025-10-20 12:43:22 +00:00
eldritch horrors 2d2cd7ac03 libutil: always rethrow kj::CanceledException
the fiber runtime requires this for correctness.

Change-Id: I5ebc6a046596403e86cebaa95962053ff7813877
2025-10-20 12:43:22 +00:00
eldritch horrors bab44b870e libstore: handle log size limiting in only one place
extracting the size-specific log handling into a new sink deduplicates
the size-limiting code and lets us clean up the derivation goal a bit:
a number of log-related fields we kept only because previous ownership
semantics were a lot more ad-hoc can be moved into the new sink class.

Change-Id: Ie770a276597c84f9d928a9624c0f0de86adfe815
2025-10-20 12:43:22 +00:00
eldritch horrors 4b9723a23f libstore: DerivationGoal::{handleChildOutput -> wrapChildHandler}
we'll want to remove handleRawChildStream from DerivationGoal, but the
timeout handling is still important. the wrapper is thus useful, but a
more generic way to pass it a promise to do the handling is necessary.

Change-Id: I55bf041d51e4f8a8b8291deae053423d06724329
2025-10-20 12:43:22 +00:00
eldritch horrors b02a66d13e libstore: simplify hook instance handling
we never need the connection or the rpc client directly after the hook
is constructed, only the hook instance rpc object. wrapping them using
kj primitives makes this more explicit and prevents destruction errors

Change-Id: I7e0b14d7e365c2e001273e04c0e741ba4afb12f2
2025-10-20 12:43:08 +00:00
eldritch horrors 6c416ff2ca libstore: make build hook exit status reusable
this makes it possible to wait for the hook to exit in one place,
process its exit status for some purpose, and later process it in
another place for a different purpose. rpc will need this to shut
down a hook cleanly after the hook has completed its assignments.

Change-Id: I5af2d5aac4b02a0a200d720d0e6f0b5df5496aaf
2025-10-19 16:09:32 +00:00
eldritch horrors 7e171a4abe libstore: localize act, builderActivities
only LocalDerivationGoal needs these, and once the child is done
running (or is begin torn down) we can just destroy all of them.

Change-Id: Id4d9f0105aaf33d6736c435bb891d3f9af8e7894
2025-10-18 21:33:54 +00:00
eldritch horrors 0365d17d7e libutil: disallow implicit ref downcasts
wtf?

Change-Id: I3dbce7052e72525c9430efb0f5090b168db04750
2025-10-18 21:33:54 +00:00
eldritch horrors 641769414b libutil: add a timed wait to async mutex
wrapping the wait in a timeout at the call site is insufficient because
a timeout would not relock the mutex and leave the raii object invalid.

Change-Id: I0be2aaf6b3c9966070fb0f1deaab048765fd7af3
2025-10-18 21:33:54 +00:00
Commentator2.0 2541db5321 tests/functional2/lang: fix expected skip message
it seems like pytest is updating the message printed when skipping a set
due to no parametrization
which leads to breakage on staging-next.
this commit changes the expected message to allow both old and new skip
message

Change-Id: I34d11ad84d7075911d8229fbc89889bb880a27c9
2025-10-18 17:19:01 +02:00
Commentator2.0 0ac71ea1cc tests/functional2/lang: fix wrong unused file error for generic test group collection
Change-Id: I1c548fcebe45d2a6621987091e3a852b8a9b5765
2025-10-18 11:24:00 +00:00
Commentator2.0 4fcfdc66fe tests/functional2: migrate debugger.sh
Change-Id: I82c5b739db09530ff216c91608be2f70a2036e11
2025-10-18 11:23:43 +00:00
helle e8d281eac6 doc: information at the use-cgroups option on conflicts it can give
as discussed on Zulip and with Lunaphied

Change-Id: I7c6b3e7994c1e7961033e3daf509c81348927baf
2025-10-18 09:51:36 +00:00
K900 6e2edbff93 flake: only apply the monotonic clocks patch to capnp<1.2.0
1.2.0 already includes it so building on unstable fails.

Change-Id: Iefa49203c371e5bab164c06b9da6f89a89ce7cfe
2025-10-18 12:04:06 +03:00
eldritch horrors a55fe35dac apply capnp patches again
This partially reverts commit f68233ec43.

while more modern capnp in *does* have the build system changes, it
does *not* have the patches. and those patches are rather important
to us; the clock patch because our CI machiens don't behave the way
capnp expect and the nodiscard patch because it *is* a bugsquasher.

Change-Id: Ic273777f09fd8e5e7001f815db8998dae2dd7b88
2025-10-17 19:21:17 +00:00
EmilyandQyriad 6ea1d8e37e libstore: use makeTempSiblingPath in replaceValidPath
Change-Id: I6a6a69641a3b4e6fdd076faac44dc314e6cc057e
2025-10-17 18:41:58 +00:00
EmilyandQyriad 39ebb982ea libutil: add makeTempSiblingPath helper
The prospective callers of this should probably be doing something
smarter or more abstracted to begin with, but this is useful as an
incremental improvement for call sites with existing `makeTempPath`
logic in the face of filename length limits.

Change-Id: I6a6a69644292f5bbf984a1df90192e06c6022b53
2025-10-17 18:41:58 +00:00
EmilyandQyriad d9eead0eac tests: add fetchTarball test for symlink temporary directories
Change-Id: I6a6a6964dfe85b5ee4f66b8c442fe448c7c5c87c
2025-10-17 18:41:58 +00:00
Qyriad 013d5e54e9 libstore: fix non-awaited calls to optimisePath()
LocalStore::optimisePath() was made asynchronous in 38b75b736¹, but we
lost warnings for not awaiting kj::Promise in f68233ec4², since our
capnproto no longer has the [[nodiscard]] patch.

[1]: 38b75b7367
[2]: f68233ec43

Change-Id: I2363396949f40dd43eae08cc76be9ede6b488cf7
2025-10-17 18:41:43 +00:00
eldritch horrors 20ba2b49fb testing: mock ssh during nix-copy prompt test
we don't need full ssh, we only need to know something makes it onto the terminal.

Change-Id: Ic31808e10e1b876b35d0dbdeee0b5ede7b5b9883
2025-10-17 15:13:37 +02:00
eldritch horrors ab9dddfb7a libutil: wrap async kj exceptions as errors
this is important for rpc error reporting: if the peer disconnects we
want to throw a useful error that can e.g. let pending builds finish,
not kill the entire process because kj errors are non-lix exceptions.

Change-Id: I41ebe10ad7fd65d886238ce52eeca1fa243b1bb2
2025-10-17 11:33:00 +00:00
eldritch horrors 21d7cb8e1c libstore: initialize build hooks via rpc
this removes another file descriptor from the build hook. we are now
using only rpc to communicate between build hook and daemon, setting
the stage for a future world in which we don't even need build hooks

Change-Id: I706d9d3f2a420abd42fc7762c205931a45d3c8c5
2025-10-17 11:33:00 +00:00
eldritch horrors 9b886e2acf libstore: remove unused DerivationGoal::machineName
interpolation of the remote store name into activity text is now done in
the build hook, so we no longer need to send it back to the daemon. this
also reduces the dependency of the daemon on how *exactly* remote builds
are done a little bit, and maybe in time we can make these fully opaque.

Change-Id: Ie51c4f2cd107350fec4ad0a8ef83621ed86db6a2
2025-10-17 11:33:00 +00:00
eldritch horrors 711ad52776 libstore: move logSize into each log handler
there's no need for this to be an instance variable of the goals.

Change-Id: Iaa315e8b5d8649d8eb3c3fedc387c0f0c48945fc
2025-10-17 11:33:00 +00:00
eldritch horrors 645a0533eb libstore: move sandbox log handling to LocalDerivationGoal
only local builds can now have a builderOutFD, remote builds only log
via json streams. these two kinds of logs have different requirements
and each is only needed by its respective build kind. splitting these
apart thus makes sense, though ideally we'd also split DerivationGoal
into a RemoteDerivationGoal to clean up the rest, but that will wait.

Change-Id: Ib577537266d1160355ab9c44b4604ebda87a7d04
2025-10-17 11:33:00 +00:00
eldritch horrors a824877d45 libstore: don't treat legacy ssh like a sandbox
treat it like ssh-ng instead, and have the build hook do the translation
of ssh stdout to the json log message steam the derivaiton goal can use.
since the ssh-ng path also handles all store urls that aren't legacy ssh
we now have a single logging system that handles every remote build kind
equally, without requiring fd passing into the build hook. this is later
required to rpc-ify the log stream emitted by build hooks to the daemon.

Change-Id: Ifb522eb8a9745029050f16b1b3b3601a6ddac748
2025-10-17 11:33:00 +00:00
Alois Wohlschlager ac8209404c nix-eval-jobs: estimate memory usage using the heap size
When the maximum memory size is chosen too large (relative to the free memory
usage), so that the evaluation workers don't fit into the free memory, they
will start being swapped out. Further increase in memory usage will not be
reflected in the RSS, so they will not exit, and instead fill up all swap too
until the system runs out of memory.

The BDW-GC keeps track of its heap size, including any parts of it that may be
swapped out. For this reason it does not suffer from a similar problem. While
not all memory usage by the evaluation worker is accounted for by the GC, a
simple affine model for the overhead works reasonably well in practice. The
specific parameter values were determined using nixpkgs evaluation, and appear
to work quite well also for somewhat different workloads (like the `hydraJobs`
of Lix, which include a bunch of NixOS system configurations). So this is what
gets used.

When Lix is configured without the BDW-GC, of course this approach cannot be
used. In this case the old strategy is retained.

Change-Id: I6cb5f0a9b4ceda9dd14be165dda108cd6a6a6964
2025-10-16 15:22:54 +00:00
Alois Wohlschlager ed9cc5f448 nix-eval-jobs: move more worker initialization code to its file
Change-Id: Ief8b16220c153e402ecbdeabd576344c6a6a6964
2025-10-16 15:22:54 +00:00
Alois Wohlschlager e36ac58f93 nix-eval-jobs: hide hidden flags in the --help
Right now there are no hidden flags so this does not matter, but this will
change very soon.

Change-Id: I6d65ce9c32170b6d4f4a691ff9f8806a6a6a6964
2025-10-16 15:22:54 +00:00
eldritch horrors a85115bd33 libutil: add a log line splitter
we'll need this in other places too soon.

Change-Id: I8ddd57aefa4cbd1f8f7232f35e30a204ace77e58
2025-10-16 12:31:08 +00:00
eldritch horrors daff1b148f build-remote: de-optionalize an always-set parameter
Change-Id: Ifd79229cf5f608e3cfe5532ab24b2a4efb547e15
2025-10-16 11:51:27 +00:00
eldritch horrors cac395ffbc nej: fix some clang-tidy lints
these are really annoying when running `just lint` with nej enabled.

Change-Id: I8d35e77fe9905fdd6c28f95361f7431459079b96
2025-10-15 20:27:28 +02:00
eldritch horrors 59b583b46d n-e-j: disable darwin ci
it's a disaster. cf #1015

Change-Id: I4671c1ea0f1b6b2750b97cf3c42497460ef33259
2025-10-15 13:37:18 +00:00
helle 30a5f8ec15 doc: Mention Buildkite in the hacking document
Includes link to the Buildkite SSO login, which is currently not visible
anywhere else in documentation.

Change-Id: Ic3ec6412127b2ac0df7e6efc4ec6020cc9d8b34f
2025-10-15 09:21:49 +00:00
Jade LovelaceandCommentator2.0 faa0b4f291 functional2/http_server: add some example misbehaviour routes
Part of https://git.lix.systems/lix-project/lix/issues/949.

This also fixes a bug where our SO_REUSEADDR wasn't done before bind was
called and thus didn't work as intended.

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>

Change-Id: Ie69fd594a32d7a6f538fb66d9d2cac6fe117d563
2025-10-13 18:30:51 +02:00
Jade LovelaceandCommentator2.0 556012e409 functional2: forbid chdir and setting environment
These are a footgun and are not acceptable in functional2 due to thread
safety, effects on other tests, etc.

Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems>

Change-Id: I8d7285061eaa9bab27edd52f3646024c8cf605e5
2025-10-13 18:30:51 +02:00
Commentator2.0 844feb17b5 tests/functional2/lang: fix duplicate collection when both err and out are provided
When providing both a `.err.exp` and a `.out.exp` for a lang test
**not** containing a toml, the test was collected twice and hence threw
a duplicate id error.
This commit adresses this issue

Change-Id: Ia781d69e0f1db2809a30192d6cd0a98861e6cc32
2025-10-13 14:33:25 +00:00
eldritch horrors 2e3d97eb37 libstore: move currentHookLine into handleHookOutput
Change-Id: I00cdc7fae1b953f2d541bc966d15afa00c04b06a
2025-10-13 11:26:49 +00:00
eldritch horrors 26e8e3caac libutil: allow builders to create all activity types
this restriction was added in 4af2611bd1
and extended later. it makes little sense to allow *one* activity type
specifically and drop all others on the floor, especially since broken
builders can create transfer activities with ids that would be used by
other, "real" activities. the only thing achieved here is to drop logs
written in json format in the build sandbox, which does not help much.

we may revisit this restriction later during other log-related rework.

Change-Id: I8bda494083877b71a2f958470fa52380f6ec4968
2025-10-13 11:26:49 +00:00
eldritch horrors b04521e4ec libstore: move log handling fully into handleBuilderOutput
it was split up like this only because the old worker system had no
promises. since we have them now we can use them for encapsulation.

Change-Id: Idbd523eff617d4c53c14b125ab3dfce4979cdab1
2025-10-13 11:26:49 +00:00
eldritch horrors 1210a4e025 libstore: flush log lines only from handleBuilderOutput
also change the tests to ensure that we handle all lines correctly.

Change-Id: I13de286bda8eee57acd53af1ab5c081d3048b500
2025-10-13 11:26:49 +00:00
eldritch horrors f29dfb3d3c libutil: add buffer state management to loggers
currently all loggers can always accept messages and never suggest
flushing buffers. in the future this may change, and at that point
we're already fully set up for it. local loggers should never keep
asynchronous (i.e. network-backed) buffers, disk buffers are fine.
networked loggers will require buffers and periodic flushes later.

Change-Id: Ide2114f5bc17f4a1d289c92ed4f9381a1d59dacf
2025-10-13 11:26:49 +00:00
eldritch horrors 38b75b7367 libstore: make store optimization non-recursive
this keeps the call stack flat even for very deep store directories.
moving progress reporting out of the method optimizing one path also
lets us move the inevitable IO wait and associated promise overhead.

Change-Id: I5083d88b05c247c7e19a21a646bcf3f62bfa3200
2025-10-13 11:26:49 +00:00
eldritch horrors 34b1f362cd libutil: wrap activity updates in macros
we'll eventually want to yield to flush buffers from the non-sync versions.

Change-Id: I8bcbb1c4c8af39c7d7ebf5a76e1ce1dc98067e00
2025-10-12 22:37:31 +00:00
eldritch horrors b73a7f1815 libutil: clean up the Activity interface a bit
create activities from loggers themselves instead of passing the logger
as a constructor argument and allow direct construction of children, no
direct logger access needed. most call sites are not changed because we
still need to handle the "no parent" case, and the logger method can do
that more cleanly than a ternary at each site that creates an activity.
we may eventually want to create a root activity, which is cleaner too.

Change-Id: I295e056228dabb08a1316eba7973874784baa113
2025-10-12 22:37:31 +00:00
eldritch horrors 47000b658e libutil: don't trust RemoteStore activity ids
remotes can generate the same activity ids we might generate locally,
especially if the remote is accessed over the network. in that case a
pid collision is possible, and since activity ids are sequential it's
very possible to create colliding activity ids on both sides as well.

Change-Id: Id58074a41f5f7a59171b52818d1fb5a1beb4bf40
2025-10-12 22:37:31 +00:00
eldritch horrors ed034d0526 libutil: make Activity a real, move-only class
activities are scopes, and there's no reason scopes should not be able
to move around. this also means we can *create* them elsewhere without
also having to box them in some way, making parent relationships clear

Change-Id: I5df036e12ebd8270feb4dca1f23b6bee1f08e906
2025-10-12 22:37:31 +00:00
Lunaphied e9f6baedd1 libstore: add an informative message about disabling cgroups
Change-Id: I0271eff2f7a357af18ddd6ae0571d548a9adbe3e
2025-10-12 20:12:33 +02:00
Commentator2.0 d9c1c0925c unify version string between lix and nixos-module
Currenlty `lix` and `nixos-module` have slightly diverging version
numbering. This commit fixes the lix side of things, in accordance to
the format proposed in
https://git.lix.systems/lix-project/lix/issues/585#issuecomment-7336
which allows for better use of `builtins.compareVersions`

fixes #585

Change-Id: I2072b701f9fadf780e7aab67b62fbcd2ec5df76d
2025-10-11 18:47:46 +00:00
eldritch horrors b88a6e6f11 libexpr: use pascal strings for eval
this has no performance impact in any benchmarks we've run. nul bytes
are still used as implicit truncation points in many places all over:
rejecting them in all locations that treat them as a string end point
requires large changes such as using a proper path library everywhere

Change-Id: I936158bd435f6abf009a689adfbc24496262c578
2025-10-11 12:57:57 +02:00
eldritch horrors 53d172a308 libutil: remove unused CanonPath methods
Change-Id: Id593e0d03373af88e03a9da473935e5c00f86b33
2025-10-10 16:55:34 +00:00
eldritch horrors 2f16cf6014 treewide: lint syscalls for c string safety
Change-Id: I3caf476e59dcb7899ac5a3d83dfa3fb7ceaaabf0
2025-10-10 16:13:54 +00:00
eldritch horrors 3ef7e0711b Revert "functional2: fix in the development shell"
This reverts commit 42691f0d94.

Reason for revert: darwin builds time out now, apparently due to newly appearing infinite loops in the test suite

Change-Id: I81a09efd53636a287f3095ac87ed8854b6e57922
2025-10-10 12:49:45 +00:00
Commentator2.0 5e2412ea7e tests/functional2: migrate add.sh
Change-Id: I699929b61db19a4ab7bea8281df830de9fea6d04
2025-10-08 13:09:17 +02:00
Alois Wohlschlager 42691f0d94 functional2: fix in the development shell
The functional2 test suite was broken in the development shell for two mostly
separate reasons leading to "no such file or directory" errors:

* The `BUILD_TEST_SHELL` (already containing the correct path) would always be
  set from the Meson option `build_test_shell`, even to the empty string if
  that option is not set. Skip the overwrite in this case to make the
  environment variable work again.
* Sandboxed builds would fail to find their builder `/bin/sh`, since in the
  development shell busybox is not found, so no sandbox shell gets configured.
  Use the shell from `BUILD_TEST_SHELL` instead. (How this does not break the
  old functional tests remains a mystery.)

Change-Id: I6a6a696424e8caaef3f9b68e3738bfd58ea0b056
2025-10-07 20:14:48 +00:00
Raito Bezarius 41fab8a31c legacy/nix-store: do not crash on cache unsoundness
Local store make use of SQLite as a cache for output maps, they can
diverge with actual store reality.

Causing a crash at realization time.

We can just throw an error instead.

Change-Id: I943a4bddfd2461a34933e9ec079a6638ab58e5b1
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-07 13:35:42 +00:00
Raito Bezarius feab75bde0 legacy/nix-build: create various temporary directories into a known tempdir
Fixes fj#940.

When running `nix-shell`, the `$NIX_BUILD_TOP` environment variable is
set to `$TMPDIR` or `/tmp`.

nixpkgs stdenv uses $NIX_BUILD_TOP to create `$NIX_BUILD_TOP/env-vars`
which contains all the environment variables set by stdenv. This is used
for debugging purposes in combination with `--keep-failed` to reload the
bash environment of a derivation.

`$TMPDIR` is often unset, therefore, `/tmp/env-vars` was constantly
being created. On a multi-user system or, when you run Lix as root, you
might create a `/tmp/env-vars` with different permission bits.

As a result, `nix-shell` can cease to function because that file will
fail creation for an unprivileged user for example.

fj#940 rightfully remark that the code is not consistent between
nix3-develop and nix-shell and it should be reworked.

Change-Id: Iddf15945385d8bd497b2800b37fee5e1f97689b7
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-07 03:28:45 +00:00
eldritch horrorsandRaito Bezarius 7e665feae6 libexpr: make .debug_gdb_scripts aligned
This avoids mangling debug gdb scripts and breaking them resulting in no
script loading at all.

Change-Id: Ib5e7034c37a1e41d1a1c9bd8442b8b8b8758e350
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-06 23:00:40 +02:00
Raito Bezariusandeldritch horrors 7b6bcffe8b libexpr/genericClosure: de-ptr-ize UnsafeValueList
UnsafeValueList held pointers from Value which were not necessarily GC
allocated, causing mayhem when evaluating something with genericClosure
(texlive environments).

We get rid of storing pointers and we let comparison take places on
const references.

We keep `gc_allocator<Value>` so that GC can scan things it allocates
inside the `res` list.

Co-authored-by: eldritch horrors <pennae@lix.systems>
Reported-by: qbit
Change-Id: I4fed3a3d9e18a2ef2d751f32d81801540e196f92
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-06 23:00:40 +02:00
Raito Bezarius b5d31b7780 libexpr: CompareValues can take const references
Change-Id: I5ab1e9f71c2f066eb9bb39683ff00c5190c1fcd7
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-10-06 22:27:36 +02:00
eldritch horrors 14737888e0 libexpr: add a gdb script with value pretty printers
Change-Id: Ia4a6feb194c73dddf468c78287962713bef582f7
2025-10-05 16:23:05 +02:00
eldritch horrors 80654b84b6 libexpr: de-ptr-ize Value references
thunk values are shareable, and we can represent invalid/uninitialized
values with a special bit pattern that makes no sense otherwise. there
is no need to keep allocating values on the heap, instead we can treat
values like reference-counted smart pointers to heap objects, which in
turn lets us save a lot of allocations and, ultimately, gc heap space.

compared to our baseline (main of 2025-09-27) we save 15%+ memory on a
system rebuild and 17% on nix search. eval time regresses by ~3% for a
system rebuild, while nix search is 7% faster. further optimization is
probably possible (but for now this will just have to be good enough).

Change-Id: Ib6c47acdbe2fac4f76a83c2269f16f30ef66b2e1
2025-10-05 16:23:05 +02:00
eldritch horrors 28c4431c69 libexpr: reformat stuff we'll change soon
mainly to keep the next diff smaller. it'll be large enough as is.

Change-Id: Ib8a34520f03539cbf6aa2f0e66cbed05fe1225eb
2025-10-05 16:22:35 +02:00
eldritch horrors db35aa753b libexpr: de-ptr-ize many Value uses
with thunk state being shareable we no longer need to worry about value
uniqueness, only about value lifetime. this means we can liberally drop
indirections and allocations, passing references instead of pointers or
using stack memory instead of gc-managed memory for some intermediates.

Change-Id: I2d48a6fd57a376d544bd9bd2d05e5420611986d1
2025-10-05 16:22:35 +02:00
eldritch horrors 23df732ddb libexpr: remove ValueVector{,Map}
these typedefs were convenient in the past, but now they're not really.

Change-Id: I7522f7582ead545148af8e6444295d620ee0872a
2025-10-05 16:22:35 +02:00
eldritch horrors ad4c6b6eb1 libexpr: remove unused return types
Change-Id: Ief898b70f9781bd3dbe66734710f388daa2f2fed
2025-10-05 16:22:34 +02:00
eldritch horrors f4dee18693 libexpr: remove type punning in primt_attrValues
there's no measurable performance gain in real-world testing to abusing
our list value storage like this. we haven't tested how much storage we
actually need on the stack to offset most of the temporary storage cost
and used 128 as a "good enough" value instead, reserving 1 kiB of stack
space on 64 bit platforms in a leaf function. this should do for a bit.

Change-Id: Ie98519b1da3e6fe685da88d1c44ffb4580fb592a
2025-10-05 14:56:56 +02:00
eldritch horrors 8108e8a760 libexpr: tag Value::Acb
Value is already tagged. Value::Acb blocks are allocated for lambdas (so
we can fit the value tag into the three bits we have available), but the
current layout is rather wasteful for this purpose. the type bits can be
stored together with parts of pointers, which in the lambda case will be
the scope the lambda captures. the expr could also be used, but Env is a
gc-allocated item and thus guaranteed to be aligned properly for tagging

Change-Id: Ia685875387c7795bc4a00d73d1ce3cfea84e7297
2025-10-05 14:56:56 +02:00
eldritch horrors b19bbdfee1 libexpr: make thunk state shareable
this is a strong prerequisite for making values themselves copyable
without duplicating evaluation side effects. with this we can treat
`Value` the way we treated `Value *` to date and drop indirections.

Change-Id: I08f30d12697614a3ae7149615f6f1da83b13f52b
2025-10-05 14:56:56 +02:00
eldritch horrorsandRaito Bezarius 57333a0e60 libutil: preserve ForeignException type info
preserve type information of wrapped exception when constructing a
ForeignException. this requires using `std::current_exception` for
construction in all cases as passing the exception by reference to
any function erases dynamic type information: `throw` may copy the
thrown exception from its source expression; this only works as we
need it to if static and dynamic type of the expression are equal.

fixes #1000

Change-Id: I7167f298540de7c43c2566592bdb8d7a93c34d31
2025-10-05 00:40:22 +00:00
eldritch horrors dc99a5ea1f libexpr: reduce Value size to one pointer
Change-Id: Id6e4a2f68eaa4afdd006379ebcf839c4a126b819
2025-10-04 21:06:52 +02:00
eldritch horrors 0e9e9fd917 libexpr: heap-allocate "large" integers
Change-Id: Ic391f2f1bf87f044d7a688196ba9e0ad766d65aa
2025-10-04 16:31:45 +02:00
eldritch horrors 79586575c5 libexpr: heap-allocate app nodes
Change-Id: I9a39dcf0be7589cedf494757e21665c5d50e446b
2025-10-04 16:31:45 +02:00
eldritch horrors 94a866d44f libexpr: heap-allocate thunk control state
Change-Id: I20d8ab1d6f683c0a2f3b77edf9bdad147d62c8fa
2025-10-04 16:31:45 +02:00
eldritch horrors d84f3003cf libexpr: move lambdas to auxiliary storage
Change-Id: Ibe4885f17c0ba1634ed6dbca0a45f8bd4619d69b
2025-10-04 16:25:05 +02:00
eldritch horrors 1b5f4eb5eb libexpr: move primops to auxiliary storage
same as for null: we have few of them, they're statically allocated,
and they're not the largest contributor to the value population. not
storing them in Value itself frees up resources we *will* use later.

Change-Id: I521f9f243f48f56a78f7bffdf1dc1f0bc40a5c2d
2025-10-04 16:25:04 +02:00
eldritch horrors 05b80a5ba1 libexpr: move null to auxiliary storage
we only need the one object for it. there's no need to waste precious
bits of the value internal type enum for this simple singleton datum.

Change-Id: Ie314b5bf429015e518798d9d65ad8ab2bb84a38e
2025-10-04 16:20:07 +02:00
eldritch horrors 1d998a343b libexpr: move floats to auxiliary storage
floats are used very rarely, and our float support is bad enough to
strongly discourage using them on reproducibility grounds alone. we
can thus move them to more expensive storage without hurting folks.

Change-Id: I1086f612f85e294dd3fae4a2d334e09f52bbe4a8
2025-10-04 16:20:07 +02:00
eldritch horrors 4d7f468c87 libexpr: move external value refs to aux storage
external values very rarely appear during eval "normal" eval, and
creating them is pretty expensive. does *anything* even use them?

Change-Id: Id50fa3f76b7e1f551d550d99996a1ed5880b2531
2025-10-04 16:20:07 +02:00
eldritch horrors 90be3e34c9 libexpr: heap-alloc string control blocks
despite not using allocation caches this does not have a statistically
significant performance impact, with less than 1% extra memory needed.

Change-Id: Ibe51a55ba986e471f217f3724977af17880fafff
2025-10-04 16:20:07 +02:00
f1ef994f12 libexpr: enable parallel marking in boehm-gc
Using parallel marking in GC speeds up evaluation a fair bit

```
Benchmark 1: ./lix-main/bin/nix search nixpkgs hello --no-eval-cache
  Time (mean ± σ):     20.740 s ±  0.046 s    [User: 17.583 s, System: 3.062 s]
  Range (min … max):   20.678 s … 20.794 s    10 runs

Benchmark 2: ./lix-parallel-marking/bin/nix search nixpkgs hello --no-eval-cache
  Time (mean ± σ):     15.037 s ±  0.080 s    [User: 19.602 s, System: 3.125 s]
  Range (min … max):   14.960 s … 15.227 s    10 runs

Summary
  ./lix-parallel-marking/bin/nix search nixpkgs hello --no-eval-cache ran
    1.38 ± 0.01 times faster than ./lix-main/bin/nix search nixpkgs hello --no-eval-cache
```

Based-on: https://github.com/NixOS/nix/pull/13708
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
Change-Id: Ibc7625f21e0ee7c8ad66203eeb3aca5d83977731
2025-10-01 23:07:28 +00:00
eldritch horrors 1c4e77387a libexpr: remove tPrimOpApp
using the same nodes as tApp is possible, and thanks to multi-arg app
nodes it can even be a bit faster than the linked lists used to date.

Change-Id: Idccb7c0b54c808e62da85d1c42ee09e6e92c4f7b
2025-09-29 17:56:05 +02:00
eldritch horrors 0b5b14ddc7 libexpr: add multi-arg app nodes
these behave like the old chains of app nodes, but they can store more
than one argument per node. for tApp values themselves this is not all
that useful, but if we could share tApp and tPrimOpApp backing storage
we could avoid creating and traversing the linked lists of values that
are currently needed to represent partially applied builtin functions.

Change-Id: I5a2a02d9733e1e0be5443459e2998d62fd3b9a5b
2025-09-29 17:56:05 +02:00
eldritch horrors 3350ab8a56 libexpr: use std::span for callFunction
Change-Id: I8c94bafabdb2416c85d9721d3d6424f52fbd45e0
2025-09-29 17:56:05 +02:00
eldritch horrors 0d69da184c libexpr: unify strings and paths
paths already are just strings with slightly magic semantics. the type
can mirror that at no perf cost, letting us drop one internalType tag.

Change-Id: I98acaa4fe3bedd28fc0841e1b81184d8dcddacc5
2025-09-29 17:56:05 +02:00
eldritch horrors d23e3a09a4 libexpr: alloc list storage as a (length, vla) type
memory overhead is minimal and performance impact not measurable. once
we've done something like this for all value types that don't fit in a
single machine word we can cut a word from Value, offsetting the cost.

Change-Id: I9813bacd7e851957ad3426aed8f74033179a4212
2025-09-29 17:55:54 +02:00
eldritch horrors 01f1852360 libexpr: don't inline small lists into values
this has no measurable performance impact thanks to the new caches.

Change-Id: Ib403a9a567161675f78e8c5d314d6340183d181d
2025-09-29 15:22:41 +02:00
eldritch horrors 739624ddcf libexpr: cache more allocation sizes
we now use a single cache set for a number of sizes from one to eight
words. this also matches small attrsets, but perf impact seems small.

Change-Id: Icf16b329b98a20fcc9fe75e6395e148f0852c798
2025-09-29 15:22:41 +02:00
eldritch horrors c7cc7d6c31 libexpr: "hide" Value union members
on its own this is not very useful, but having accessors for every value
kind is a prerequisite for doing smart things with Value than the union.
the net effect for now is only to add a few parentheses across the tree.

Change-Id: I88688ac09eb08495dad1eb221034ca540f094950
2025-09-29 15:22:41 +02:00
eldritch horrors 2dae1141d9 bench: add memory benchmark
Change-Id: I4b2aa305b452a3a0c73e37953a5c332219d43d2c
2025-09-29 15:22:41 +02:00
eldritch horrors f31e8e2b55 bench: allow benchmarking a single build
Change-Id: Ie77247f9348eaeea740b0f894819ee2383d92312
2025-09-28 13:35:37 +00:00
eldritch horrors e4ee5e2eb5 testing: disable substitution in f2
mirrors f1. much faster.

Change-Id: I38bbbd5b26220f480afe76ef9302e5c90f21507a
2025-09-28 13:19:13 +00:00
Raito Bezarius 992c3ae981 nix3/develop: support structured attrs-based output checks
nix develop should ignore output checks in general.

This was done only for the old way of specifying output checks, the
structured attrs way requires rewriting the JSON and removing the output
checks pieces.

We take a brutal approach of removing as many as possible including
non-recommended ways of doing it.

Fixes #997.

Change-Id: Iaf83029016c71b5171e56e15d4eadc1a60a8be98
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-09-23 14:35:08 +00:00
Alois Wohlschlager 43325669df daemon: let subdaemons outlive their parent again
In 7b37d5ea6a, aside from subdaemons getting
properly executed, they also lost the ability to outlive their parent, due to
now getting set the parent death signal like most other processes spawned by
Lix. This has annoying consequences like all concurrent builds being forcefully
terminated on system updates requiring a nix-daemon restart. As the behaviour
change was not documented and the systemd service file retained
`KillMode=process`, it seems to have been accidental. Restore the old behaviour
of letting the subdaemons outlive their parent.

Change-Id: I6a6a69645312a90dbce55495c2fef3825dd3c097
2025-09-22 19:51:58 +02:00
K900 f68233ec43 flake: unvendor capnproto
Nixpkgs has a recent enough version and all the relevant packaging changes now.

Change-Id: Ifdf814f80689803dd63ba7d16049e7d37e389542
2025-09-22 10:04:17 +03:00
Commentator2.0 1e69b17f0a tests/functional2: migrate timeout.sh
Change-Id: Ieb12c46bc987c74a6adda07e6c6ed33aebf8a96c
2025-09-21 17:56:19 +02:00
Commentator2.0 e0739afb42 tests/functional2: migrate build.sh
Change-Id: Iac3f3dc021436fc693a3729ba522d4bf1f124220
2025-09-21 13:58:26 +02:00
Raito BezariusandSergei Zimmerman a20a83b0a7 libexpr: replace Bindings::find by Bindings::get
In preparations for a new representation of bindings that will make it
impossible to write an efficient `Bindings::find`.

Change-Id: I4e5a25b8d37d01b5728f7fe43978ceda2ab1b9b6
Signed-off-by: Raito Bezarius <raito@lix.systems>
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-09-20 23:46:16 +02:00
Raito Bezarius 257e910247 libutil/comparator: support > for generation
Change-Id: Idd40b06c7051b9b0bd4c125359af0eb69996313a
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-09-20 23:45:41 +02:00
Raito Bezarius ccf3c5e30d libexpr/primops: make zipAttrsWith not mutate attribute sets
The way zipAttrsWith works is to replace the attribute set value by a
call to a function (the argument of zipAttrsWith) over the list of
attributes sharing a common key.

Instead of that, we will insert into the resulting attribute set the
various lazy calls and return that.

Change-Id: I2aae054eb99b1d1f8b0e7c658cc8d3488e5cdb01
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-09-20 23:45:41 +02:00
Raito Bezarius 19e4f11e88 libexpr/symbol-table: efficiently generate ≤, <, >, ≥, ==, != for Symbol
C++ has the "spaceship" operator which can be auto-implemented and
generates efficiently a strong ordering.

Change-Id: Idfd1fd68039b395e54401cbe913454e0cbd80fb3
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-09-20 23:45:38 +02:00
Raito BezariusandSergei Zimmerman 057b725ae3 libexpr: use const references or pointers to attribute sets
Prior to this change, references or pointers could be mutated. In
practice, we do not require this capability in the codebase except in
zipAttrsWith.

This cleans up all easy sites in preparation to have a smarter
representation of attribute sets albeit one that requires constant
references.

Change-Id: I2be20cce040a9228bde9e5f7b42c0499fba9550b
Signed-off-by: Raito Bezarius <raito@lix.systems>
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-09-20 20:31:19 +02:00
Alois Wohlschlager 3ee839cc5e libutil,nix: fix clashes with stdio stream identifiers
The stdio stream identifiers (stdin, stdout, stderr) are allowed to be macros.
In musl libc they are, for example doing `#define stdout (stdout)`, breaking
compilation with an error when one of the clashing variables is attempted to be
initialized the "wrong" way:

    ../lix/libutil/processes.cc:272:7: error: expected class member or base class name
      272 |     , stdout(stdout ? std::make_unique<AsyncFdIoStream>(std::move(stdout)) : nullptr)
          |       ^
    /nix/store/ziw42d7rvgnf3vkbfc8kry07kipwf1xm-musl-static-x86_64-unknown-linux-musl-1.2.5-dev/include/stdio.h:67:16: note: expanded from macro 'stdout'
       67 | #define stdout (stdout)
          |                ^

Other places only cause warnings on musl:

    ../lix/libutil/processes.cc:254:17: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'stdout' [-Wvexing-parse]
      254 |     std::string stdout;
          |                 ^~~~~~
    /nix/store/ziw42d7rvgnf3vkbfc8kry07kipwf1xm-musl-static-x86_64-unknown-linux-musl-1.2.5-dev/include/stdio.h:67:16: note: expanded from macro 'stdout'
       67 | #define stdout (stdout)
          |                ^~~~~~~~
    ../lix/libutil/processes.cc:254:17: note: add a variable name to declare a 'std::string' (aka 'basic_string<char>') initialized with 'stdout'
      254 |     std::string stdout;
          |                 ^
          |                  varname
    /nix/store/ziw42d7rvgnf3vkbfc8kry07kipwf1xm-musl-static-x86_64-unknown-linux-musl-1.2.5-dev/include/stdio.h:67:16: note: expanded from macro 'stdout'
       67 | #define stdout (stdout)
          |                ^
    ../lix/libutil/processes.cc:254:5: note: add enclosing parentheses to perform a function-style cast
      254 |     std::string stdout;
          |     ^                 
          |     (                 )
    ../lix/libutil/processes.cc:254:17: note: remove parentheses to silence this warning
      254 |     std::string stdout;
          |                 ^
    /nix/store/ziw42d7rvgnf3vkbfc8kry07kipwf1xm-musl-static-x86_64-unknown-linux-musl-1.2.5-dev/include/stdio.h:67:16: note: expanded from macro 'stdout'
       67 | #define stdout (stdout)
          |                ^

However they are still wrong, since the macro could be more complicated. Fix
them as well.

Change-Id: I6a6a6964a50ef7dec8f05f0bd8fc8f13f3036d51
2025-09-20 11:25:00 +02:00
Alois Wohlschlager a7e1b23165 libexpr: remove liblixexpr_mstatic
It was supposed to be removed in 480fdf146d, as
it is not needed any more with the prelinked library. Due to a mistake in
rebase conflict resolution it reappeared by accident. Actually remove it now.

Change-Id: I6a6a6964d175fdb0ba0ad9ac55d4d22d7b27ad3f
2025-09-20 08:30:35 +00:00
Commentator2.0 3a4f9488f0 tests/functional2: migrate nix_path.sh
Change-Id: Ibc4f848721d4da628c44aa074faf009c87af165d
2025-09-19 20:51:49 +02:00
Commentator2.0 fc2eedf9db tests/functional2: migrate why-depends.sh
Make builds work on darwin and migrate the first building test :D

Change-Id: Ia301c78d3bc771cd826d93dc114b098167043e97
2025-09-19 20:51:49 +02:00
Commentator2.0 a25a5739c7 tests/functional2: migrate search.sh
Change-Id: Id0f47fc72191d913442ff35d47df1b87ceb9f0be
2025-09-19 15:09:22 +02:00
piegames 2a622d7de7 tests/functional2/lang: Migrate value printing tests
Change-Id: I39303ef44552eb9fc17ccc2da5206c8906e46f27
2025-09-18 23:38:46 +02:00
piegames fe7a8d5e67 tests/functional2/lang: Migrate arithmetic tests
Change-Id: I73259875debc053dca46fe34f9f8d10b8486fa4f
2025-09-18 23:38:46 +02:00
piegames 096aa37cf1 tests/functional2/lang: Migrate ind-string tests
Change-Id: Ibc764ab97a53b751287654300211f3a9d8750b74
2025-09-18 23:38:46 +02:00
piegames 21a0b81a26 tests/functional2/lang: Migrate function args tests
Change-Id: Ia805d7fbf74c671fc419fb8c9db3960b6be62354
2025-09-18 23:38:46 +02:00
piegames f2b64142a9 tests/functional2/lang: Migrate dup-attrs tests
Change-Id: Ia5976229c8b2e6bf89d821b5676a9a397e4539d7
2025-09-18 23:38:46 +02:00
piegames 0d4a6132dc tests/functional2/lang: Migrate builtins.deepSeq test
Change-Id: I5caeb8a606d8cba519267c6011561afc9813598c
2025-09-18 23:38:46 +02:00
piegames 3692cf1ea2 tests/functional2/lang: Migrate inherit tests
Change-Id: I0f09f2b4ffa2edc5031351d0426865d7605ff7fa
2025-09-18 23:38:46 +02:00
piegames c7b8ac7cd9 tests/functional2/lang: Migrate substring tests
Change-Id: I902de6f3aebc902d56a79f8909bd6c9b5ba70cda
2025-09-18 23:38:46 +02:00
piegames 81baa64847 tests/functional2/lang: Migrate eval-okay-eq*
Change-Id: I17f81a765bbdbde3a27dd547e1ef65bffa97bce5
2025-09-18 23:38:46 +02:00
piegames 16db4da8f0 tests/functional2/lang: Rename tests
Most tests for builtins now have `builtins.builtinName` as their name.
This makes navigating the test list a bit easier

Change-Id: Ief5af5c568a419bf9130601f9590e7a696b0dc0a
2025-09-18 23:38:46 +02:00
piegames 5cfe785352 tests/functional2/lang: More trivial eval-okay test migrations
In the first pass I erred on the cautious side, only migrating safe
bets, to here's some trivial migrations that I missed

Change-Id: I934011919837b0aa491113afdcad603cf6b9cbbb
2025-09-18 23:38:46 +02:00
Jade Lovelace 0018b98859 codeowners: add some missing directories
Change-Id: I22aa53074dedd822517a5e8dfa2f0a520d0000bb
2025-09-17 16:26:49 +00:00
Alois Wohlschlager d63a31e7a9 Remove obsolete editline.patch
Its usage has been removed in 3936f9b5de but for
some reason the file remained. Drop it now.

Change-Id: I6a6a696420f3425587f82bd485c6307e1ccff08d
2025-09-17 06:09:44 +00:00
Commentator2.0 a9f28622c8 tests/functional2: migrate pure-eval.sh
Change-Id: Ieadb54a27b1cedcf3a4ce65e024a68440759ce7e
2025-09-16 20:06:07 +02:00
eldritch horrors d648ec55eb libutil: asyncify runProgram2 stdout stream
fun side effect: post-build hooks are no longer single-threaded!

Change-Id: Ie5c75e588e4b2b8d515d4f1ae36de45b0a0807f7
2025-09-16 16:10:59 +00:00
Maximilian BoschandJörg Thalheim d6b0b8b382 nix-eval-jobs: add --no-instantiate flag
Closes #987

The patch adds a flag `--no-instantiate` which only performs evaluation
without instantiating any derivations. Hence, GC root creation is also
skipped. To achieve that, Lix is also put in read-only mode and all
operations that require reading a derivation (e.g. constituents or
listing input derivations) are disabled fallback values are set.

This is a port of an upstream PR[1]. Given the divergence of the
codebases (different restructurings on both ends, no more CA derivations)
I decided to redo large portions from scratch instead of
cherry-picking the patches. Hence, the authorship.

Additionally the clean up of casts down to a local store are removed or
guarded behind an if, as done in the upstream PR.

[1] https://github.com/nix-community/nix-eval-jobs/pull/379

Co-authored-by: Jörg Thalheim <joerg@thalheim.io>
Change-Id: Ib84f44e7799bc5577fd2ee98912458f16ebeab81
2025-09-16 13:03:53 +02:00
eldritch horrors 812f466e0d libutil: asyncify runProgram
Change-Id: I397d02b1a993dc4f0c2dc2b2f90d0c1aebda4c2e
2025-09-15 16:18:01 +00:00
Marie Ramlow 8981fb5a18 meson: only require libatomic if the test program doesn't link
95448347 made lix require libatomic if the platform is able to link a
simple program using atomics, but it should actually be the other way
around. We need to require libatomic if it fails.

Change-Id: I6a6a6964ca6ee90a59314ddf1865753e83713772
2025-09-13 21:30:52 +02:00
eldritch horrors d90e4a6581 libutil: reject malformed nars harder with better errors
fixes #993

Change-Id: I56aff32498ecd32e65f1576661d5a15808a4439f
2025-09-12 23:22:11 +02:00
eldritch horrors 95d43d1e39 testing: unrace functional-repl
using sleep(1) as a synchronization mechanism does not work. use fifos instead.

fixes #690 and ci constantly falling over in the same exact fucking source line

Change-Id: I51725f8e439b6753f3212d2897dbb0620ad77a37
2025-09-12 23:22:11 +02:00
Sergei Zimmerman 88517c324f libexpr: slim down attrsets by 8 bytes on 64 bit systems
It's pretty bad that Bindings effectively wasted whole 8
bytes (4 for capacity and + 4 for alignment padding) to
store something it doesn't actually need. BindingsBuilder
allows the capacity to be checked at construction time,
after which the Bindings does not get mutated aside from
the ugly case of builtins, which doesn't get built all
at once.

For `nix search --no-eval-cache github:nixos/nixpkgs/e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870 hello`
this shaves off around 53MB allocations out of 2GB used
for attrsets in total:

<     "bytes": 2001170768,
---
>     "bytes": 1947398072,

<     "Bindings": 16,
---
>     "Bindings": 8,

Nix PR: https://github.com/NixOS/nix/pull/13919

Change-Id: I939c5ac545f5abbca048370dcf4936346339d75c
2025-09-12 19:23:38 +03:00
eldritch horrors b966d2e53b libfetchers: asyncify some git/hg internals
Change-Id: I3aea82173a610dc9584e956aa74d3e3ad06bfe68
2025-09-12 11:52:03 +00:00
eldritch horrors 9b01455ada libfetchers: asyncify Input{,Scheme}::{putFile,clone}
Change-Id: I084b6fc2271ea99a9325b1969f18b83778702bea
2025-09-12 11:52:03 +00:00
eldritch horrors 078e1d7245 libstore: asyncify LocalStore::findPlatformRoots
Change-Id: I173fae8aa17cb757b9c2aceadb4d68259a236b32
2025-09-12 11:52:03 +00:00
Qyriad 138c7161be nix3-develop: correctly escape ASCII control characters for JSON
Fixes #991.

Change-Id: Iafc7d9603fbc3615393d32d9630f0e8fe548950b
2025-09-12 09:42:20 +00:00
Qyriad ee91eec5cf libutil: add bashEscape, which escapes non-printing characters with $''
Change-Id: I23b416372677acb80bae9c124e9fd6d867e7af6d
2025-09-12 09:42:20 +00:00
Jade LovelaceandRutile b5cf7dff7b package: fix running pytest in a dev shell
I have no idea how seemingly I am the only one hitting this, but either
way, this fixes it.

Fixes: https://git.lix.systems/lix-project/lix/issues/964
Workaround-For: https://github.com/NixOS/nixpkgs/pull/435749
Change-Id: If2a7ad89f98f0054928868eabb62b35c2df28e6e
2025-09-11 19:15:51 +00:00
Marie Ramlow 95448347ea meson: link against libatomic if required
Some platforms like 32-Bit PowerPC need linking against libatomic.
Try to compile and link a very simple snippet of code which uses atomics
and make libatomic required if it fails.
Because we're using `dependency('atomic')`, the required meson versions
gets bumped to 1.7.0. See https://mesonbuild.com/Dependencies.html#atomic-stdatomic

Change-Id: I6a6a696471e1d352fb161c537ba9023b97c2d31e
2025-09-11 17:58:25 +00:00
eldritch horrors b04419e719 libutil: asyncify streaming unpackTarFile
libarchive is not async and cannot be used async without involving green
threads, which have already proven to be very problematic. unpacking tar
archives is rare enough that spawning a new thread for each shouldn't be
too much overhead, and the additional data copy probably also won't hurt
performance too much. we may even benefit from being able to extract not
just one archive per event loop but as many archives as we can keep fed.

Change-Id: Iece82bd566ada0a2a49de54c4e69caf6d93f6720
2025-09-11 16:36:52 +00:00
eldritch horrors 6f0bf9798a libstore: process post-build-hook logs directly
using a sink for this has long been a bit weird anyway. originally it
was necessary due to api limitations, but it hasn't been for a while.

Change-Id: I3dfa157944618349bfd6f398ee1667fc31519d86
2025-09-11 16:36:52 +00:00
Alois Wohlschlager 91bf54d726 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 16:50:37 +02:00
Jade Lovelace f4bdddf0fd tree-wide: log commands executed at --debug --quiet
Fixes: https://git.lix.systems/lix-project/lix/issues/973

Information about which commands were executed is really valuable to
debug Lix and is much more user relevant than the vast majority of the
e.g. build loop junk printed at debug level. Currently we have a *whole
lot* of call sites where we call execv* which should probably be cleaned
up, but that's future work.

I chose to print argv0 rather than the executable path if these differ,
since the code is shorter and since the command could be a fully
resolved symlink or so where argv0 is the actual command name being run.
However, it's not exactly *hard* to write std::ranges::drop_view(args,
1).

Change-Id: I73c3abb20b229d5e2d64277aa29cbbeed7764bab
2025-08-28 17:19:14 -07:00
Qyriad fe6395cd4d ci: add job to ensure static builds eval and configure
Static builds have broken and been fixed multiple times now[1][2]. It's
too expensive to add another "build Lix" job to CI, but a lot
of failures happen at eval time or during build configuration. We can at
least catch those.

[1]: https://git.lix.systems/lix-project/lix/commit/ac80a11300eb60006b7de90fb10ad6789e5beeed
[2]: https://git.lix.systems/lix-project/lix/commit/c82af241f58d7aeaecbb2a6d17bd8d7bfcc834ce

Change-Id: I5618f1ba7554324e60f4f510e70b1ccea6445f4e
2025-08-27 03:29:46 +00:00
eldritch horrors d5970d8a8b libutil: remove unused logger function
Change-Id: I8505346baa88b9f174707e127f1c78088238cf3e
2025-08-25 21:00:15 +00:00
eldritch horrors ed9a78fccd treewide: colorize logs by default
printTaggedWarning already colorized its messages. we can do the same
for most other log messages.

Change-Id: Idcd31bbf4f8d0d703395b0d2b7b9bc33264d969f
2025-08-25 21:00:15 +00:00
eldritch horrors 18285afa76 treewide: force log format strings to be literals
luckily none of these a format strings vulnerabilities because
boost::format is smart enough to throw an exception when given
fewer format string arguments than are requested by specifiers

Change-Id: I5fa78f0d1396263271f6e1dbcee9c0b2e9e18c34
2025-08-25 21:00:15 +00:00
eldritch horrors 466115c9c8 treewide: don't call Logger output functions directly
always use log macros, which also have the benefit of respecting the
verbosity setting without needing virtual function calls to read it.

Change-Id: I1c605562a53e54140724d5225e040abcf49ac996
2025-08-25 21:00:15 +00:00
eldritch horrors 4c6c01786f treewide: turn nix::warn into a macro
we add two variants: one that just prints a message at the warning
level (mirroring the other printer macros), and one that also adds
the colored "warning: " prefix the function added. since there are
no overriders of this function in tree it looks safe to remove it.

Change-Id: I7008fd0f31d59fbc9259472e29359c8df19ff87d
2025-08-25 21:00:15 +00:00
eldritch horrors 03ab20e191 libutil, cli: remove Logger::warn
only use the free function instead, so we can turn that into a macro.

Change-Id: I0319e9f7bdebb96f6159053e8b7b7a82559c9b33
2025-08-25 21:00:15 +00:00
eldritch horrors f40a60f46a libutil: make log macros usable outside of nix namespaces
mostly useful for nix-eval-jobs which currently has to call the logger
functions directly because its main code *isn't* in the nix namespace.

Change-Id: Ia8440d86a293d9006ffef2562b1859e9aaa79a62
2025-08-25 21:00:15 +00:00
Commentator2.0 9cdc2bf61c tests/functional2: migrate hash.sh
Change-Id: I5061479b972088c904ca1db4d9004e738c2b5a57
2025-08-25 21:29:27 +02:00
Alois Wohlschlager 451a14980b libstore: use OpenSSL for Ed25519 signatures
Previously two cryptography libraries were linked into Lix: OpenSSL used for
hashing and (in usual configurations) indirectly via curl for TLS, and Sodium
used only for handling the Ed25519 path info signatures. The latter is
functionally redundant since OpenSSL supports the same use case as well.
Reimplement the Ed25519 handling using OpenSSL and drop Sodium.

Fixes: https://git.lix.systems/lix-project/lix/issues/969

Change-Id: I6a6a696456b9d3ad7fdc2bf9b0759836a6247a38
2025-08-25 17:11:45 +00:00
Raito Bezarius 836644a7a1 libstore/build: put nix log command on its own line
This way, you can copy paste it easily.

Change-Id: Ie5799d1dea59f26cc0a1b3fde17d4449f49361c5
2025-08-25 09:51:07 +00:00
Raito Bezarius d6ccc6b89c libstore/build: make build errors extensible by children
Currently, DerivationGoal prints a pretty generic message.

For many valid reasons, children may have better knowledge of the detail
of what has happened and would like to extend the error message.

What we did is to printError at convenient places but this is
counterproductive because the build error can bury the notes.

This is still not perfect because there's no fine-grained structured
information that children can use to act upon the generic messaging, but
this is already an improvement for LocalDerivationGoal and keep failed
which will occur in the next change.

Change-Id: I5835cbbb30c4f2aa64abefb83999018d30ca4a0c
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-08-25 09:51:07 +00:00
Alois Wohlschlager 8d55251ebd libstore: remove StorePath::random
It was only used for impure derivations, which were finally removed in commit
be07629820. Delete the unused function.

Change-Id: I6a6a696481711f68a8c3ea7eac7978fcf5884cce
2025-08-24 19:34:20 +02:00
Commentator2.0andCommentator2.0 7b6a85982b tests/functional2: provide a way to easily access often used assets
Change-Id: I461ee08d9752d972e7485e15186426f98e68ba13
2025-08-24 10:38:39 +02:00
Maximilian Bosch e2641cb890 libstore/local-derivation-goal: show tree with references that lead to an output cycle
Closes #551

This adds a special accessor that falls back to checking if a store-path
exists within a chroot if it's not a valid path. That way,
`genGraphString` can find out which files have which references before
the outputs are registered.

Change-Id: I03c9d508fa3c72e5c262194461a25d71f3f4de15
2025-08-24 01:15:15 +02:00
Maximilian Bosch 4886e506f2 libstore: move LocalStoreAccessor definition to header
That way it's possible to inherit from LocalStoreAccessor to implement
special behavior such as an accessor that falls back to the chroot
directory if it can't find a store-path (which is what we'll do in the
next commit).

Change-Id: If689eb3f410e81e629f1d13cc2b48594fecb1001
2025-08-23 18:36:53 +02:00
Maximilian Bosch 10c04ce846 libstore/local-derivation-goal: create reference maps between outputs outside of topoSort()
That way we do now have linear complexity to determine output
references per output within each step of the topological sort.

Instead, this is done before and the topo-sort only filters the output
map for other derivation outputs.

Following up on this, we can re-use `outputGraph` to generate a tree
with references to display which files cause an output reference cycle
if needed.

Change-Id: Ibdd46e7b2e895bfeeebc173046d1297b41998181
2025-08-23 18:36:53 +02:00
Maximilian Bosch 2175d007e5 libstore/path-tree: allow passing a custom accessor
If none is given, we fall back to whatever accessor we get from the
store.

To display which paths actually contain the references leading to
e.g. a cycle or triggering a disallowedRequisites error, we'd
potentially have to look into the chroot from the previously finished
build. This behavior should not be part of the local accessor by
default, but part of a "special" accessor. This change allows using such
an accessor for `genGraphString()`.

Now that we inject the accessor from the outside, we have to mock it
anyways in the tests. Hence, this also adds a testcase for the
precise=True case.

Change-Id: I58465fb944776c2b0262ba054d1f296ed2ae3406
2025-08-23 18:36:49 +02:00
Maximilian Bosch 312e90f4b6 tests: add small testcase for output cycle detection
Change-Id: I186937dfbca4d051e5ad860239720816429a0a8e
2025-08-23 16:23:35 +02:00
Maximilian Bosch f7871fcb57 libutil/topo-sort: return std::variant<std::vector<T>, Cycle>
The variant has on the left-hand side the topologically sorted vector
and the right-hand side is a pair showing the path and its parent that
represent a cycle in the graph making the sort impossible.

The goal is to implement #551 which needs to throw an error if the
topo-sort fails. However, the error-message is supposed to contain a
graph of store-paths and the API to generate this is inherently async.

Now, catching the exception and re-throwing another one is impossible
since `co_await` is forbidden in `catch`-blocks and adding another
topoSort variant that allows an async `makeError` also seems odd. Hence,
I decided to alter the data-structure in use a bit for this use-case.
One out of two uses of the function are affected after all.

Change-Id: I70a987f470437df8beb3b1cc203ff88701d0aa1b
2025-08-23 16:23:35 +02:00
eldritch horrors be438c62e1 nix/eval: remove --write-to
it's broken, can write arbitrary file paths when run as root, and only
supports strings and recursive sets of strings. this was only used for
manpage generation in a build system that has not woken up since 1976.

fixes #974
fixes #227

Change-Id: I4f18599685a3077c15ddc02c759558f986c8c6e4
2025-08-23 10:39:30 +00:00
Alois Wohlschlager 0f50bc452e libutil: make backoffTimeouts inline
Commit 5dc847b47b introduced it as a non-inline
function with definition in the header, which can result in linker errors like
the following:

    /build/source/build/lix/libutil/backoff.hh:36: multiple definition of `nix::backoffTimeouts(unsigned int, std::chrono::duration<long, std::ratio<1l, 1000l> >, std::chrono::duration<long, std::ratio<1l, 1000l> >, std::chrono::duration<long, std::ratio<1l, 1000l> >)'; tests/unit/liblixutil-tests.p/libutil_backoff.cc.o:/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gtest-static-x86_64-unknown-linux-musl-1.17.0-dev/include/gtest/gtest-printers.h:1223: first defined here

This error was observed during trying to bump `lixPackageSets.git` in nixpkgs.
I am not sure why it can't be observed in the in-tree `nixStatic` package but
the definition is wrong in any case.

Change-Id: I6a6a6964e218a03ca2a2e8eddbb72d44e06e904e
2025-08-23 11:23:15 +02:00
Maximilian Bosch 5dc847b47b libstore: exponential backoff for downloads
Closes #932

`connect-timeout` gets replaced by an exponential backoff for the
download timeout where the initial value is controlled by the setting
`initial-connect-timeout`.

Per iteration, the upper limit of the timeout is increased set to

    timeout := min(max_connect_timeout, initial_connect_timeout * 2^i)

I decided to move the entire timeout / tracking of attempts into its own
class to not make the filetransfer implementation more complex. Also,
that allows us to write unit-tests for it.

Setting `--download-attempts` to `0` is forbidden now and an exception
will be thrown. For `--offline` we set it to `1`, the behavior is
equivalent to what it was before: whether the max tries were exceeded is
only checked after the first download exception got thrown, i.e. there's
still one attempt being made.

The end-result - with timeouts being caused by a wrongly set proxy -
looks like this:

    $ env HTTPS_PROXY=1.1.1.1 nix store ping --store https://example.com
    warning: error: unable to download 'https://example.com/nix-cache-info': Connection timed out after 5006 milliseconds (curl error code=28); retrying in 422ms ms (attempt 1/5)
    warning: error: unable to download 'https://example.com/nix-cache-info': Connection timed out after 10010 milliseconds (curl error code=28); retrying in 1003ms ms (attempt 2/5)
    warning: error: unable to download 'https://example.com/nix-cache-info': Connection timed out after 20020 milliseconds (curl error code=28); retrying in 2018ms ms (attempt 3/5)
    warning: error: unable to download 'https://example.com/nix-cache-info': Connection timed out after 40007 milliseconds (curl error code=28); retrying in 4087ms ms (attempt 4/5)
    error: unable to download 'https://example.com/nix-cache-info': Connection timed out after 80074 milliseconds (curl error code=28)

Change-Id: I9e8d08d78275bcf60080d663febc9e075243d36b
2025-08-22 16:19:46 +02:00
Commentator2.0andCommentator2.0 7553d0a983 tests/functional2/lang: don't throw unused file errors on invalid configurations
Currenlty, when a test group is invalid already, we also throw unsued
file errors.
This leads to clutter as more often than not, the unused files are
caused by an invalid configuration, making the debug stack bigger
without reason.

With this commit the behavior is changed to only error about unused
files, when no other configuration issues were found

Change-Id: I92a819753f13b8ed5a07dae53ecaee5d84b5ce64
2025-08-22 07:50:20 +02:00
Commentator2.0andCommentator2.0 0a3e43590c tests/functional2: improve files ux
Currenlty one is required to always write the bulky `mark.parametrize`
with indirect and things

This commit adds a custom decorator for usage of files, which hides the
parametrization complexity from the user.

Change-Id: I526e016d12006669dc302dfc5af619735399c503
2025-08-22 07:50:20 +02:00
Jade Lovelace a84355a813 perl: passthru perl
Required for compat with CppNix derivation.

Fixes: https://git.lix.systems/lix-project/lix/issues/971
Change-Id: I6c38545b7a34b22843fc9acfbb042259cd824d84
2025-08-22 01:51:47 +00:00
Raito Bezarius ac9721a92e Revert "libutil: add makeTempSiblingPath helper"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: Ifc8ccc212ec73f51958b20c9419c81d723f87b0d
2025-08-21 14:37:46 +00:00
Raito Bezarius 1fdaa6888a Revert "libstore: use makeTempSiblingPath in replaceValidPath"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I23f659664bcb1f38ea8cd053279d3275f33e001c
2025-08-21 14:37:46 +00:00
Raito Bezarius 7622d28dd4 Revert "libutil: extract Base32 helpers from Hash"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I2dae7147030c883a57be8a8c205e492e16425a23
2025-08-21 14:37:46 +00:00
Raito Bezarius 28bcc7fb24 Revert "libutil: use OS‐provided entropy for temporary filenames"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: Icdbb89bbf031581250fbda3c9ab9095e7af10ec1
2025-08-21 14:37:46 +00:00
Raito Bezarius 7c03f42759 Revert "libstore: simplify makeTemp{,Sibling}Path callers"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I410046be0ed84e84d1530748d29383489e36c72c
2025-08-21 14:37:46 +00:00
Raito Bezarius ca3328dac0 Revert "libstore: use makeTemp{,Sibling}Path more"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I22a7e48239783bfee53734f65d4e723a7690c3f5
2025-08-21 14:37:46 +00:00
Raito Bezarius 805aeffece Revert "libstore: simplify fallback build directory logic"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: Id6db066f3f5c454b258157bc12e0f26020de94a7
2025-08-21 14:37:46 +00:00
Raito Bezarius bde4a50740 Revert "libutil: use makeTempPath in createTempSubdir"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I22d2c315bd8b1eed536c08f2d5b368331907f994
2025-08-21 14:37:46 +00:00
Raito Bezarius e3ff4e0365 Revert "libstore: simplify createTempDir interface"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I76930bdc1fb51edb5b0c591272ecb6f69085f197
2025-08-21 14:37:46 +00:00
Raito Bezarius e7253d0621 Revert "libstore: make temporary path prefixes optional"
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: Ib4d3179cbfa8e9f861d7416fe08f7d7e3a7d55e2
2025-08-21 14:37:46 +00:00
Raito Bezarius c9cbbc4f63 Revert "tests: remove obsolete code to create custom build direc..."
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I56f871786760eb9f54c02773f0617de9878c1382
2025-08-21 14:37:46 +00:00
Raito Bezarius 9cabe56fcd Revert "libstore: don’t include derivation names in build direct..."
Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: Iee4c3f071238fa58e0e92f0bcc5584ded4a9d71f
2025-08-21 14:37:46 +00:00
Jade Lovelace 61955d0a40 libexpr: hyperlink attr names to their definition locations
Concept: what if you could, in your fancy terminal, in the year of our
lord 2025, just click on the attrs you're looking at to go to where
they're defined. Currently we only expose this info as
builtins.unsafeGetAttrPos, which is inconvenient as it's not
discoverable to users.

By putting it in this more visible yet invisible spot, it's more likely
to be more useful to more people.

In the current state, this is not the most useful ever due to stuff like
https://github.com/neovim/neovim/discussions/35097. However, it can be
expanded by perhaps adding something like the url format setting ripgrep
has.

Change-Id: I3947f97d5c2056d59099af468d7b855486438227
2025-08-20 20:55:54 +00:00
Alois Wohlschlager c82af241f5 packaging: fix static build
Normally `pkgsStatic` adds ` -static` to `NIX_CFLAGS_COMPILE`. Due to a bug
this did not apply with `__structuredAttrs`. As the fix [1] has not been
backported yet, put it in the package manually.

[1] https://github.com/NixOS/nixpkgs/pull/428430

Fixes: https://git.lix.systems/lix-project/lix/issues/962

Change-Id: I6a6a6964c6a33f486ba3df3be16f715ad1b060c3
2025-08-20 18:31:52 +02:00
Alois Wohlschlager 010dae39d3 capnproto: fix platform offset
Backport of https://github.com/NixOS/nixpkgs/commit/8b0263aba578e2fa611a528bedcfc5cf4d5a687c .

Change-Id: I6a6a6964917df3610cd728c696ecdcd8ea6e61a4
2025-08-20 18:25:57 +02:00
eldritch horrors 001c70d2ba libstore: mark all non-local stores as thread-unsafe
this pretty much only impacts store verification via the nix3 cli. no
other thread pools are left, and the verification pool may *actually*
be important for throughput since verification involves much hashing.

Change-Id: I32152e6169a82a1268a790e333f21a0430ede7f4
2025-08-19 13:08:53 +00:00
eldritch horrors 3cecd2306b nix/sigs: remove sign pool
signing is very cheap, it's only the store access that is expensive.
http binary caches parallelize async accesses extremely well though.

Change-Id: Ifdbf398bd328ba16ec4e8caba3f5f99a6cf3e046
2025-08-19 13:08:53 +00:00
eldritch horrors d63edddeb0 libstore: remove debug info upload pool
Change-Id: Ife5f69ddaeb82f002f4dfe05347fe700d201df72
2025-08-19 13:08:53 +00:00
eldritch horrors 13509ef773 libstore: rewrite debug info upload with generators
Change-Id: I1b0424c3b8aed5a90d1ca3d61b11cc5a1bf92cf0
2025-08-19 13:08:53 +00:00
eldritch horrors c917f4ec78 nix/sigs: remove CopySigs thread pool
we don't have benchmarks for this one, but a 10x improvement seems likely.

Change-Id: I76f4e9c9ebff86fd7d451ed7e125ab309011457e
2025-08-19 13:08:53 +00:00
eldritch horrors 20f84eb6bf libstore: remove queryValidPaths thread pool
this is used by nix-env and copyPaths, which in turn is used to upload
to binary caches. for a large path set we have seen 10x a improvement.

Change-Id: Ieadd0e66180e5ceecefaf944a5bb2f0523374954
2025-08-19 13:08:53 +00:00
eldritch horrors 5fc6ab2e50 libutil: make generator iterators adl-visible
lets us use generators in algorithms that use adl iterator access

Change-Id: I05b06f070e370ef21c693e61979d07d9b7206a9f
2025-08-19 13:08:53 +00:00
eldritch horrors 5a30005e2f libutil: remove unused runAsyncInNewThread
Change-Id: I55d161201737fc6b7dbfb0a387b253939dfe5784
2025-08-19 13:08:53 +00:00
sternenseemann e339480592 Test build with lowdown < 1.4 in CI
Change-Id: I486dec6f2d91580d21712c1f4f18462aa02473b3
2025-08-19 10:45:40 +00:00
Commentator2.0 d8b1fb7799 tests/functional2/lang: replace toml with tomllib
currenlty we use the external package `toml`, this just adds an
unnessecary dependency, as python ships its own toml as `tomllib`

Change-Id: Ia63fa7558973e853ada20cbfa21d897d700444f8
2025-08-18 20:08:09 +02:00
WeetHet 1f47ecef4e libstore/build: adjust setupConfiguredCertificateAuthority
Always use tmpDir on darwin. Call setupConfiguredCertificateAuthority even if useChroot = 1 on non-linux.
Even though macOS builds are not executed in a chroot, enabling the sandbox
sets `useChroot = 1`. Basically, useChroot is set when the sandbox is enabled,
not really when a chroot build is executed

Change-Id: I8d4c1e617abcc05dfabd998a8ce94bb11587f9d1
2025-08-18 13:08:42 +00:00
Emily ce6dcf18d6 libstore: don’t include derivation names in build directories
They have variable size, which is bad for #913.

Change-Id: I6a6a6964a84804dee281ade48e6517419a6143fa
2025-08-18 09:27:31 +00:00
Emily 246f0eed82 tests: remove obsolete code to create custom build directories
We now do in fact do this and decide this.

Change-Id: I6a6a69643af2449370df001f8be787eba889b857
2025-08-18 09:27:31 +00:00
Emily 6aedc0ee70 libstore: make temporary path prefixes optional
This is not the same thing as passing an empty string, because it
avoids the `-` separator.

Change-Id: I6a6a69646aa76953078a08c606e8f82c9ec03e8e
2025-08-18 09:27:31 +00:00
Emily 0173d0dde4 libstore: simplify createTempDir interface
We always use the default temporary directory, because
`createUniqueDir` has an interface nice enough to use directly for
the few bespoke uses.

Change-Id: I6a6a6964c15c31bb3e131fbe1db1837987a6d6dc
2025-08-18 09:27:31 +00:00
Emily 2a17164865 libutil: use makeTempPath in createTempSubdir
This makes the paths more nondeterministic, but more reliably unique,
and lets us remove the retry loop.

Note that this adds random entropy to the build directory visible
inside derivations on Darwin and unsandboxed Linux. It was already
non‐deterministic in the presence of concurrent builds and similar,
but now we can reliably expect it to be different every time. On the
whole I think that’s a good thing, as it is impossible to ensure
a single consistent build directory and derivation outputs should
not depend on it.

Package reproducibility isn’t great on Darwin to begin with,
though, and the reproducibility bugs this will turn up in packages
will be more urgent to fix than when the build directory was mostly
consistent. A quick survey of my local store shows that many C, C++,
and Rust binaries contain build directory references, likely due to
use of `__FILE__` and its equivalents; non‐binary offenders include:

* Install logs included in the Rust and Cargo bootstrap compilers
* Example errors in the Rust documentation referencing build paths
* Configuration information installed with CPython itself
* Python 2 metadata from resholve’s closure
* Cython metadata
* Generated headers in Facebook libraries referencing source paths
* Generated CMake files in Facebook libraries referencing source paths

I haven’t built that much in this store since the last GC, so this is
probably only a small sample of the problems across the tree. These are
all instances of <https://reproducible-builds.org/docs/build-path/>,
though, and should probably just be treated as general reproducibility
bugs outside of contexts like the Linux sandbox where we can normalize
them away entirely.

I have implemented away build directory paths for C/C++, applied some
additional fixes for non‐`__FILE__`‐related issues in binaries
from ATF and LLVM, and fixed the derivation bug causing the CPython
3 issue, and will work on upstreaming these changes. Rust is working
on the problem upstream, with some temporary workarounds we can
potentially apply in Nixpkgs for now. The rest will require some
distributed effort.

Change-Id: I6a6a69648f74d85c6fca86cc52f38fd957e4f9ad
2025-08-18 09:27:31 +00:00
Emily 267d9e100c libstore: simplify fallback build directory logic
This does change the behaviour when the global temporary directory
does not exist, but other uses of the global temporary directory are
already broken in that circumstance, and it should be fixed centrally
if the use case is considered desirable. The logic was not present
before the recent churn around build directories – it was added now
that Lix is taking ownership of the build directory in the store –
so this should not be a meaningful regression.

Change-Id: I6a6a69648054ae201b3ce36d11e49c93793fdb0e
2025-08-18 09:27:31 +00:00
Emily cad304420f libstore: use makeTemp{,Sibling}Path more
Change-Id: I6a6a69641f9c9d3ab339d25d061dad6cd1f8416d
2025-08-18 09:27:31 +00:00
Emily 24ccf500d1 libstore: simplify makeTemp{,Sibling}Path callers
There is now no risk of race conditions on a system with a functioning
entropy source, and the bespoke prefixes are either redundant to the
default or unnecessary.

Change-Id: I6a6a69648a3b8060333e97269ea8b72499614559
2025-08-18 09:27:31 +00:00
Emily 03beb9a1d3 libutil: use OS‐provided entropy for temporary filenames
Relax the constraints on keeping the exact same filename format to
provide a more robust source of entropy with a simpler interface
(as previously suggested by eldritch horrors). Using 128 bits of
OS‐provided entropy ensures global uniqueness and allows us to
skip any thought of gracefully handling the case where these files
already exist.

My microbenchmark that repeatedly constructed paths like this and
printed them out showed that this takes about 1.23× the time of
the previous implementation, both taking on the order of a couple
microseconds for one iteration. Since everything that uses it is doing
things more expensive than printing to standard output, the actual
performance delta is likely to be lost in the noise. If it somehow
becomes a bottleneck, it can be optimized without sacrificing the
guarantees by reading from the system RNG only to seed a thread‐local
CSPRNG like [ChaCha8Rand], but I think that’s very unlikely.

We also tweak the recommended way of creating a temporary file inside
a directory in anticipation of later changes, and rename the `suffix`
parameter to `prefix` (it’s a prefix to the random characters and
a suffix to the root, but this way is more consistent).

[ChaCha8Rand]: https://c2sp.org/chacha8rand

Change-Id: I5bd7badf1392243f485935c4a016c1f833cb16d3
2025-08-18 09:27:31 +00:00
Emily 76baa4c50d libutil: extract Base32 helpers from Hash
Change-Id: I6a6a6964f95aecf152090a3bf82b5ec287a21481
2025-08-18 09:27:31 +00:00
Emily a42cb1c43d libstore: use makeTempSiblingPath in replaceValidPath
Change-Id: I6a6a69643732c1bb4942425ae1f179a411412fd5
2025-08-18 09:27:31 +00:00
Emily e2d85579d8 libutil: add makeTempSiblingPath helper
The prospective callers of this should probably be doing something
smarter or more abstracted to begin with, but this is useful as an
incremental improvement for call sites with existing `makeTempPath`
logic in the face of filename length limits.

Change-Id: I6a6a6964374f47abbf0ec10aa8d945c4e50a43af
2025-08-18 09:27:31 +00:00
eldritch horrors 3de996f521 libexpr: stringviewify some more APIs
notably this also includes the symbol table because it stores real
strings that are referenced by eval values, and an upcoming change
will make it impossible to share those strings with value strings.

Change-Id: I20a3644db8aa0850efe29630e0b73d424cb2aa56
2025-08-17 14:55:13 +02:00
eldritch horrors 8208c6ebb7 libexpr: don't read Value::string.s directly
Change-Id: I0f224459fcbff8bc53c3668bc6ea52881c453fd0
2025-08-17 12:11:19 +00:00
Emily 27f7075f4d libexpr: remove the parse-toml-timestamps experimental feature
See [my comment] on the Nix PR to restore the previous behaviour
for why I believe we should remove this for the next release. The PR
should still be backported to stable releases to avoid making breaking
changes to their semantics.

[my comment]: <https://github.com/NixOS/nix/pull/13741#issuecomment-3180851635>

Fixing this across supported Lix versions is required for Nixpkgs to
update toml11, which is a blocker for the CMake 4 update.

Change-Id: I6a6a69642e6b6cb13a9fccc0778e9158b53102d5
2025-08-16 14:27:13 +01:00
4de09b6b54 packaging: bump toml11 to 4.4.0
This version changes the handling of TOML timestamps, and throws an
error on out‐of‐range integer literals rather than the previous
saturating behaviour, as required by [the TOML v1.0.0 specification]:

> Arbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be
> accepted and handled losslessly. If an integer cannot be represented
> losslessly, an error must be thrown.

[the TOML v1.0.0 specification]: <https://toml.io/en/v1.0.0#integer>

The only known use of this is a questionable Nixpkgs test that I have
proposed [a fix] for.

[a fix]: <https://github.com/NixOS/nixpkgs/pull/433710>

Bumping this ahead of Nixpkgs ensures we can test these cases on
HEAD in advance. I presume that the next Lix major version will be
released after 25.05 goes out of support, so it should be fine to
drop support for the old version of toml11.

The co‐authors of this commit are the contributors to the vendored
package definition from Nixpkgs.

Co-authored-by: Anderson Torres <torres.anderson.85@protonmail.com>
Co-authored-by: Artturin <Artturin@artturin.com>
Co-authored-by: Silvan Mosberger <silvan.mosberger@moduscreate.com>
Change-Id: I6a6a69644a188b6e09eee5c9cf91ddd3c81d24ee
2025-08-16 14:27:13 +01:00
Emily 7ee442079d tests/functional2/lang: add tests for builtins.fromTOML overflow
This behaviour is bad and will be fixed, but adding a test for the
present state documents the change.

Change-Id: I6a6a6964b88dc929269ee136804857b3852dfafe
2025-08-16 13:39:20 +01:00
Sergei ZimmermanandEmily 2898b9e7dc libexpr: Canonicalize TOML timestamps for toml11 > 4.0
This addresses several changes from toml11 4.0 bump in
nixpkgs [1].

1. Added more regression tests for timestamp formats.
   Special attention needs to be paid to the precision
   of the subsecond range for local-time. Prior versions select the closest
   (upwards) multiple of 3 with a hard cap of 9 digits.

2. Normalize local datetime and offset datetime to always
   use the uppercase separator `T`. This is actually the issue
   surfaced in [2]. This canonicalization is basically a requirement
   by (a certain reading) of rfc3339 section 5.6 [3].

3. If using toml11 >= 4.0 also keep the old behavior wrt
   to the number of digits used for subsecond part of the local-time.

[1]: https://www.github.com/NixOS/nixpkgs/pull/331649
[2]: https://www.github.com/NixOS/nix/issues/11441
[3]: https://datatracker.ietf.org/doc/html/rfc3339

(cherry picked from commit dc769d72cb8ad22a0f89768682b5499a9d2b3d8b)
Upstream-PR: https://github.com/NixOS/nix/pull/13741
Change-Id: Iac4fbe5108be79be585e9670fa42dfd11f3c5e89
2025-08-16 13:39:20 +01:00
Sergei ZimmermanandEmily 19d9a87c2f libexpr: Use table.size() instead of unnecessary loop
(cherry picked from commit d8fc55a46e0c09241131097dbf1d6fa09e0a9808)
Upstream-PR: https://github.com/NixOS/nix/pull/13741
Change-Id: I8a11e21ae3bff3a885e13fbab74e1deb162a34cf
2025-08-16 01:20:12 +01:00
Sergei ZimmermanandEmily 5badc1bc8a libexpr: Use recursive lambda instead of std::function
There's no reason to use a std::function for recursive lambdas
since there are polymorphic lambdas.

(cherry picked from commit a80a5c4dba0d944fab8f5ed57a343869ae96bf16)
Upstream-PR: https://github.com/NixOS/nix/pull/13741
Change-Id: I593bd04597e2ae000374ca1eca4d8928e986c0b5
2025-08-16 01:20:12 +01:00
Sergei ZimmermanandEmily 2ca5670ec3 libexpr: Remove extra trailing semicolons (NFC)
This looks really weird after the reformat.

(cherry picked from commit df4e55ffc13c413e270af134227115a20a2341ba)
Upstream-PR: https://github.com/NixOS/nix/pull/13741
Change-Id: I8de92d58620cc4545a31d8b7d533d2f1e9f4f233
2025-08-16 01:14:07 +01:00
Emily 86303ffb05 libexpr: treat too‐large unsigned JSON integers as floats
JSON has only one numeric type, with vague semantics. [RFC 8259] says:

> This specification allows implementations to set limits on the range
> and precision of numbers accepted.  Since software that implements
> IEEE 754 binary64 (double precision) numbers [IEEE754] is generally
> available and widely used, good interoperability can be achieved by
> implementations that expect no more precision or range than these
> provide, in the sense that implementations will approximate JSON
> numbers within the expected precision.  A JSON number such as 1E400
> or 3.141592653589793238462643383279 may indicate potential
> interoperability problems, since it suggests that the software that
> created it expects receiving software to have greater capabilities
> for numeric magnitude and precision than is widely available.
>
> Note that when such software is used, numbers that are integers and
> are in the range [-(2**53)+1, (2**53)-1] are interoperable in the
> sense that implementations will agree exactly on their numeric
> values.

[RFC 8259]: <https://www.rfc-editor.org/rfc/rfc8259.html#section-6>

Floating‐point numbers are annoying to deal with in Nix, so it
optimistically parses integer‐looking literals as Nix‐language
integers where possible. Nixpkgs relies on this behaviour, as it backs
its `lib.toInt` family of functions with `builtins.fromJSON` in lieu
of a real integer‐parsing built‐in, and treats floating‐point
outputs as an error. Therefore, dealing with integer‐looking
JSON number literals that are outside the interoperable range is
unavoidable.

However, this raises the question of how literals that look
like integers, but exceed the range of a Nix‐language integer,
should be handled. The JSON library we use attempts to represent
integer‐looking literals as a unsigned or signed C++ integer type
before falling back to floating‐point numbers.

This means that we were parsing literals below −2⁶³ as
floating‐point numbers, while rejecting ones above (2⁶³ + 1)
with an error. This was done to avoid the C++ undefined behaviour in
the previous code path, but is hard to justify. This change causes
them to both be parsed as floating‐point numbers.

The alternative would be to reject the signed case too. However,
I believe that is less consistent with how JSON handles its single
numeric type, less interoperable with JSON documents found in the wild,
and that it is preferable to avoid the function being needlessly
partial in this case. It does mean that round‐tripping is less
lossless than before, but extreme floating‐point values already
caused these kinds of issues, and from JSON’s point of view that’s
exactly what these literals represent. Only numeric values outside the
RFC’s suggested interoperable range will have any round‐tripping
issues, and we continue to guarantee the behaviour on all values that
can be represented as Nix‐language integers.

Change-Id: I6a6a696412383e8a2cc160397716cb7f7bc7a2d4
2025-08-15 23:46:14 +01:00
eldritch horrors 935901cd46 nix/ls: fall back to downloading the nar if the .ls is bad
fixes #959

Change-Id: I1715f6fcc938dac7287d9cf4a85e93c9d66768a0
2025-08-15 18:05:06 +02:00
eldritch horrors 612d553a4f libstore: fail makeLazyNarAccessor for broken .ls files
Change-Id: I58ecc89046ee5fc58d05c980acb3616e91ee4741
2025-08-15 18:05:06 +02:00
eldritch horrors c3bfb6fe17 testing: unbreak functional tests in devshells
turns out that adding busybox to checkInputs just totally trashes f1 testing.

Change-Id: Iac8d49a59a39c44e0663d7ae760e0a0473ebf7fd
2025-08-15 15:26:27 +02:00
Commentator2.0andRutile 7869385b98 tests/functional2: Make Command Environment actually declarative
So far, the environment used by `command` was completely leaky and the
one used by `nix` was very leaky despite it trying to be a "hermetic"
environment.
This commit moves the hermaticity to `command` and changes its
implementation to be not leak anything.

To achieve this, the following changes were also nessecary:
- the `files` and `snapshot` fixture now use the folder `test-home`
within the tmp_path directory by default, as the `HOME` environment
variable is set to there. (extraction not possible due to dependencies
of command etc also using this directory)

Fixes: #847, #848

Change-Id: I55f86ee0e1615e73fcf442ee2f28f3b89893bbb4
2025-08-15 06:56:07 +00:00
Sergei ZimmermanandEmily b2e48aac5c tests/functional/lang: Add more tests for TOML timestamps
Current test suite doesn't cover the subsecond formatting at
all and toml11 is quite finicky with that. We should at the very
least test its behavior to avoid silent breakages on updates.

(cherry picked from commit 7ed0229d1abd4414144c7af396842462ce6fc1eb)
Upstream-PR: https://github.com/NixOS/nix/pull/13741
Change-Id: I6a6a696433b168072d6ad2585dce8a3c10ccbc39
2025-08-15 01:11:52 +01:00
Emily c586596a9f libexpr: format fromTOML source
Otherwise the next diff becomes very messy.

Change-Id: I6a6a6964d96543ade130d491f413ebd9fe2b7ff1
2025-08-15 01:11:52 +01:00
Emily d84bc45e17 tests/functional2/lang: add test for underflowing JSON number literal
Change-Id: I6a6a6964c49a82244f7c0062c27ec9a5feadd910
2025-08-15 00:19:25 +01:00
EmilyandPhilipp Otterbein 860984be27 tests/functional2/lang: add tests for NUL bytes in JSON and TOML
Based on the tests in the upstream PR.

Co-authored-by: Philipp Otterbein <potterbein@blockstream.com>
Upstream-PR: https://github.com/NixOS/nix/pull/12024
Change-Id: I6a6a69643ae9bd2445e551013d09e64ac1fe9916
2025-08-14 22:19:29 +01:00
Emily 5359ab9a76 doc: update emilazy in change-authors
Change-Id: I6a6a6964bf752f27fde54d3bb3f94afdae4fe139
2025-08-14 19:56:18 +01:00
janw4ld 15a42d21a1 libexpr/flake: add inputs.self.submodules flake attribute
a port of <https://github.com/NixOS/nix/pull/12421> from CppNix, gated behind a `flake-self-attrs` experimental feature.

Fixes: https://git.lix.systems/lix-project/lix/issues/942
Change-Id: I655ce089e603d95abc693d6b77130fcf00c7f456
2025-08-13 03:05:49 +00:00
eldritch horrors 4a119e6e46 libutil: support async deserialization on musl
use a thread pool and allow only buffered sources for performance. we
may want to use this code path unconditionally due to gc interactions
of fibers in circumstances we should not even be able to trigger, but
if that becomes important we will have a useful implementation ready.

Change-Id: Ib4e1531fe920847d8e30a42e8df393ace549f52e
2025-08-12 14:14:35 +02:00
Linus Heckemann 52ef1181f0 build: fix cross-compilation
We need capnproto-lix to be provided by callPackage, otherwise it won't
be spliced and the same (built for the cross host platform) for both
buildInputs (correct) and nativeBuildInputs (incorrect). We thus move it
into the overlay.

A similar problem exists for the lowdown build. We thus use callPackage
to override it as well. This is horrible (especially because it means we
need to pass the enableDarwinSandbox package argument through
ourselves), but at least it builds...

Fixes: https://git.lix.systems/lix-project/lix/issues/939
Change-Id: I802152072d852903401ef701f526195aa99475f2
2025-08-08 09:48:42 +02:00
Commentator2.0andCommentator2.0 8bbd5e1d0d tests/functional2: do not copy testlib tests to internal environment
When testing specific internal functionallity while needing things from
the testlib, so far, the tests for the testlib have always been copied
too.
To reduce the amount of additional program required when later making
the env of the pytest_command declarative, and to not test the same
tests a multitude of times (and potentially reaching infinite recursion)
those tests will no longer be copied

Change-Id: I36ec3824a21ed30f9b8ff19948031d1edbf6c76c
2025-08-07 14:25:51 +02:00
eldritch horrors a9117791e2 libutil: remove unused FdSource::specialEndOfFileError
Change-Id: Ia03e270c359014ab3675a043bad342c4bbfdbafd
2025-08-06 14:43:47 +00:00
eldritch horrors 22cf5eb989 libstore: use async io for remote store IO
this means both the worker protocol and the serve protocol, i.e.
ssh-ng/local connections and legacy ssh connections. now we have
no blocking reads left anywhere in our client store connections.

Change-Id: I2f628d4d2e71ef0a7006918f175192f3f58eea95
2025-08-06 14:43:47 +00:00
eldritch horrors db0ed505e9 libutil: add async serialization helpers
Change-Id: I5c123e1ac31172d61c9e1d293e99ca1022bcec4e
2025-08-05 19:10:46 +00:00
eldritch horrors 7e8b44d718 libutil: allow access to async stream buffers
this is easier than remembering which buffer was used during construction.

Change-Id: I64a8bdcbc0104c5a4a3330266b508cfd9297852e
2025-08-05 19:49:11 +02:00
Maximilian BoschandMic92 cad6118e20 subprojects/nix-eval-jobs: don't set NIX_PATH
Corresponding upstream change: https://github.com/nix-community/nix-eval-jobs/commit/f584ae856ebab2d20115c5d1424f4d2fb9e0e6a6.patch

Co-authored-by: Mic92 <joerg@thalheim.io>
Change-Id: Id6085968f7f4ccdbc8035f608ff75420fbf962a5
2025-08-02 14:21:13 +02:00
Emily 52872026fb packaging: actually run install checks
`mesonCheckPhase` of course runs `preCheck` and `postCheck` hooks,
not `preInstallCheck`, so this was not doing the right thing. Really
sorry for breaking CI :(

Fixes: e6da29ad6b
Change-Id: I6a6a69642a242e2c8bfe10ac61d3f6756d666548
2025-08-01 18:17:47 +01:00
Maximilian Bosch f077a6f36e libstore/binary-cache-store: don't cache narinfo on nix copy, remove negative entry
Snix's nar-bridge[1] stores NARs under a different URL, i.e.
`nar/snix-castore/<hash>.nar` rather than `nar/<filehash>.nar`. Right
now, when copying into such a store via the http binary-cache, we'd end
up with wrong cache entries that point to the wrong NAR URL.

On Hydra, this is a fatal error, i.e. builds that depend on previously
built paths (that were written to the cache before by the queue runner)
would be aborted because of that.

This patch removes the caching since we'd have to re-fetch the narinfo
to do taht and this can also happen the next time, the narinfo is
queried. Also, removes the negative cache entry indicating that the
store-path doesn't exist in the store.

We don't have any coverage for http-stores so far, so I wrote a small
testcase for the "default" case and the nar-bridge case in functional2
since it has a very nice fixture for an HTTP server ready. I'm aware
that there's a CL for a nicer cache server[2], but given I'm down a
pretty deep rabbit hole by playing around with Snix, I decided to not
finish the CL and write something small for the tests in here. This can
be replaced by the fixtures from that CL later on as well.

[1] https://snix.dev/docs/components/overview/#nar-bridge
[2] https://gerrit.lix.systems/c/lix/+/2431/1

Change-Id: I4fcdf47a6bf9c3c8fbeb235eeca7a48914a4d693
2025-08-01 12:44:28 +02:00
eldritch horrors d5cfc6f19c libstore/remote: frame buffers, don't buffer frames
shoving a nar dump directly into a framed sink created a bunch of tiny
frames, each of which requires at least two syscalls to read. this can
lead to immense performance loss when using a daemon; we have seen 15%
in benchmarks on main and even more with async code involved ... oops.

Change-Id: I8529506e3de74d92834d1f4ee228dcaf32eb756c
2025-08-01 01:10:50 +02:00
eldritch horrors 98a27fbfd2 bench: soup up the benchmark script
add daemon support, fix the rebuild cases by using an installer config

Change-Id: I47cbb0dd401abf5e041e9936077e502f5e0cabf9
2025-07-31 15:15:24 +00:00
Alois Wohlschlager becb2f0002 packaging: fix pkg-config files
Notably, this adds the Requires.private required for proper static linkage of
Lix libraries. Some minor missing or duplicated dependencies are also fixed
along the way (although some optional dependencies are omitted due to their
size).

Fixes: https://git.lix.systems/lix-project/lix/issues/789

Change-Id: I6a6a696413d538124d9ac75c68f100cc3089284f
2025-07-31 06:43:58 +02:00
Alois Wohlschlager e69aaa5f65 packaging: only install lix_doc for static builds
The stated rationale for installing lix_doc static library only applies to
static builds. Doing it even for dynamic builds is unnecessary and has lead to
the questionable practice of deleting the library in the nixpkgs packaging [1],
in turn contributing to breaking downstream static linkage.

[1] https://github.com/NixOS/nixpkgs/blob/bbb1dbe938ff2341e6618872671de7432c98078f/pkgs/tools/package-management/lix/common-lix.nix#L294-L296

Change-Id: I6a6a69642be04c6ee6976e324ab87abf1e112b90
2025-07-30 06:18:39 +02:00
Alois Wohlschlager dfb9e77c22 packaging: fix dependencies
A bunch of dependencies were superfluous, while others were missing (in
particular on internal sub-libraries) and things just happened to work because
they leaked in or were explicitly required in other places. Make efforts to fix
them all.

Change-Id: I6a6a69643e35ac4b0b66a72f4e42a2ba5ed52488
2025-07-30 06:18:39 +02:00
Alois Wohlschlager 480fdf146d packaging: prelink static libraries that need to be linked fully
Some of the Lix libraries always need to be linked in full due to their
reliance on static initializers. This was achieved internally using link_whole,
but they are still easy to abuse by external users who manually need to
remember passing linker flags such as `--whole-archive` (GNU) or `-force_load`
(Apple), and the obvious way to shove it in pkg-config breaks Meson due to
potentially including a library's flags multiple times, and then deduplicating
only the file names leaving a stale `-force_load` around causing trouble.

Instead we now "prelink" the static libraries, by merging them into one object
file. Since the static linker will always link entire object files, this will
have the same effect as whole-archive linking (except the library won't be
included if it's completely unused, which should not cause trouble since it's
unused after all, and dynamic libraries behave the same way). Unfortunately
Meson's native prelink functionality cannot be used due to missing (non-Apple)
Clang support [1], so write our own one. While not particularly portable, it
should work with Clang which is the only officially supported compiler, as well
as GCC.

[1] https://github.com/mesonbuild/meson/pull/14846

Change-Id: I6a6a6964a82241ce3b0b11fe8397fd451b8027f2
2025-07-30 06:18:39 +02:00
Alois Wohlschlager 321807a40e packaging: stop requesting linkage against boost_container
Meson only requires the `modules` option for Boost libraries that should be
linked against [1]. However, we use only header-only portions of the Boost
container library; in fact we only do not run into the disallowedReferences
because the linker drops the unused library. Remove the misleading option.

[1] https://mesonbuild.com/Dependencies.html#boost

Change-Id: I6a6a69648b806bf6bcf784391263f5ee9cd63a0b
2025-07-30 06:18:39 +02:00
Emily 93acdd40f6 packaging: remove redundant apple-sdk_11
This is now the default in all supported Nixpkgs versions.

Change-Id: I6a6a69642951c2e1ae117d8360b450cc9fdc741b
2025-07-29 20:45:58 +01:00
Emily 99cf661187 packaging: remove redundant --print-errorlogs
These were added to Nixpkgs in
4dec85d68b81ed971e7f2953cfea895f0f0c0c2c, back in 2024.

Change-Id: I6a6a69646f6a09fb3d8bae3efbf9d6e56d662ca3
2025-07-29 20:45:58 +01:00
Emily e6da29ad6b packaging: use the upstream mesonCheckPhase for installCheckPhase
This gets us `--print-errorlogs` and `--timeout-multiplier=0` for free,
and also fixes the concatenation logic with `__structuredAttrs`.

Change-Id: I6a6a69643ea7224cb24508505c554143f83ae243
2025-07-29 20:45:58 +01:00
OPNA2608 8c2891ae14 meson: Actually use host_cpu in host_system, expand fixups
Otherwise we'll get system names like `x86-linux`, which is nonesense.

Also add fixups for 32-bit ARM, and MIPS.

Change-Id: I6bd773bec82dcc54b40bbc018641cd614b272a28
2025-07-29 14:38:52 +00:00
eldritch horrors f0150eb8a3 libutil: add AsyncFramedInputStream
the async version of FramedSource, with all its weaknesses for bug-compat.

Change-Id: Ifcdd4a5819f7cf25a0e8b01c63975ffead54079c
2025-07-29 13:37:53 +00:00
eldritch horrors 96200d5768 libstore: use async io from RemoteStore::Connection::processStderr
this lets us avoid a bunch of fcntl calls to unset and re-set O_NONBLOCK
on remote store connections. the overhead of these isn't high, but doing
it is still wasteful and a maintenance burden when we have async readers

Change-Id: I900cdca2a16202380c8b6f9b86da7d9b0f1e34ac
2025-07-29 13:37:53 +00:00
eldritch horrors 7f22e9e6cc libutil: duplicate deserializers for async streams
this is needed to asyncify the wire protocol deserializers.

Change-Id: I8087c852ab7b64bc1749310aa1493912af8b1c6e
2025-07-29 13:37:53 +00:00
eldritch horrors 45d81027e3 libutil: remove readInt, readLongLong
the former isn't even int, it's unsigned. the latter is uint64. both
should be explicit about this to avoid problems that we have already
had, such as the FramedSource wire protocol writing using 64 bits to
write frame sizes, but 32 bits to read them. large frames will cause
the reading end to crash with an unnecessary serialization exception

Change-Id: I3c15e911f649eec719d4b1c135dde1b6ba020271
2025-07-29 12:25:56 +00:00
eldritch horrors 7923dcc034 libtuil: remove deserializing operator>>
they will not work well with async deserialization and are not used
consistently anyway. just like the serializing operator<< these are
protocol stability hazards: changing the type of a field influences
the wire protocol layout and type constraints, which is not amazing

Change-Id: I54b20a133048f4ca15a9fb0f4d8b94dc78f62d89
2025-07-29 11:54:33 +00:00
eldritch horrors d647bf7d0a libutil: remove unused readString overload
Change-Id: I8419efe895617b5473170f3cbb76697f0aa2def2
2025-07-29 11:47:40 +00:00
eldritch horrors 51a7f1f37a libutil: add AsyncInputStream::readRange
this is an equivalent of the regular kj read interface which also takes
a min/max pair. we do not need this very often though, so we'll keep it
as a separate method for now. if we do find we use it more than read we
can still rename read to readSingle and readRange to read. we will see.

Change-Id: Ib04ca146911adae7081cf4b2df097217ea5fe9f8
2025-07-29 11:47:40 +00:00
eldritch horrors 874e878ba0 libutil: move LengthSink into sole user
this should've been a filter from the start. since filter support in the
old IO model is very bad we just move it into the only use of it instead

Change-Id: Ifb9cfecf07587ae1d2d55072ddf505c86c79cc1b
2025-07-29 10:42:00 +00:00
eldritch horrors db7c3a88b2 libutil: move SizedSource into its only user
we should not encourage this kind of framing. in the future we will have
to do this on async streams, which we *absolutely* should not encourage.

Change-Id: Ib89e144afb564284db64fc7367cba7fffc18fdaf
2025-07-29 10:42:00 +00:00
eldritch horrors 5c2ee71c61 libstore: update exceptionAbortsDownload test
the exception no longer actually matters, only that the download stream
is destroyed before the download finishes does. exceptions during drain
calls on the returned stream will cause the stream to be destroyed, but
draining this stream is just a remnant of the old download-to-sink API.

Change-Id: Ic6de40deb2ccff09d77180148afe746f29f55d23
2025-07-29 10:42:00 +00:00
eldritch horrors 0acb43f6d3 libutil: pass owned sources to makeDecompressionSource
we lose reference lifetime constraints for minimal runtime overhead.

Change-Id: I198b521a0fc56f9a3499ec1d6ae9aa8655daa59e
2025-07-29 10:42:00 +00:00
Qyriad fde2a4be63 rnix: 0.11.0 -> 0.12.0
Fixes rnix not parsing files with chained pipe operators in them. Though
honestly I'm not sure how this was working before with any pipe
operators at all?

See: https://github.com/nix-community/rnix-parser/pull/167

Fixes: https://git.lix.systems/lix-project/lix/issues/938

Change-Id: Ifbd737a02bd43f994bfef61d035d40391836aeb9
2025-07-29 09:51:33 +00:00
OPNA2608andRaito Bezarius ce3e9e81b0 meson: Fix Meson CPU names for powerpc CPUs
Nixpkgs expects the `builtin.currentSystem` for POWER CPUs to be:

`powerpc[64][le]-linux`

But using `host_machine.cpu_family()` for the CPU part of the system
string on POWER produces this instead:

`ppc[64]-linux`

So evaluating Nixpkgs errors out on:

`error: Unknown CPU type: ppc64`

To fix this, change
`ppc` -> `powerpc`
`ppc64` -> `powerpc64`
and append `le` if `host_machine.endian() == 'little'`.

I can't actually test this on hardware rn due to hitting a kernel bug
on the host system when linking big things[1], but the approach here
is similar to how it was fixed in cppnix[2][3], so it *should* be fine.

[1] https://git.adelielinux.org/adelie/packages/-/issues/1315
[2] https://github.com/NixOS/nix/pull/13514
[3] https://github.com/NixOS/nix/pull/13520

Change-Id: Ib82839cdaf2198bf18b89e82caaa1217f88e11ed
2025-07-29 05:46:08 +00:00
jadeandLix Systems Gerrit 2b42901ec7 Revert "contrib/plugins: init with mTLS store example"
Revert submission 3698

Reason for revert: Regressed the build, needs some rework.

Reverted changes: /q/submissionid:3698

Change-Id: I651e35435f1006c0abf8c37feb3aa385ac6d4256
2025-07-29 03:34:49 +00:00
569dcf9392 contrib/plugins: init with mTLS store example
This is a collection of Lix plugins that showcase how to write one for
various usecases.

The first is a mTLS store plugin that enable mTLS cache URIs
(`https+mtls://`).

We enable meson build system support for this plugin but we are not
going to distribute it in the official packaging of Lix, we will
repackage each relevant plugin downstream in Nixpkgs.

These plugins have *NO* guarantee support, they are provided as useful
references and are possibly production-ready if your usecase is simple
enough.

Reference: https://github.com/NixOS/nix/pull/13030 (this change has
resemblances but our APIs are different, the tests harness is mostly
from CppNix).

Change-Id: Ib354271981b35dff6c134b12c4748c3eaf743fcb
Co-authored-by: Jörg Thalheim <joerg@thalheim.io>
Co-authored-by: László Vaskó <1771332+vlaci@users.noreply.github.com>
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-28 23:00:44 +00:00
Raito Bezarius 2d0c1e29d2 tests/functional: support loading (contributed) plugins
This is useful to test extended features in Lix.

Change-Id: Idb2416a080329116677809b883950e6c33028a44
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-28 23:00:44 +00:00
eldritch horrors 173e6fe995 libstore: optimize nar copy stream adapter
we don't need to report progress for every read call. that's way too
much. batching like this greatly reduces CPU usage for copies out of
or into remote buidlers due to likewise greatly reduced log traffic.

Change-Id: I3db2b2ab113fbaadefc69cfde6f977fb0c6cd5ad
2025-07-28 23:57:16 +02:00
Jade Lovelace 2512d7a801 clang-tidy: fix some lints on macOS
I think this is partially stuff like
https://git.lix.systems/lix-project/lix/issues/806 but idk.

Change-Id: I4c38bb66fc9552269f33590eb3e99025942f382f
2025-07-27 23:34:59 -07:00
Jade Lovelace e29a4b64ef rl-next: fix incorrect "2.18 or older"
2.18 is still supported and will not become unsupported because we are
2.18 also.

Change-Id: If8af27e2924f67952e29b8f4db461b6784f5106e
2025-07-27 23:05:30 -07:00
Raito Bezarius 2d0109898a libstore/build: rewire builder's environment in presence of a global CA
Historically, Nix would support copying certificate authorities inside
the sandbox so you could use them.

In addition to that, the primitives consisting of leaking environment
variables via `impureEnvVars` and `extra-sandbox-paths` to render paths
external to the sandbox visible to the builder would also constitute a
mechanism to expose special inodes which should have no influence on the
output result, e.g. interception CAs.

Unfortunately, in nixpkgs, `lib.fetchers.proxyImpureEnvVars` set
`NIX_SSL_CERT_FILE` as an impure environment variable.

A confused user may set `ssl-cert-file` via `NIX_SSL_CERT_FILE` outside the
builder believing that this will set magically the right
`NIX_SSL_CERT_FILE` inside the sandbox, but this is not true.

The combination of impure environment variables and setting `caFile`
creates a weird interaction where `NIX_SSL_CERT_FILE` points to an
"outside the builder's world" inode *AND* `ssl-cert-file` creates
this very same certificate file in /etc/ssl/certs/ca-certificates.crt
without rewriting the environment variable.

This footgun is closed by making these two features mutually
incompatible with a warning and forcibly rewriting the SSL family of
environment variables even if it was set via impure environment
variables.

Users who truly meant to use `impureEnvVars` can obtain the right
behavior by setting `ssl-cert-file` to an empty string and will have to use
`extra-sandbox-paths`.

Users who meant to use `ssl-cert-file` will have everything work
automatically with a warning hinting at nixpkgs *fixing its own bug*,
i.e. passing `NIX_SSL_CERT_FILE` as an impure environment variable and
expecting the Nix interpreter to magically reconcile the diverging
values or expecting the user to actually do the work to render the path
visible available via `extra-sandbox-paths`.

Fixes #885.

Change-Id: I32f8b5ce20fe9b6a911768114c92f95fc886cc07
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-27 19:42:37 +00:00
Raito Bezarius e854c5364a libutil/mount: accept copy flags for bind path
Sometimes, `bindPath` will detect the source is a symlink and we are not
using the new mount API which support symlinks (kernel ≥ 5.12 IIRC?).

In those instances, we copy the inode to the target.

But some callers may want to follow the symlink in such circumstances,
we add a new default argument to the previous value and let caller
decide for themselves.

Change-Id: I8505b613fc614ce539eb89258fbbb7eaecebe23b
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-27 00:20:09 +00:00
Raito Bezarius ef94901156 libstore/build: pathContentsGood is physical path aware now
`pathContentsGood` is used to assess the validity of a path as part of
derivation goals *in repair mode*.

When repair is used with a diverted store, i.e. a store where
fsPath(toRealPath(s)) != fsPath(s) for s a store path, this result in
utterly broken behavior because it will attempt to assess the goodness
of the *logical* store locations, most of the time: /nix/store/...

So, if you are repairing your system using a live NixOS ISO. Your ISO
contains a `/nix/store` (assumed to be good) and you repair your system
which is rooted at /mnt and contains its own /nix/store, that is, a Nix
store at /mnt/nix/store.

Performing the following operation `nix-store --verify --repair --store
/mnt` will assess the contents goodness of the ISO's Nix store.

To avoid this, we assess the path existence of the *physical path*, aka
the result of `store.toRealPath` applied to a *logical* store path
string representation and we verify the hash of the *physical path*.

The error messages are not taken care of in this CL as those are purely
cosmetic and helps the user understand what is going on.

Fixes #892.

Change-Id: Ib9e0153cb5683edcf37f1963ebf065ceba5e5dfb
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-27 01:42:41 +02:00
Raito Bezarius 66860eec01 libstore/entry-points: failure to repair inform about the physical store path
Change-Id: I5e4cf19c591662b5823f0302fe074021a19a8ba3
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Raito Bezarius 015b6ca452 libstore/local-store: verifyStore inform about the physical store locations
Change-Id: I0af9c600f1a26c99eb787996e6b24847151dd2c0
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Raito Bezarius 527d0a001f libstore/local-store: invalidatePath inform about the physical store locations
Change-Id: I2d0d6ac4e42be9c7139602a29adf6e0450e1c9d0
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Raito Bezarius 5019eba747 libstore/local-store: verifyPath inform about the physical location store
Change-Id: I2e28acbff01d91484a9bf24a8ac8c37c53306af7
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Raito Bezarius bde5830352 libstore/store-api: isValidPath inform the user about physical store locations
Instead of showing logical Nix store paths, we show the actual physical
location so that the user can stat by copy-pasting these paths.

The bad thing about this change is that certain Nix porcelain only
accept their logical counterparts.

Change-Id: Id0eb45d1bf08a23508dfc2bb694c88155654f585
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Raito Bezarius b7a9da96be libstore/worker: pathContentsGood inform about physical store locations
When a user runs a repair or check sequence, they might be confused of
seeing references to a logical /nix/store path rather than the actual
physical store location.

Change-Id: I042031a6159cdd1054e7e200a220bf6c321d5fb8
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 20:52:25 +00:00
Jade Lovelace 95ea633547 docs: properly explain conversions in nix eval --json/--raw options.
jade: I rewrote this PR to be consistent between nix-instantiate and nix
eval. It turns out that nix eval *doesn't* copy to store with `--json`,
whereas nix-instantiate does. Wat.

Closes: https://github.com/lix-project/lix/pull/17
Co-authored-by: tyberiusprime <tyberiusprime@noreply.git.lix.systems>

Change-Id: Id22deec1cee0fed3bd5689567869b70bab26bae5
2025-07-26 20:05:54 +00:00
Alois Wohlschlager e02c9b5a01 packaging: stop copying unnecessary boost libraries
Originally, libboost_context and dependent dynamic libraries have been copied
into the nix package to remove boost from the closure and consequently reduce
the closure size. Since commit ef0de7c79f we do
not depend on Boost coroutines any more, so these libraries are not needed at
all any more and (somewhat ironically) only increase the package size. Remove
them.

Change-Id: I6a6a6964dc3e0b29dfad8b2b232b428ba3cc653c
2025-07-26 20:04:59 +00:00
Qyriad 275ca3fda0 build: simplify -Dnix-eval-jobs handling
Meson conveniently does lets you pass feature objects to `required :`
arguments[1], which is handy

[1]: https://mesonbuild.com/Build-options.html#features

Change-Id: I54194b235a9b3dc207f3f78e0a8c50f957e1fd1f
2025-07-26 19:38:35 +00:00
Alois Wohlschlager ae64570ee4 packaging: remove obsolete boost-finding environment variables
The issue requiring these environment variables to be set for Meson to find
Boost [1] has been fixed [2] for quite some time now. Drop them since they are
unnecessary in all supported nixpkgs releases (in fact they have already been
removed in the lix package there).

[1] https://github.com/NixOS/nixpkgs/issues/86131
[2] https://github.com/NixOS/nixpkgs/pull/315998

Change-Id: I6a6a69640a30e917cd7a983b9d846d023b393dcd
2025-07-26 17:08:14 +00:00
Raito Bezarius 5e4cbf39cf libstore/build: endure dangling symlinks of system files at sandbox setup
In certain scenarios, a path may exist but is a broken symlink. For
instance, this happens frequently if you are rescuing an existing NixOS
system via `nixos-enter` or a manual `chroot` invocation because the
rescued system `/etc` may have broken links or the system prior to the
root pivot may interfere.

Nonetheless, these dangling symlinks are not always fatal for the builds
so we can just warn and skip their setup.

The warnings will provide a better diagnostics for system administrators
also.

Fixes #893.

Change-Id: Ifa12be3a43f23c973d7b466e8b73bd776abf3e7b
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-26 14:54:59 +00:00
Raito BezariusandMaximilian Bosch 3c614a136b libstore/binary-cache: fix catching JSON exceptions
We were catching ForeignExceptions believing it came from the TRY_AWAIT
handler, but this was misguided.

`j.dump()` is evaluated in synchronous context, outside of the `try {
... } catch (...)` block from `TRY_AWAIT`.

Therefore, we need to use `JSON::Exception` directly.

The previous test case did not catch it because:

(1) https://git.lix.systems/lix-project/lix/issues/865 hid the fact that
`--arg` was wrong.
(2) we did not grep for the warning because… we were not even copying
the strange store path to the binary cache.
(3) checking for the NAR happened after the NAR directory was emptied
for test reasons and this was not even caught neither.

Anyway, the test case was completely busted and has now been tested
without this commit and after this commit and we can confirm that prior
to this commit, the test will fail with an exception trace.

Co-authored-by: Maximilian Bosch <maximilian@mbosch.me>
Change-Id: I8df5befd06c4a449072b987f82a67bc4437e7e49
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-25 21:04:16 +02:00
eldritch horrors 57b1c289b5 treewide: drop PushActivity in favor of explicit context
PushActivity does not work with async code since we have no such thing
as promise-local storage. it will be confusing at best, and completely
wrong at worst, with the current thread-local linking state. if we can
find a way to get promise-local storage we may want to bring this back
though, explicit context passing is rather error-prone. luckily we are
not using parent links for anything important, just to keep the multi-
line activity display from filling up with stuff we're already showing

Change-Id: Ie373d713080a3db811b2d5abd681f78137735e45
2025-07-25 13:05:24 +02:00
eldritch horrors e88a85bd92 build-remote: don't copy failed paths with ssh-ng & --keep-going
checking that the remote build actually succeeded only implied-trusted
remotes or CA derivations makes *absolutely* no sense. we should check
that builds have succeeded before trying to copy them from the remote.

Change-Id: Ib2cf216c580f4c577dd9fef8849acc033ae082b9
2025-07-24 17:56:05 +02:00
Raito Bezarius f6c0aea824 libstore/http: expose HttpBinaryCacheStore in the header
Including the `.cc` is possible but is suspicious.

Change-Id: Ie18fef1e30e517edff4ab96f4a9c339e2b3145b5
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-23 15:35:32 +00:00
sternenseemann cc73479558 Use lowdown 2.0.2 in CI
postInstall needs to know the name of the (versioned) .so file since it
needs to be renamed for Darwin platforms. Unfortunately, the .so version
is not properly overrideable, so we need to use string replacement.

Change-Id: Idf9671f84fac955a52d82a20ec0f381d05fdc762
2025-07-23 16:48:52 +02:00
sternenseemann 858de5f47a 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
2025-07-23 16:45:25 +02:00
eldritch horrors 43d6a79863 libstore: work around capnp fd passing bug
capnp does not handle fd passing correctly in all circumstances. we hit
such cirumstances when passing large closures path lists to build-hook.
since capnp seems to ignore fds passed in non-final segments of any rpc
message we just ensure that the capability including the log fd will be
small enough to not be fragmented on the receiving side of the channel.

cf https://github.com/capnproto/capnproto/issues/2359

Change-Id: Id22309264936b3a57bcc68a0753c3bfb3c9a43d2
2025-07-23 13:53:24 +00:00
2c6542bd9c libstore/http: provide makeOptions hook
Some users may have arbitrary needs to connect to their store URIs, e.g.
mTLS authentication, Kerberos authentication, custom renewal using any
RPC mechanism of their preference and so on.

To avoid encoding all these patterns in Lix itself, we push the
configuration to the plugin boundaries and offer a hook for end users to
inherit from `HttpBinaryCacheStore` and provide new store schemes like
`https+mtls://my.very.secure.cache?tls-certificate=...&tls-key=...` or
`https+krb5://my.kerberos.enabled.cache`.

Co-authored-by: George Shammas <george@shamm.as>
Co-authored-by: eldritch horrors <pennae@lix.systems>
Signed-off-by: Raito Bezarius <raito@lix.systems>
Change-Id: I79f322b1a74632500fc79d53f5c920f9e43fd0c4
2025-07-23 13:17:28 +00:00
Raito Bezarius f8ccd9d572 libutil/async-io: augment read type safety w.r.t to EOFs
Usually, EOFs are represented by returning 0 in the `read` APIs, at
least, this is what read(2) dictate.

As clever creature, we may sum zeroes sometimes (advanced form:
`buf->added(got)`) and forego handling the EOF condition.

To avoid the bug that lurked in remote-store.cc and caused busy looping
if the remote end disconnects suddenly, we return
`Result<Option<size_t>>` forcing the caller to perform a specific
processing for the EOF situation.

The conversion did not raise any other offending code path.

Change-Id: I185fdcb77aa82d87ab0802d66ac37c1363657a73
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-23 10:35:37 +00:00
Jade Lovelace 8a2d25054d libstore: rename confusing const identifiers
Also adds an assert that store path hash part length is what we expect
because it's alarmingly easy to forget to truncate a hash before
throwing it into there. It's kind of messy code, someone could improve
it more later.

Change-Id: I5296ea3d5b854323d092f0256defb598dd5b87e8
2025-07-23 02:51:45 +00:00
eldritch horrors 72cad8918b libstore: fix remote build failures killing everything
remote builds failures used to be signaled via exit status 1 of the
build hook, which in turn only happened because the build errors we
got from remote stores was thrown and bubbled up to main which then
logged the error and exited with code 1. with rpc we cannot do this
any more. barring a rewrite of the worker infra to allow for errors
being reported with something other than process exit codes this is
the best can do. ideally we would wrap remote builds in a new goal.
(and then remove all exit code shenanigans from DerivationGoal too)

fixes #928

Change-Id: Idc3ede3cbaca34c8c8e40247da52794f2a5013b9
2025-07-22 15:32:25 +02:00
eldritch horrors 9eb3c1be80 daemon: restore daemon-trust-override
apparently this feature got lost in the migration to exec'ing daemons.

Change-Id: Iac9425cf6d20781bb49e5cf12f2056f4a3ec23ba
2025-07-22 12:33:49 +00:00
eldritch horrors cb96940042 libstore: pass a log pipe into build-hook
this way we don't have to duplicate build log parsing in the hook.

Change-Id: I1c96b75aea3b4bb747aa0f0cc76c00eace8911c4
2025-07-22 12:33:49 +00:00
eldritch horrors 6ddd3045f0 testing: remove obsolete daemon tests
remove all daemon version checks targeting daemons we no longer support.

Change-Id: If722024c3d66c73fa1b3cdd63134a09389ac6ea5
2025-07-22 10:39:32 +00:00
eldritch horrors d8dfffbe37 daemon: use kj for splicing stdio connections
drop our reimplementation of splice for non-linux in favor of using kj
pumpTo. this avoids select() for its O(maxfd) behavior, and if kj ever
uses something more efficient than read/write loops we'll benefit too.

Change-Id: Id01ba84bf8831455af2d9755bf1a3039d215bb47
2025-07-22 10:39:32 +00:00
Jade Lovelace bf3d52e5bb rl-next: link to the fixed issue for removing old wires
Fixes: https://git.lix.systems/lix-project/lix/issues/510
Change-Id: Ia100f2f0bb48a4880b2c55d5622be9dab25b313b
2025-07-21 15:17:54 -07:00
eldritch horrors 2fc47b65b8 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:25:04 +00:00
K900 97a3a8cb67 readFile: don't explode on negative st_size
Should this ever happen? No. Does it? Evidently.

Change-Id: I62fa7530fbc2cdfd6112088dbc82a4a615cf6820
2025-07-20 11:06:05 +03:00
eldritch horrors 9d8ab80435 libstore: don't wait for empty cgroups to empty
oops. m(

Change-Id: Ia421589e76a9740b3e49133598c893339f92250e
2025-07-18 18:57:19 +02:00
eldritch horrors 6d6cccee75 libstore: restrict build-hook parallelism
previously we only had one build hook in waiting at most because build
hook rpc was synchronous. now that it no longer is we attempt to start
one hook per derivation, which depending on scheduling can be a *very*
large number. restrict the waiting hook count to 4 to some concurrency
without collecting a large number of hooks that may never do anything.

Change-Id: Ic0b1125cec4acd69e8a0d4639c232e71b825e01d
2025-07-18 13:43:02 +02:00
Jade LovelaceandJade Lovelace d906c7965b OWNERS: fix some wrong emails
Change-Id: Id5c5d50eb493a328eaecdf84f33f8bad18c33f5d
2025-07-17 12:36:54 -07:00
Jade LovelaceandJade Lovelace ab33a5b01f manual: reorg contributing docs, talk about gerrit
This section was kind of a mess so I've had a go at making it better.

Change-Id: Ia13b79db9cb0555660abc6ce795f6fe827ee15ad
2025-07-17 12:36:54 -07:00
eldritch horrors ae3b8e58c3 libstore: chown build dirs with --keep-failed
although we only chown if the build was requested by a local daemon
user. daemonless invocations will not chown as they do not have to.
remote builds *can* chown to the remote builder user, but that does
not seem to happen (for some reason keep-failed is not propagated).

Change-Id: Ic0ead406b38b4ca0556fec42d84888efa25123bf
2025-07-17 15:05:32 +02:00
eldritch horrors 9d5a5c4dc0 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
2025-07-16 23:02:16 +00:00
eldritch horrors 8f325fe436 libstore: convert build-hook protocol to rpc
Change-Id: I8da74acdc965aba5091c089101745f7aa501befa
2025-07-15 20:33:30 +02:00
eldritch horrors 8a5a477ca3 treewide: add first batch of capnp rpc types
this touches both libutil and libstore because with no rpc users it
doesn't make that much sense to separate the two. note that all our
strings are represented as Data (ie, blobs) because capnp Text must
be nul-terminated. while it's technically possible to use Text with
strings containing non-terminating NULs it is a bit of a hassle and
could lead to rpc users erroneously stopping at the first NUL byte.

Change-Id: I4c75e03b79a226ffa8d7cd985e3ac632a0cd7c1c
2025-07-15 20:33:30 +02:00
eldritch horrors ca12657a68 build: add capnp compiler wrapper
we need this to generate dependency information, and it'll be the entry
point for custom codegen once we need it. a wrapper also makes it a lot
easier to generate a whole namespace's worth of rpc definitions at once

Change-Id: Iba7a1c92a8a40bede9ed71aa3ab455477ff5e568
2025-07-15 06:40:48 +00:00
eldritch horrors ea11d075e6 libutil: add low-level provider to AsyncContext
without it we can't wrap socket fds for capnp rpc.

Change-Id: I0d603c82d8574b7b0f6eb07b2dff655d94418ec9
2025-07-15 06:40:48 +00:00
eldritch horrors 4a1d16ebca libstore: asyncify build-remote functions
Change-Id: I9fbee928eb955e03c41dfe8ce74bd8a90f5e26cd
2025-07-15 06:40:48 +00:00
eldritch horrors 6877ae5fb8 libstore: handle the entire hook lifecycle in tryBuildHook
if the hook accepts the build request we can handle the entire request
in tryBuildHook. there is no need to punt a partially handled build to
the caller (we only did this to minimize churn during asyncification).

Change-Id: Iec3e35a8103da4fc5fbef394cc28a134ee62a198
2025-07-15 06:40:48 +00:00
eldritch horrors 07ba511921 libutil: add a type-mapping TRY_AWAIT
mapping the result of an await operation before unpacking it lets us
inject rpc type conversion functions without duplicating all that is
needed for proper exception wrapping and async error traces support.

Change-Id: Ibcba1cc6d2b275757e3475881ef20f95dd4d684f
2025-07-15 06:40:48 +00:00
eldritch horrors e01ae1f453 libutil: add generic unix socketpair wrapper
previously we used this only for SSH, but other uses may appear soon.

Change-Id: Ibe9666d63aaea07525ebad57decda88b11964cc0
2025-07-15 06:40:48 +00:00
Jade LovelaceandJade Lovelace f4a11d0336 Draft of OWNERS
Goals:
- Distribute reviews to people who can do the reviews
- Not prevent anything from getting done
- Allow giving away more commit access

Anti-goals:
- Silo people into particular areas
- Discourage contributing to any area

This was drafted by glancing at git logs. It is not likely to be very
accurate; the goal here is that we figure out a way to distribute
reviews to the right people.

Change-Id: I8be44bf7fdeca23da8099124eec7bc3a30e34627
2025-07-14 18:20:47 -07:00
eldritch horrors b43d7b8136 libstore: don't use Outcome<void, T> in goals
`Outcome<void, T>` and `Result<std::optional<T>>` can be interpreted as
being the same thing, but the latter is easier to use: not only do they
allow TRY_AWAIT usage for their promises, we also don't have the error/
exception confusion of outcomes (where the T above is the "error" type)

Change-Id: I92c9241481cecc97e2992445b3dced53c82a2524
2025-07-14 17:02:30 +00:00
eldritch horrors 280772583f libutil: remote unsafeLockFileSingleThreaded
while this does require spawning a thread for every contended lock now
we don't expect performance to be impacted. only build-remote used the
synchronous method, and it only used it to serialize uploads to remote
builders. these uploads are expensive enough to dwarf the thread cost.

Change-Id: Iad0aa0cd738bc96fd06a90d655803dadffa09c47
2025-07-14 17:02:30 +00:00
eldritch horrors df45583c7a libutil: add AsyncContext::timeoutAfter
this is just a Result-aware version of kj's Timer::timeoutAfter.

Change-Id: I17ff77d40201996b9dafc32bbff0298db8a4fcc9
2025-07-14 17:02:30 +00:00
eldritch horrors 9c1e7d4d07 libstore: use AsyncInputStream for reading builder output
DerivationGoal::InputStream existed only because we did not have an
error-reporting AsyncInputStream of our own yet. we do have one now
though and can thus delete old code in favor of the generic variant

Change-Id: I01c7c564554f8794bdf54603b239b7a808faeda0
2025-07-14 17:02:30 +00:00
eldritch horrors 334b8e2b20 libstore: add log-fd to ssh-ng as well
this way we can get ssh error message if connection setup fails.

Change-Id: Ifc001f77ec0477fb9786f7767a47f3745d6475ff
2025-07-14 17:02:30 +00:00
eldritch horrors d20c3d3643 libutil: remove ErrorInfo::programName
it's effectively unused. one use is a write and a read immediately after
the write, the other use checks whether it's not equal to itself (..wat)

Change-Id: I5f6ce26e75a6bfa500c2e9ac3fc70e8dafc9bd74
2025-07-14 17:02:30 +00:00
Alois Wohlschlager 2090853b80 falsify the glibc store paths
Commits 205c59367c and
325e7e1824 introduced real glibc store paths from
current nixpkgs unstable into the source. Since nixpkgs `fetchFromGitea` (and
similar fixed-output derivations) depends on a C library, on x86_64-linux they
will fail with the forbidden reference error:

error: the fixed-output derivation '/nix/store/wnmnj3jzc82y89sfmyicr04kilg8zs2k-source.drv' must not reference store paths but 1 such references were found:
         /nix/store/q4wq65gl3r8fy746v9bbwgx4gzn0r2kl-glibc-2.40-66

Falsify the store path to prevent this failure.

Change-Id: I949033567bcad070f9a0a19cefdb33a79222e421
2025-07-13 10:56:47 +02:00
Jade Lovelace ae00b12983 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
2025-07-11 20:02:00 -07:00
Jade Lovelace 9a8f111af2 darwin: fix repeated delivery of MonitorFdHup callbacks
My lix build failed today with this result:

```
lix> [----------] 3 tests from MonitorFdHup
lix> [ RUN      ] MonitorFdHup.works
lix> [       OK ] MonitorFdHup.works (0 ms)
lix> [ RUN      ] MonitorFdHup.works_with_pipes
lix> stderr:
lix> Using configuration: seed=6402097764877502971
lix> libc++abi: terminating due to uncaught exception of type std::__1::future_error: The state of the promise has already been set.
lix> 4/5 lix:check / libstore-unit-tests        OK              1.10s
lix> 5/5 lix:check / libexpr-unit-tests         OK              1.12s
lix> Summary of Failures:
lix> 3/5 lix:check / libutil-unit-tests  FAIL            0.93s   killed by signal 6 SIGABRT
lix> Ok:                4
lix> Fail:              1
lix> Full log written to /nix/var/nix/builds/nix-build-lix-2.94.0-dev-pre20250711-65ef28d.drv-0/source/build/meson-logs/testlog.txt
```

I had a response best described as "wtf". I think the cause of this
problem is that there's a race condition with the test in which the loop
gets gone around again a second time because it's triggered by the
terminate fd (and I guess the flags remained what they were before?
seems reasonable), and this is probably racing with the quit atomic
being first to break out of the loop.

I don't know how many hundreds of lixes I've compiled without my test
failing, but this is definitely a bug. I don't think this affects actual
usage as the only impact is repeat delivery of Ctrl-C which is harmless
and which users do regularly.

Change-Id: I60da81d4ac2e79052cd323b5171f9d8bd0aa6783
2025-07-11 19:41:18 -07:00
Matthew Bauerandjade 65ef28df6d completions: Show description in zsh completions
Uses the second part of NIX_GET_COMPLETIONS if available.

Change-Id: I35efaaea3f35eea25a8de723ab32ceecd054e7df
Fixes: https://git.lix.systems/lix-project/lix/issues/910
2025-07-11 02:54:08 +00:00
eldritch horrors 1a0d05d852 libstore, build-remote: delete static ssh:// fds
this was a mess. ssh:// remotes used the extra static fds for build
logs, ssh-ng:// remotes did not. ssh-ng remotes did not use them at
all since ssh-ng never redirected them to begin with. we now create
pipes dynamically and only for ssh:// builders, then translate logs
received over these pipes into the same format used by ssh-ng. this
requires a new activity we did not have before, but since we have a
great many activities that rarely show up already this shouldn't be
a problem for external tooling. if anything external tools can tell
what's going on much better now (at least for ssh:// remote builds)

Change-Id: I02010cee45598362a947faa3a5b04800d39daa31
2025-07-09 18:21:20 +00:00
eldritch horrors 11d854281a build-remote: extract connecting to builder
Change-Id: I364f20f1c689f87dd4e6ec98a36b43f34647ff43
2025-07-09 15:48:07 +00:00
eldritch horrors a17771569e build-remote: extract machine selection
Change-Id: Id5abe9a46ee8ba71f00379af31b442c3fa7cda92
2025-07-09 14:20:51 +02:00
eldritch horrors 44895d1ed5 build-remote: extract error message printer
Change-Id: I5eab56be27d6178caa341fb2ff1f52475252aab8
2025-07-09 14:20:51 +02:00
Philipp OtterbeinandRaito Bezarius fc3261c340 libexpr/primops: fix overflows and silent type casts
Avoids incorrect behavior with large integers in `elemAt`, `substring`,
`genList`, etc, which results into crashing the Lix interpreter.

At the same time, unit tests were added for these edge cases with 2^32
as an argument of these primops.

Port of https://github.com/NixOS/nix/pull/13309.
Prior art in https://github.com/NixOS/nix/pull/7222 (forgotten by the original project…).

Change-Id: I1c43ed64f26bcb60e51869e11a74e5de2b7db53a
Co-authored-by: Raito Bezarius <raito@lix.systems>
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-07 23:32:18 +00:00
Raito Bezarius b225794503 libcmd: drop warning about interpretation of store paths
Fixes #897.

Change-Id: Ie4da11d0427d8c9f48cd6e979d80bd39474e8390
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-07 21:13:16 +00:00
eldritch horrors 487b37291f libutil: optimize Sync<T, AsyncMutex>
async queries easily lead to high contention on the localstore sqlite
lock. optimizing the lock wakeup scheme improves query performance by
a linear factor (with the O(waiters) wakeup replaced by O(1) wakeup).
on 100k drv closures we're now at 55s query, down from >8min in 2.93.

Change-Id: I9b96e792c4518a782c690dea92e61260f08f0bad
2025-07-07 18:13:16 +00:00
Maximilian Bosch da0df360e1 libstore: print dependency in tree boldly
That way it's easier to spot whether a node is the "final" node in the
graph which is especially helpful for larger graphs.

Change-Id: I460a699f07f5455917792599f4247ebf8f430d93
2025-07-07 11:44:17 +00:00
Maximilian BoschandRobert Hensing 325e7e1824 libstore: show forbidden chain(s) to forbidden path from disallowedRequisites
Closes #334
Closes #626

This is loosely based on upstream PR#10877[1], but heavily changed to
use the graph logic from `nix why-depends`.

`precise` is `false` here since the out-path of the drv being built
isn't registered yet, so the path accessor cannot scan through files
yet.

Example output (from an openssh build with `pcsclite.lib` & `glibc` in
`disallowedRequisites`):

    error: output '/nix/store/hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2' is not allowed to refer to the following paths:
           /nix/store/p6r5awz3ywrz66symnrn0xb85xzmcysf-pcsclite-2.3.0-lib
           /nix/store/q4wq65gl3r8fy746v9bbwgx4gzn0r2kl-glibc-2.40-66
           Shown below are chains that lead to the forbidden path(s).
           /nix/store/hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2
           └───/nix/store/ys91ywnwikm14xznwk3cdbprapv2m37z-libfido2-1.16.0
               └───/nix/store/p6r5awz3ywrz66symnrn0xb85xzmcysf-pcsclite-2.3.0-lib
           /nix/store/hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2
           ├───/nix/store/q4wq65gl3r8fy746v9bbwgx4gzn0r2kl-glibc-2.40-66
           ├───/nix/store/6r4zqb04fq5l5l4zghq76wvcpz7dwd35-linux-pam-1.6.1
           │   ├───/nix/store/q4wq65gl3r8fy746v9bbwgx4gzn0r2kl-glibc-2.40-66
           [...]

[1] https://github.com/NixOS/nix/pull/10877

Co-authored-by: Robert Hensing <robert@roberthensing.nl>
Change-Id: Ib30024c0d9e45c1160bf0134f7d3ba17dbdeff47
2025-07-07 11:44:17 +00:00
Maximilian Bosch 114bc770e3 doc: remove ignoreSelfRefs from docs
While working on the LocalDerivationGoal code, I realized that this
attribute is only set to `false`/`true` depending on whether
`__structuredAttrs` is `true`/`false`.

Change-Id: I53868cd32cedd7e25cb6233bd93bc01111b56a07
2025-07-07 11:44:17 +00:00
Maximilian Bosch 205c59367c libstore: add genGraphString from why-depends
This will be useful for other things as well such as the
disallowedRequisites error in the builder code. Additionally, print the
dependencyPath in the tree bold to spot where a change terminates.

Also implemented some unit-tests for this code.

Change-Id: I8460f3f6c5095d5bfbe390f223bc0252800dca5e
2025-07-07 11:44:17 +00:00
Maximilian Bosch 5ab5f7d96c why-depends: add entrypoint for graph builder API
The now-introduced genGraphString will be the public API of the libstore
helper.

Change-Id: Id47d21230d1a30b880f298f307c30ddffdb0e9c7
2025-07-07 11:44:17 +00:00
Maximilian Bosch 49263f154a why-depends: initialize internal graph data from std::map<StorePath, StorePathSet>
The Node struct should become an implementation detail when moving this
into libstore. A map from a node to its direct references is more
intuitive here.

Change-Id: I9fddce6b398b8bb97834e5586bee72b244885fdd
2025-07-07 11:44:17 +00:00
Maximilian Bosch 353a87727b why-depends: refactor Node struct
* Better name for refs
* Use std::optional<T> for distance

Suggested-by: eldritch horrors <pennae@lix.systems>
Change-Id: Ie35c3f2a7ea1a90ce3a9807025d0af9ea73e2403
2025-07-07 11:44:17 +00:00
Maximilian Bosch 57e071e815 why-depends: asyncify printNode
Instead of logging directly, we now write into a `Strings` set that is
referenced by the caller.

While at it, added a test-case to ensure that self-reference invocations
and --all behave properly.

Change-Id: Ib183ab8e8e90436300e1c870fb3ae8f18730abbf
2025-07-07 11:44:17 +00:00
Maximilian Bosch 1d6c8bff77 why-depends: extract printNode
Change-Id: Ia0ba08745b9498fdbcc4231f91bf3d45afbe8373
2025-07-07 11:44:17 +00:00
Maximilian Bosch c2693327d9 why-depends: asyncify visitPath
Change-Id: If42e2a5ed6069817e66aeff3e2de1f69e5e526b1
2025-07-07 11:44:17 +00:00
Maximilian Bosch 7b84545ce1 why-depends: extract visitPath function
First step towards moving this code into libstore to re-use it
elsewhere.

Change-Id: I1daccd984f759b235c4c187d5c7783cb5a35f0b9
2025-07-07 11:44:17 +00:00
K900 4bc0bdc20b nix-eval-jobs: run tests with -v
That way we get a line of output per test completed,
which makes it more obvious it's actually doing things.

Change-Id: Ifbbe8bdf64e7178d3c59349cf071eb5a9d0fcd32
2025-07-06 21:31:48 +03:00
K900andeldritch horrors 378b360bf8 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
2025-07-06 21:11:41 +03:00
eldritch horrors 33784540c4 libutil: fix signaling handling on darwin
this partially reverts commit 0cc021ee15,
which for some reason is completely broken on darwin: there seems to be
no way to receive process-directed signals on a non-main thread. trying
to do it anyway will fail silently. since we only ever used kj for this
to get signal handling timeouts on darwin (which lacks sigtimedwait) to
print a nice message about retrying ^C again we can work around this by
moving the message printing into a fresh, unrelated, non-signal thread.

Change-Id: I5939c6ec62a7e1dc1b3f16067f77277533949fa0
2025-07-06 17:47:42 +02:00
Raito Bezarius df58bffc0f doc/rl-next: missed credit for the symbol reuse work
We missed xokdvium being author on cl/3300. This is something we
absolutely want to avoid.

We credit xokdvium in the RL and add a note on this problem.

Thanks to xokdvium for reaching out in private to us so we can repair
this mistake.

Change-Id: I094d0f95b6647104621d6b228e69a4529a300304
Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-07-06 11:03:07 +00:00
eldritch horrors 29d9a88af6 libutil: handle sigint only once per thread
many a cleanup path has been broken by interruptions being thrown every
time checkInterrupt is called. we should only throw *once* though; more
than one Interrupted exception for the same event is not only confusing
but also breaks all cleanup paths at the first checkInterrupt call site
(e.g. #900, the cgroup cleanup saga, temp dirs not being removed, etc).

Change-Id: Ibfabf7f6af6ac2b78ad93582c254bbc48fcb3073
2025-07-06 10:45:55 +00:00
eldritch horrors b1544582af libutil: quit immediately on second sigint
we must be crash-safe *anyway*, and being unable to interrupt lix if it
gets stuck somewhere that never calls checkInterrupt is really annoying

Change-Id: I7c40271c3da7e69d8735e22b7b7c4751b5306ab6
2025-07-05 16:27:47 +02:00
eldritch horrors 0cc021ee15 libutil: asyncify signal handler thread
macos doesn't have sigtimedwait and we need signal wait timeouts in
order to print a "please hit ^C again" message with a bit of delay.

Change-Id: If574fb1a9de0b19975b34fc63662b089eaedc9d2
2025-07-04 22:59:13 +02:00
eldritch horrors 9dbf46f573 cli: asyncify daemonLoop
another checkInterrupt can be a makeInterruptible wrapper now. this is
also necessary to add a second daemon socket for the new rpc protocol.

Change-Id: I55055f975335a75708f1f73edb75f7bfe77a5938
2025-07-04 21:12:12 +02:00
1673 changed files with 44718 additions and 23109 deletions
+4 -3
View File
@@ -4,9 +4,10 @@ AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignEscapedNewlines: Left
AlignOperands: DontAlign
AllowShortBlocksOnASingleLine: Always
AlignTrailingComments: false
AllowShortBlocksOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortIfStatementsOnASingleLine: Never
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
@@ -35,7 +36,7 @@ BreakAfterAttributes: Always
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
ColumnLimit: 100
ColumnLimit: 110
EmptyLineAfterAccessModifier: Leave
EmptyLineBeforeAccessModifier: Leave
FixNamespaceComments: false
+4 -7
View File
@@ -8,18 +8,16 @@ Checks:
- -bugprone-narrowing-conversions
# kind of nonsense
- -bugprone-easily-swappable-parameters
# too many warnings for now
- -bugprone-implicit-widening-of-multiplication-result
# Lix's exception handling is Questionable
- -bugprone-empty-catch
# many warnings
- -bugprone-unchecked-optional-access
# many warnings, seems like a questionable lint
- -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
@@ -27,9 +25,6 @@ Checks:
# crimes must be appropriately declared as crimes
- cppcoreguidelines-pro-type-cstyle-cast
- lix-*
# This can not yet be applied to Lix itself since we need to do source
# reorganization so that lix/ include paths work.
- -lix-fixincludes
# This lint is included as an example, but the lib function it replaces is
# already gone.
- -lix-hasprefixsuffix
@@ -38,3 +33,5 @@ Checks:
CheckOptions:
bugprone-reserved-identifier.AllowedIdentifiers: '__asan_default_options'
bugprone-unused-return-value.AllowCastToVoid: true
ExtraArgs: ["-Werror=unnecessary-virtual-specifier"]
+3
View File
@@ -41,3 +41,6 @@ buildtime.bin
*.pyc
**/.idea
# Yeah, I've got no clue.
/subprojects/.wraplock
+3
View File
@@ -1,2 +1,5 @@
Fiona Behrens <me@kloenk.dev>
Fiona Behrens <me@kloenk.dev> <me@kloenk.de>
rootile <lix@rootile.de>
rootile <lix@rootile.de> <commentator2.0@crystal-cavern.systems>
rootile <lix@rootile.de> <lix@crystal-cavern.systems>
Generated
+7 -3
View File
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "countme"
@@ -39,6 +39,10 @@ dependencies = [
"rowan",
]
[[package]]
name = "lixutil-rs"
version = "0.0.0"
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -47,9 +51,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "rnix"
version = "0.11.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb35cedbeb70e0ccabef2a31bcff0aebd114f19566086300b8f42c725fc2cb5f"
checksum = "6f15e00b0ab43abd70d50b6f8cd021290028f9b7fdd7cdfa6c35997173bc1ba9"
dependencies = [
"rowan",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["lix/lix-doc"]
members = ["lix/lix-doc", "lix/libutil"]
[workspace.package]
edition = "2021"
+26
View File
@@ -0,0 +1,26 @@
# 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
View File
@@ -0,0 +1 @@
*
+157 -36
View File
@@ -7,15 +7,44 @@ import os
import json
import tempfile
import platform
import shlex
import textwrap
import dataclasses
flake_args = ["--extra-experimental-features","'nix-command flakes'"]
# hyperfine has its own variable substitution, so we use that and pass build="{BUILD}" here.
# perf doesn't have variable substitution, so we call these with build being the actual build directory.
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", "'with import <nixpkgs/nixos> {}; system'"],
"rebuild_lh": lambda build: ["GC_INITIAL_HEAP_SIZE=10g", f"{build}/bin/nix", *flake_args, "eval", "--raw", "--impure", "--expr", "'with import <nixpkgs/nixos> {}; system'"],
"parse": lambda build: [f"{build}/bin/nix", *flake_args, "eval", "-f", "bench/nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix"],
"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()
@@ -24,46 +53,81 @@ arg_parser = argparse.ArgumentParser()
# 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")
available_modes = [ "walltime" ] + [ "icount" ] if platform.system() == 'Linux' else [] # perf doesn't run on Darwin
arg_parser.add_argument('--mode', choices=available_modes, default="walltime")
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) < 2:
raise ValueError("need at least two build directories to compare")
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}")
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):
hyperfine_args = ["--parameter-list", "BUILD", ','.join(args.builds), "--warmup", "2", "--runs", "10"]
for case in benchmarks:
case_command = cases[case]("{BUILD}") # see the comment on cases
subprocess.run([
"taskset", "-c", "2,3",
"chrt", "-f","50",
"hyperfine", *hyperfine_args, "--export-json", f"bench/bench-{case}.json", "--export-markdown", f"bench/bench-{case}.md", "--", " ".join(case_command)
], env=env, check=True)
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:
fd = open(f"bench/bench-{case}.json")
result_json = json.load(fd)
fd.close()
for result in result_json["results"]:
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"])))
attr_rounded = lambda attr: f"{result[attr]:.3f}"
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"]/result_json["results"][0]["mean"]:.3f}")
print(" relative:", f"{result["mean"]/results[0]["mean"]:.3f}")
print("\n")
@@ -71,12 +135,14 @@ def bench_icount(env):
perf_results_for: dict[str, list[tuple[str, float]]] = {}
for case in benchmarks:
for build in args.builds:
case_command = cases[case](build)
# 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", " ".join(case_command)
"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")
@@ -84,8 +150,9 @@ def bench_icount(env):
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((" ".join(case_command), float(instr["counter-value"])))
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():
@@ -97,6 +164,54 @@ def bench_icount(env):
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([
@@ -108,9 +223,15 @@ with tempfile.TemporaryDirectory() as tmp_dir:
subenv = os.environ.copy()
subenv["NIX_CONF_DIR"] = "/var/empty"
subenv["NIX_REMOTE"] = tmp_dir
subenv["NIX_PATH"] = "nixpkgs=bench/nixpkgs:nixos-config=bench/configuration.nix"
subenv["NIX_PATH"] = ":".join([
"nixpkgs=bench/nixpkgs",
])
subenv["NIX_DAEMON_SOCKET_PATH"] = f"{tmp_dir}/daemon"
if args.mode == "walltime":
bench_walltime(subenv)
else:
bench_icount(subenv)
for mode in args.mode:
if mode == "walltime":
bench_walltime(subenv)
elif mode == "memory":
bench_memory(subenv)
else:
bench_icount(subenv)
-314
View File
@@ -1,314 +0,0 @@
{
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";
}
+1
View File
@@ -0,0 +1 @@
*
+19
View File
@@ -0,0 +1,19 @@
# Darwin: don't link liblix* into plugins (host process provides them at runtime).
# Explicitly link curl so it binds to Nix-store libcurl, not /usr/lib/libcurl.
if is_darwin
plugin_deps = [
liblix.partial_dependency(includes : true, compile_args : true),
curl,
]
else
plugin_deps = [liblix, curl]
endif
plugin_mtls_store = shared_module(
'plugin_mtls_store',
'plugin_mtls_store.cc',
dependencies : plugin_deps,
install : false,
build_by_default : true,
link_args : is_darwin ? shared_module_link_args : strict_shared_module_link_args,
)
@@ -0,0 +1,14 @@
R"(
**Store URL format**: `https+mtls://...`
This store allows a binary cache to be accessed via HTTPS with mutual TLS (client certificate authentication).
Both parameters are required:
- `tls-certificate`, a path to the TLS client certificate
- `tls-private-key`, a path to the TLS private key backing the client certificate
If you don't need mTLS, use `https://` instead.
)"
+102
View File
@@ -0,0 +1,102 @@
#include "lix/libstore/store-api.hh"
#include "lix/libutil/config.hh"
#include "lix/libstore/http-binary-cache-store.hh"
#include <stdlib.h>
#include <curl/curl.h>
namespace nix {
struct mTLSBinaryCacheStoreConfig : HttpBinaryCacheStoreConfig
{
using HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig;
const std::string name() override
{
return "mTLS HTTP Binary Cache Store";
}
std::string doc() override
{
return
#include "mtls-http-binary-cache-store.md"
;
}
PathsSetting<nix::Path> tlsCertificate{
this,
"",
"tls-certificate",
"Path of the TLS client certificate in PEM format as expected by CURLOPT_SSLCERT"
};
PathsSetting<nix::Path> tlsKey{
this,
"",
"tls-private-key",
"Path of the TLS client certificate private key in PEM format as expected by CURLOPT_SSLKEY"
};
};
struct mTLSBinaryCacheStoreImpl : public HttpBinaryCacheStore
{
struct Keyring
{
nix::Path tlsCertificate;
nix::Path tlsKey;
};
mTLSBinaryCacheStoreConfig config_;
std::shared_ptr<Keyring> keyring;
mTLSBinaryCacheStoreConfig & config() override
{
return config_;
}
const mTLSBinaryCacheStoreConfig & config() const override
{
return config_;
}
mTLSBinaryCacheStoreImpl(
const std::string & uriScheme, const Path & _cacheUri, mTLSBinaryCacheStoreConfig config
)
: Store(config)
, HttpBinaryCacheStore("https", _cacheUri, config)
, config_(std::move(config))
, keyring(std::make_shared<Keyring>(config_.tlsCertificate.get(), config_.tlsKey.get()))
{
}
FileTransferOptions makeOptions(Headers && headers = {}) override
{
auto options = HttpBinaryCacheStore::makeOptions(std::move(headers));
auto baseExtraSetup = std::move(options.extraSetup);
auto keyring = this->keyring;
options.extraSetup = [keyring, baseExtraSetup{std::move(baseExtraSetup)}](CURL * req) {
if (baseExtraSetup) {
baseExtraSetup(req);
}
const bool haveCert = !keyring->tlsCertificate.empty();
const bool haveKey = !keyring->tlsKey.empty();
if (!(haveCert && haveKey)) {
throw Error("https+mtls requires both tls-certificate and tls-private-key");
}
curl_easy_setopt(req, CURLOPT_SSLCERT, keyring->tlsCertificate.c_str());
curl_easy_setopt(req, CURLOPT_SSLKEY, keyring->tlsKey.c_str());
};
return options;
}
static std::set<std::string> uriSchemes()
{
return {"https+mtls"};
}
};
}
extern "C" void nix_plugin_entry()
{
nix::StoreImplementations::add<nix::mTLSBinaryCacheStoreImpl, nix::mTLSBinaryCacheStoreConfig>();
}
+15 -9
View File
@@ -1,9 +1,15 @@
(import (
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
) { src = ./.; }).defaultNix
let
lockFile = builtins.fromJSON (builtins.readFile ./flake.lock);
flake-compat-node = lockFile.nodes.${lockFile.nodes.root.inputs.flake-compat};
flake-compat = builtins.fetchTarball {
inherit (flake-compat-node.locked) url;
sha256 = flake-compat-node.locked.narHash;
};
flake = (
import flake-compat {
src = ./.;
}
);
in
flake.defaultNix
+1
View File
@@ -0,0 +1 @@
*
+3 -3
View File
@@ -24,8 +24,8 @@ def map_contents_recursively(transformer):
def process_command:
.[0] as $context |
.[1] as $body |
$body + {
sections: $body.sections | map(map_contents_recursively(if $context.renderer == "html" then transform_anchors_html else transform_anchors_strip end)),
};
# XXX FUTURE: drop sections once mdBook is at 0.5.0 or above in nixpkgs
$body | (.items? // .sections) |= map(map_contents_recursively(if $context.renderer == "html" then transform_anchors_html else transform_anchors_strip end))
;
process_command
+6 -5
View File
@@ -22,20 +22,21 @@ fold.level = 30
# not want to disable the links preprocessor entirely though because that requires
# disabling *all* built-in preprocessors and selectively reenabling those we want.
[preprocessor.substitute]
command = "python3 doc/manual/substitute.py"
command = "python3 substitute.py"
before = ["anchors", "links"]
[preprocessor.anchors]
renderers = ["html"]
command = "jq --from-file doc/manual/anchors.jq"
command = "jq --from-file anchors.jq"
[output.markdown]
[output.linkcheck]
# XXX FUTURE: may be reenabled once mdBook 0.5.0 or above and matching mdbook-linkchecker are in nixpkgs
#[output.linkcheck]
# no Internet during the build (in the sandbox)
follow-web-links = false
#follow-web-links = false
# mdbook-linkcheck does not understand [foo]{#bar} style links, resulting in
# excessive "Potential incomplete link" warnings. No other kind of warning was
# produced at the time of writing.
warning-policy = "ignore"
#warning-policy = "ignore"
+51
View File
@@ -77,10 +77,20 @@ edolstra:
display_name: Eelco Dolstra
github: edolstra
emilazy:
display_name: Emily
forgejo: emilazy
github: emilazy
ericson:
display_name: John Ericson
github: ericson2314
getchoo:
display_name: Seth Flynn
forgejo: getchoo
github: getchoo
gilice:
forgejo: gilice
@@ -89,6 +99,9 @@ goldstein:
forgejo: goldstein
github: GoldsteinE
gustavderdrache:
github: gustavderdrache
horrors:
display_name: eldritch horrors
forgejo: pennae
@@ -115,6 +128,16 @@ jade:
just1602:
forgejo: just1602
k900:
display_name: K900
forgejo: K900
github: K900
kasimeka:
display_name: ورد
forgejo: janw4ld
github: kasimeka
kfears:
display_name: KFears
forgejo: kfearsoff
@@ -153,11 +176,19 @@ ma27:
matthewbauer:
github: matthewbauer
mic92:
github: mic92
midnightveil:
display_name: julia
forgejo: midnightveil
github: midnightveil
milibopp:
display_name: Emilia Bopp
forgejo: milibopp
github: milibopp
nan-git:
display_name: NaN-git
github: NaN-git
@@ -165,6 +196,9 @@ nan-git:
ncfavier:
github: ncfavier
nkk0:
github: nkk0
not-my-profile:
display_name: Martin Fischer
github: not-my-profile
@@ -211,9 +245,16 @@ roberth:
display_name: Robert Hensing
github: roberth
rootile:
display_name: rootile (Rutile)
forgejo: rootile
seppel3210:
github: Seppel3210
stevalkr:
github: stevalkr
teofilc:
forgejo: teofilc
github: TeofilC
@@ -240,6 +281,9 @@ vigress8:
forgejo: vigress8
github: vigress8
vlaci:
github: vlaci
vlinkz:
display_name: Victor Fuentes
forgejo: vlinkz
@@ -252,6 +296,13 @@ winter:
xanderio:
github: xanderio
xokdvium:
github: xokdvium
xyenon:
forgejo: xyenon
github: xyenon
yorickvp:
github: yorickvp
+2 -2
View File
@@ -69,7 +69,7 @@ let
let
result = squash ''
- ${
if inlineHTML then ''<span id="conf-${name}">[`${name}`](#conf-${name})</span>'' else ''`${name}`''
if inlineHTML then ''<span id="conf-${name}">[`${name}`](#conf-${name})</span>'' else "`${name}`"
}
${indent " " body}
@@ -225,7 +225,7 @@ let
showCategory = cat: ''
${optionalString (cat != "") "**${cat}:**"}
${listOptions (filterAttrs (n: v: v.category == cat) allOptions)}
${listOptions (filterAttrs (n: v: v.category == cat && !v.hidden) allOptions)}
'';
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
showOption =
+9 -4
View File
@@ -41,9 +41,13 @@ manual = custom_target(
'-euo', 'pipefail',
'-c',
'''
@0@ @INPUT0@ @CURRENT_SOURCE_DIR@ > @DEPFILE@
cd @SOURCE_ROOT@
@1@ build doc/manual -d @2@ | { grep -Fv "because fragment resolution isn't implemented" || :; }
@0@ @INPUT0@ @3@ > @DEPFILE@
# Needs to be in lix/doc/manual for e.g. substitute.py
pushd @3@
@1@ build . -d @2@
popd
rm -rf @2@/manual
mv @2@/html @2@/manual
find @2@/manual -iname meson.build -delete
@@ -51,6 +55,7 @@ manual = custom_target(
python.full_path(),
mdbook.full_path(),
meson.current_build_dir(),
meson.current_source_dir()
),
],
input : [
@@ -81,7 +86,7 @@ manual = custom_target(
depfile : 'manual.d',
env : {
'RUST_LOG': 'info',
'MDBOOK_SUBSTITUTE_SEARCH': meson.current_build_dir() / 'src',
'MANUAL_SUBSTITUTE_SEARCH': meson.current_build_dir() / 'src',
},
)
manual_md = manual[1]
-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).
-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.
-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.
```
-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,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.
-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.
-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: []
cls: [3249]
significance: significant
category: "Breaking Changes"
credits: [horrors]
---
Support for daemon wire protocols belonging to Nix 2.18 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.
@@ -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.
-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.
-32
View File
@@ -1,32 +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, 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.
@@ -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.
+5
View File
@@ -39,6 +39,9 @@
- [Tuning Cores and Jobs](advanced-topics/cores-vs-jobs.md)
- [Verifying Build Reproducibility](advanced-topics/diff-hook.md)
- [Using the `post-build-hook`](advanced-topics/post-build-hook.md)
- [Pasta](advanced-topics/pasta.md)
- [Known Issues](known-issues/known-issues.md)
- [Limitations around non-isolated builds](known-issues/non-isolated-build-limits.md)
- [Command Reference](command-ref/command-ref.md)
- [Common Options](command-ref/opt-common.md)
- [Common Environment Variables](command-ref/env-common.md)
@@ -197,6 +200,8 @@
- [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.95 (2026-03-13)](release-notes/rl-2.95.md)
- [Lix 2.94 (2025-11-17)](release-notes/rl-2.94.md)
- [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)
@@ -41,106 +41,17 @@ contains Nix.
> If you are building via the Lix daemon (default on Linux and macOS), it is the Lix daemon user account (that is, `root`) that should have SSH access to a user (not necessarily `root`) on the remote machine.
>
> Furthermore, `root` needs to have the public host keys for the remote system in its `.ssh/known_hosts`.
> To add them to `known_hosts` for root, do `ssh-keyscan USER@HOST | sudo tee -a ~root/.ssh/known_hosts`.
> To add them to `known_hosts` for root, do `ssh-keyscan HOST | sudo tee -a ~root/.ssh/known_hosts`.
>
> If you cant or dont want to configure `root` to be able to access the remote machine, you can use a private Nix store instead by passing e.g. `--store ~/my-nix` when running a Nix command from the local machine.
## Configuration
The list of remote machines can be specified on the command line or in
the Lix configuration file. The former is convenient for testing. For
example, the following command allows you to build a derivation for
`x86_64-darwin` on a Linux machine:
```console
$ uname
Linux
$ nix build --impure \
--expr '(with import <nixpkgs> { system = "x86_64-darwin"; }; runCommand "foo" {} "uname > $out")' \
--builders 'ssh://mac x86_64-darwin'
[1/0/1 built, 0.0 MiB DL] building foo on ssh://mac
$ cat ./result
Darwin
```
It is possible to specify multiple builders separated by a semicolon or
a newline, e.g.
```console
--builders 'ssh://mac x86_64-darwin ; ssh://beastie x86_64-freebsd'
```
Each machine specification consists of the following elements, separated
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`
For backward compatibility, `ssh://` may be omitted. The hostname
may be an alias defined in your `~/.ssh/config`.
2. A comma-separated list of Nix platform type identifiers, such as
`x86_64-darwin`. It is possible for a machine to support multiple
platform types, e.g., `i686-linux,x86_64-linux`. If omitted, this
defaults to the local platform type.
3. The SSH identity file to be used to log in to the remote machine. If
omitted, SSH will use its regular identities.
4. The maximum number of builds that Lix will execute in parallel on
the machine. Typically this should be equal to the number of CPU
cores. For instance, the machine `itchy` in the example will execute
up to 8 builds in parallel.
5. The “speed factor”, indicating the relative speed of the machine. If
there are multiple machines of the right type, Lix will prefer the
fastest, taking load into account.
6. A comma-separated list of *supported features*. If a derivation has
the `requiredSystemFeatures` attribute, then Lix will only perform
the derivation on a machine that has the specified features. For
instance, the attribute
```nix
requiredSystemFeatures = [ "kvm" ];
```
will cause the build to be performed on a machine that has the `kvm`
feature.
7. A comma-separated list of *mandatory features*. A machine will only
be used to build a derivation if all of the machines mandatory
features appear in the derivations `requiredSystemFeatures`
attribute.
8. The (base64-encoded) public host key of the remote machine. If omitted, SSH
will use its regular known-hosts file. Specifically, the field is calculated
via `base64 -w0 /etc/ssh/ssh_host_ed25519_key.pub`.
For example, the machine specification
nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 1 kvm
nix@itchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 8 2
nix@poochie.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto 1 2 kvm benchmark
specifies several machines that can perform `i686-linux` builds.
However, `poochie` will only do builds that have the attribute
```nix
requiredSystemFeatures = [ "benchmark" ];
```
or
```nix
requiredSystemFeatures = [ "benchmark" "kvm" ];
```
`itchy` cannot do builds that require `kvm`, but `scratchy` does support
such builds. For regular builds, `itchy` will be preferred over
`scratchy` because it has a higher speed factor.
the Lix configuration file. The former is convenient for testing.
Additionally, there are two supported formats to configure remote builders:
The legacy, "space"-separated format and starting with Lix 2.95.0, a TOML.
Remote builders can also be configured in `nix.conf`, e.g.
@@ -159,3 +70,180 @@ option `builders-use-substitutes` in your local `nix.conf`.
To build only on remote builders and disable building on the local
machine, you can use the option `--max-jobs 0`.
---
Each machine specification consists of the following attributes.
How those are combined within the configuration file differs for the formats, and will be explained further down.
1. `uri` (**required**)
The URI of the remote store in the format
`ssh[-ng]://[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[-ng]://nix@mac?port=1337`. The hostname
may be an alias defined in your `~/.ssh/config`.
2. `system-types` (**optional**)
A list of Nix platform type identifiers, such as
`x86_64-darwin`. It is possible for a machine to support multiple
platform types, e.g., `i686-linux` and `x86_64-linux`.
Defaults to the local platform type
3. `ssh-key` (**optional**)
The SSH identity file to be used to log in to the remote machine.
Defaults to SSHs regular identities.
4. `jobs` (**optional**)
The maximum number of builds that Lix will execute in parallel on
the machine. Typically, this should be equal to the number of CPU
cores divided by the cores within the target machines configuration, i.e. `jobs * cores ~= cpu cores`
Defaults to 1; must be a positive integer.
5. `speed-factor`
The “speed factor”, indicating the relative speed of the machine. If
there are multiple machines of the right type, Lix will prefer the
fastest, taking load into account.
Defaults to 1; must be a positive float.
6. `supported-features` (**optional**)
A list of *supported features*. If a derivation has
the `requiredSystemFeatures` attribute, then Lix will only schedule
the derivation on a machine that has the specified features. For
example, the attribute
```nix
requiredSystemFeatures = [ "kvm" ];
```
will cause the build to be performed on a machine that has the `kvm`
feature.
Defaults to an empty list.
7. `mandatory-features` (**optional**)
A list of *mandatory features*. A machine will only
be used to build a derivation if all the machines mandatory
features appear in the derivations `requiredSystemFeatures`
attribute.
Defaults to an empty list.
8. `ssh-public-host-key` (**optional**)
The public host key of the remote machine.
Defaults to basic ssh behavior (checking contents of the known-hosts file)
### Using a TOML configuration
Each machine is configured as an attribute within the map called `machines`.
The attributes name is the machines name.
Attributes can be in any order.
For example:
```toml
version = 1
[machines.andesite]
uri = "ssh://lix@andesite.lix.systems" # toml also allows for comments
system-types = ["i686-linux"]
jobs = 8
speed-factor = 1.0
supported-features = ["kvm"]
ssh-key = "/home/deepslate/.ssh/id_ed25519"
[machines.diorite]
uri = "ssh://lix@diorite.lix.systems"
system-types = ["i686-linux"]
jobs = 8
speed-factor = 2.0
ssh-key = "/home/deepslate/.ssh/id_ed25519"
[machines.granite]
uri = "ssh://lix@granite.lix.systems"
system-types = ["i686-linux"]
jobs = 1
speed-factor = 2.0
supported-features = ["kvm", "benchmark"]
ssh-key = "/home/deepslate/.ssh/id_ed25519"
[machines.legacy]
uri = "ssh://nix@nix-15-11.nixos.org"
enable = false
```
> **Note**
>
> If the version tag is omitted (e.g. in the CLI), it defaults to the latest version.
> It is strongly recommended to always provide a version tag for configuration within files to avoid breakage.
For testing purposes, one can also define a builder ad hoc on the CLI as follows:
`--builders 'machines.andesite = {uri = "ssh://lix@andesite.lix.systems", jobs = 8}'`
#### Special handling of fields
- `enable` (**optional**)
If set to false, the declared machine will not be loaded.
This allows one to statically disable machines.
Defaults to true
### Using the legacy format
> **Warning**
>
> This format is frozen and new features / configuration options will not be backported to this format.
It is possible to specify multiple builders separated by a semicolon or
a newline, e.g.
```console
--builders 'ssh://mac x86_64-darwin ; ssh://beastie x86_64-freebsd'
```
Every machine specification consists of the elements listed in the section above, seperated by any amount of spaces or tabs.
The Attributes need to be provided **in order** and without names.
To leave a field at its default, set it to `-`.
Lists are colon seperated, without additional spaces.
```
lix@andesite.lix.systems i686-linux /home/deepslate/.ssh/id_ed25519 8 1 kvm
lix@diorite.lix.systems i686-linux /home/deepslate/.ssh/id_ed25519 8 2
lix@granite.lix.systems i686-linux /home/deepslate/.ssh/id_ed25519 1 2 kvm benchmark
```
#### Special handling of fields
- `uri`: Due to backward compatibility, the `ssh://` may be omitted for the store-uri.
- `ssh-public-host-key`: The key must be provided encoded in base64. Specifically calculated via `base64 -w0 /etc/ssh/ssh_host_ed25519_key.pub`
### Format detection
At first, the given configuration is being parsed syntactically as a toml.
If parsing fails and the given configuration contains a `"` the error is presented to the user, as those characters are necessary for TOML, but disallowed for the legacy format.
Otherwise, parsing is retried using the legacy format.
If non-syntactic errors are detected within the toml, the exception will always be shown to the user directly.
## Builder selection
The configuration(s) above specify several machines that can perform `i686-linux` builds.
However, `granite` will only do builds that have the attribute
```nix
requiredSystemFeatures = [ "benchmark" ];
```
or
```nix
requiredSystemFeatures = [ "benchmark" "kvm" ];
```
`diorite` cannot do builds that require `kvm`, but `andesite` does support
such builds. For regular builds, `diorite` will be preferred over
`andesite` because it has a higher speed factor.
+19
View File
@@ -0,0 +1,19 @@
# [Pasta](https://passt.top/passt/about/): a network sandbox for fixed-output derivations
## Introduction
This section only applies to **Linux systems** as Pasta is a Linux-only measure.
Since [CVE-2025-46416](https://lix.systems/blog/2025-06-24-lix-cves/), the Lix project decided to adopt [Pasta](https://passt.top/passt/about/) for all fixed-output derivations, protecting against various attack vectors such as UNIX abstract domain sockets or more manipulation at the network layer from a malicious fixed-output derivation code.
Pasta acts as a translation layer between a layer-2 network interface and layer-4 sockets (TCP, UDP, ICMP/ICMPv6 echo) on the host. It requires no special privileges and can serve as a alternative to [SLiRP](https://en.wikipedia.org/wiki/Slirp) which was used [by Guix to mitigate the same problem](https://codeberg.org/guix/guix/commit/fb42611b8f27960304db5a1c0d33b8371dcde2a8).
## How to disable Pasta?
It's sufficient to pass `pasta-path = ""` in your `/etc/nix/nix.conf` or on the command line `--pasta-path ""` of a Lix invocation.
## Known issues surrounding Pasta
- Only the first DNS server in `/etc/resolv.conf` is considered: failover is not possible.
- [Reduced feature set compared to the Linux kernel](https://passt.top/passt/about/#features)
- [Performance overhead in multi-gigabits contexts and IMIX MTUs](https://passt.top/passt/about/#performance_1)
+1 -1
View File
@@ -58,7 +58,7 @@ $ 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`.
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://channels.nixos.org/$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.
+3 -3
View File
@@ -11,7 +11,7 @@
Channels are a mechanism for referencing remote Nix expressions and conveniently retrieving their latest version.
The moving parts of channels are:
- The official channels listed at <https://nixos.org/channels>
- The official channels listed at <https://channels.nixos.org>
- 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)
@@ -77,9 +77,9 @@ This command has the following operations:
Subscribe to the Nixpkgs channel and run `hello` from the GNU Hello package:
```console
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
$ nix-channel --add https://channels.nixos.org/nixpkgs-unstable
$ nix-channel --list
nixpkgs https://nixos.org/channels/nixpkgs
nixpkgs https://channels.nixos.org/nixpkgs
$ nix-channel --update
$ nix-shell -p hello --run hello
hello
+14 -7
View File
@@ -107,20 +107,27 @@ 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`
- `--raw`\
When used with `--eval`, the result must be coercible to a string, i.e.,
something that can be converted using `${...}`. The output is
printed exactly as-is, with no quotes, escaping, or trailing newline.
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 abstract syntax tree rather than as a Nix expression.
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).
- `--xml`\
When used with `--eval`, print the resulting value as an XML
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).
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).
- `--read-write-mode`\
When used with `--eval`, perform evaluation in read/write mode so
+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`).
There are also two shortcuts, `--debug` to run in `DEBUG` verbosity level and
`--quiet` to run in `ERROR` verbosity level.
Use `--quiet` to decrease verbosity by one level.
There is one shortcut, `--debug` to run in `DEBUG` verbosity level.
----------
@@ -19,7 +19,7 @@ This description is not normative, but a feature removal may roughly happen like
1. Add a warning when the feature is being used.
2. Disable the feature by default, putting it behind a deprecated feature flag.
- If disabling the feature started out as an opt-in experimental feature, turn that experimental flag into a no-op or remove it entirely.
For example, `--extra-experimental-features=no-url-literals` becomes `--extra-deprecated-features=url-literals`.
For example, `--extra-experimental-features no-url-literals` becomes `--extra-deprecated-features url-literals`.
3. Decide on a time frame for how long that feature will still be supported for backwards compatibility, and clearly communicate that in the error messages.
- Sometimes, automatic migration to alternatives is possible, and such should be provided if possible
- At least one NixOS release cycle should be the minimum
+88 -19
View File
@@ -11,7 +11,19 @@ The following instructions assume you already have some version of Nix or Lix in
[installation instructions]: ../installation/installation.md
## Building Lix in a development shell
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}
### Setting up the development shell
@@ -48,7 +60,7 @@ $ just setup build test-unit
$ just install test-integration
```
Many targets have a `-custom` variant which pass extra arguments to `meson`.
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:
```
@@ -129,7 +141,59 @@ To inspect the canonical source of truth on what the state of the buildsystem co
$ meson introspect
```
## Building Lix outside of development shells
#### LLD
The development shell on Linux uses LLD by default for faster link times.
This is set using `mesonFlags`, so to override it, you can simplify re-specify the linker to Meson:
```bash
$ just setup-custom -Dc_link_args=-fuse-ld=ld -Dcpp_link_args=-fuse-ld=ld
```
While using LLD, you may find it helpful to use ThinLTO for even further improvements to link times for incremental builds:
```bash
$ just setup-custom -Db_lto=true -Db_lto_mode=thin -Db_thinlto_cache=true
```
## 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.
## Interacting with the CI, Buildkite
We use Buildkite for our CI, usually you will not have to interact directly with it other than reviewing any errors it produces, which are linked from Gerrit.
However in certain cases a CI run will fail due to transient issues not related to your code and you will need to rerun it by hand.
You can log in to the CI via [SSO](https://buildkite.com/sso/lix-project). On your job you can then hit the "Retry failed" button to rerun it, normally you will not have a repeat of the transient issue.
If the build still fails on CI issues or all builds are failing this should be reported via [Zulip on #T-infra](https://zulip.lix.systems/#narrow/channel/7-T-infra) or [Matrix on #dev](https://matrix.to/#/%23dev%3Alix.systems?via=lix.systems).
## Building Lix with `nix`
To build a release version of Lix for the current operating system and CPU architecture:
@@ -286,10 +350,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.
### Checking links in the manual
# Manual and documentation
## Building 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
@@ -301,15 +365,20 @@ meson compile -C build manual
[`mdbook-linkcheck`]: https://github.com/Michael-F-Bryan/mdbook-linkcheck
[URI fragments]: https://en.wikipedia.org/wiki/URI_fragment
#### `@docroot@` variable
The built manual is in `build/doc/manual/manual/index.html`.
`@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.
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.
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\@` variable
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@`.
`@\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\@`.
## API documentation
@@ -341,7 +410,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
## Add a release note {#release-notes}
`doc/manual/rl-next` contains release notes entries for all unreleased changes.
@@ -410,15 +479,15 @@ The following properties are supported:
### Build process
Releases have a precomputed `rl-MAJOR.MINOR.md`, and no `rl-next.md`.
Set `buildUnreleasedNotes = true;` in `flake.nix` to build the release notes on the fly.
Development releases have a generated `rl-next.md`.
## 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.
@@ -428,7 +497,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.
@@ -456,7 +525,7 @@ 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.
@@ -472,7 +541,7 @@ The following metadata properties are supported for builtin functions:
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.
+10 -2
View File
@@ -62,6 +62,12 @@ For `installcheck` specifically, first run `just install` before running the tes
Finer-grained filtering within a test suite is also possible using the [--gtest_filter](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) command-line option to a test suite executable, or the `GTEST_FILTER` environment variable.
### Inspecting failures
The test suite emits logs in `build/meson-logs/`; the full textual failure logs are in `build/meson-logs/testlog.txt`.
If you want a much nicer experience of viewing the logs in a structured manner, use `xunit-viewer --results build/meson-logs/testlog.junit.xml --server` to view them in a web browser.
### Unit test support libraries
There are headers and code which are not just used to test the library in question, but also downstream libraries.
@@ -377,7 +383,10 @@ I grepped `lix/` for `get[eE]nv\("` to find the mentions in Lix code.
Overrides compile-time configuration of various locations used by Lix. See `lix/libstore/globals.cc`.
**Expected value**: a directory
- `NIX_DAEMON_SOCKET_PATH` (optional) - Overrides the daemon socket path from `$NIX_STATE_DIR/daemon-socket/socket`.
- `LIX_DAEMON_SOCKET_DIR` (optional) - Overrides the daemon socket directory from `$NIX_STATE_DIR/daemon-socket`.
**Expected value**: a directory
- `NIX_DAEMON_SOCKET_PATH` (optional) - Overrides the daemon socket path from `$NIX_STATE_DIR/daemon-socket/socket`. Ignored if `LIX_DAEMON_SOCKET_DIR` is set.
**Expected value**: path to a socket
- `NIX_LOG_FD` (output) - An FD number for logs in `internal-json` format to be sent to.
@@ -395,7 +404,6 @@ I grepped `lix/` for `get[eE]nv\("` to find the mentions in Lix code.
**Expected value**: the path to an executable shell
- `PRINT_PATH` - Undocumented. Used by `nix-prefetch-url` as an alternative form of `--print-path`. Why???
- `_NIX_IN_TEST` - If present with any value, makes `fetchClosure` accept file URLs in addition to HTTP ones. Why is this not `_NIX_FORCE_HTTP`??
Not used anywhere else.
- `NIX_ALLOW_EVAL` - Used by eval-cache tests to block evaluation if set to `0`.
+1 -1
View File
@@ -89,7 +89,7 @@
[store path]: #gloss-store-path
- [file system object]{#gloss-store-object}
- [file system object]{#gloss-file-system-object}
The Nix data model for representing simplified file system data.
@@ -60,3 +60,10 @@ Then:
```console
$ docker run -ti lix
```
# Known issues
Lix in Docker is very sensitive to **functional** DNS resolution if you are running with [Pasta protections](../advanced-topics/pasta.md) which are enabled by default since Lix 2.93.0 on most distributions.
If you notice failure to download things, double check whether your **first** DNS entry in `/etc/resolv.conf` is functional.
Lix with [Pasta protections](../advanced-topics/pasta.md) does not support failing over the next entries.
@@ -54,11 +54,6 @@ 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
@@ -0,0 +1 @@
This section lists known issues around Lix.
@@ -0,0 +1,21 @@
# Limitations of non-isolated builds
## What are non-isolated builds?
In Lix, only builds done on Linux with `sandbox = true` and a functioning
`pasta-path` are isolated from the rest of the system, all other builds are
considered non-isolated to some degree.
For example, running Lix with [Pasta](@docroot@/advanced-topics/pasta.md)
disabled makes the host network visible to fixed-output derivations, reducing
isolation somewhat.
## Clean termination of non-isolated builds
Non-isolated builds may not terminate cleanly in all cases due to limitations in Lix's process management.
This occurs when a build keeps the build log file descriptor open past the end of the actual build. A common cause of this are background tasks that aren't properly terminated before the main build process exits, for example: HTTP servers run as part of a test suite.
See [issue #1018](https://git.lix.systems/lix-project/lix/issues/1018) for an example.
The only solution is to manually terminate leftover processes in your derivation, including during failure scenarios.
@@ -302,8 +302,6 @@ 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:
@@ -5,7 +5,7 @@
FIXME(Lix): This section does not document the most common modern practices in terms of avoiding channels, pinning, declarative software installation (see flakey-profile or home-manager or NixOS), or using flakes, etc.
It is, however, likely correct at a technical level.
For more information on modern practices, see the [resources](https://lix.systems/resources) page on the Lix site.
For more information on modern practices, see the [resources](https://wiki.lix.systems/books/lix-users/page/nix-resources) page on the Lix site.
</div>
@@ -41,7 +41,7 @@ install Lix. If this is not the case for some reason, you can add it
as follows:
```console
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
$ nix-channel --add https://channels.nixos.org/nixpkgs-unstable
$ nix-channel --update
```
@@ -49,7 +49,7 @@ $ nix-channel --update
>
> On NixOS, youre automatically subscribed to a NixOS channel
> corresponding to your NixOS major release (e.g.
> <http://nixos.org/channels/nixos-21.11>). A NixOS channel is identical
> <https://channels.nixos.org/nixos-21.11>). A NixOS channel is identical
> to the Nixpkgs channel, except that it contains only Linux binaries
> and is updated only if a set of regression tests succeed.
+955
View File
@@ -0,0 +1,955 @@
# Lix 2.94 "Açaí na tigela" (2025-11-17)
# Lix 2.94.0 (2025-11-17)
## Breaking Changes
- Remove support for daemon protocols before 2.18 [fj#510](https://git.lix.systems/lix-project/lix/issues/510) [cl/3249](https://gerrit.lix.systems/c/lix/+/3249)
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.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Remove impure derivations and dynamic derivations [fj#815](https://git.lix.systems/lix-project/lix/issues/815) [cl/3210](https://gerrit.lix.systems/c/lix/+/3210)
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.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- First argument to `--arg`/`--argstr` must be a valid Nix identifier [fj#496](https://git.lix.systems/lix-project/lix/issues/496)
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.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- New cgroup delegation model [fj#537](https://git.lix.systems/lix-project/lix/issues/537) [fj#77](https://git.lix.systems/lix-project/lix/issues/77) [cl/3230](https://gerrit.lix.systems/c/lix/+/3230)
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
Many thanks to [Raito Bezarius](https://git.lix.systems/raito), [eldritch horrors](https://git.lix.systems/pennae), and [lheckemann](https://git.lix.systems/lheckemann) for this.
- Enable high compress ratio zstd compression by default for binary caches uploads [fj#945](https://git.lix.systems/lix-project/lix/issues/945) [cl/4503](https://gerrit.lix.systems/c/lix/+/4503)
The default compression method for binary cache uploads has been switched from
[`xz`](https://github.com/tukaani-project/xz) to
[`zstd`](https://github.com/facebook/zstd) to address performance and usability
issues related to modern hardware and high-speed connections.
## Why?
`xz` offers compression ratios but is single-threaded in our implementation and
very slow (~10-20 Mbps in our test), preventing full utilization of 100Mbps+
connections and significantly slowing decompression for end users.
Lix is a "compress once, decompress many" application: build farms can afford
to spend more time compressing to achieve a faster download transfer for the
end user. More importantly, it matters that all end users spend the least
amount of time decompressing.
## What about compression ratios?
`zstd` cannot achieve the same peaks as `xz`, nonetheless, `zstd` compression
level has been increased to level 12 by default to balance compression ratio
and performance.
## Synthetic test case data
* **xz** (default compression level) on a 4.4GB file: ~632MB (77s)
* **zstd** (level 12) on the same file: ~775MB (18s), 18% larger but 50% faster
* **zstd** (level 14): ~773MB (37s)
* **zstd** (level 16): ~735MB (66s)
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) and [Raito Bezarius](https://git.lix.systems/raito) for this.
- Repl debugger uses `--ignore-try` by default [lix#666](https://git.lix.systems/lix-project/lix/issues/666) [cl/3488](https://gerrit.lix.systems/c/lix/+/3488)
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>
```
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Strings may now contain NUL bytes [cl/3968](https://gerrit.lix.systems/c/lix/+/3968)
Lix now allows strings to contain NUL bytes instead of silently truncating the
string before the first such byte. Notably NUL-bearing strings were allowed as
attribute names—even though the corresponding strings were not representable!—
leading to very surprising and incorrect behavior in corner cases, for example
```
nix-repl> builtins.fromJSON ''{"a": 1, "a\u0000b": 2}''
{
a = 1;
"ab" = 2;
}
nix-repl> builtins.attrNames (builtins.fromJSON ''{"a": 1, "a\u0000b": 2}'')
[
"a"
"a"
]
```
rather than the more correct but still with the terminal eating NUL on display
```
nix-repl> builtins.fromJSON ''{"a": 1, "a\u0000b": 2}''
{
a = 1;
"ab" = 2;
}
nix-repl> builtins.attrNames (builtins.fromJSON ''{"a": 1, "a\u0000b": 2}'')
[
"a"
"ab"
]
```
We consider this a breaking change since eval results *will* change if strings
with embedded NUL bytes were used, but we also consider the old behavior to be
not intentional (seeing how inconsistent it was) but merely fallout from a old
and misguided implementation decision to be worked around, not actually fixed.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Fixed output derivations can be run using `pasta` network isolation [fj#285](https://git.lix.systems/lix-project/lix/issues/285) [cl/3452](https://gerrit.lix.systems/c/lix/+/3452)
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.
- Function equality semantics are more consistent, but still bad [cl/4556](https://gerrit.lix.systems/c/lix/+/4556) [cl/4244](https://gerrit.lix.systems/c/lix/+/4244)
Lix has inherited a historic misfeature from CppNix in the form of pointer
equality checks built into the `==` operator. These checks were originally
meant to optimize comparison for large sets, but they have the unfortunate
side effect of producing unexpected results when sets containing functions
are compared. **Lix 2.93 and earlier** behave as shown in the repl session
```
Lix 2.93.3
Type :? for help.
nix-repl> f = x: x
Added f.
nix-repl> f == f
false
nix-repl> let s.f = f; in s.f == s.f
false
nix-repl> # however!
{ inherit f; } == { inherit f; }
true
nix-repl> [ f ] == [ f ]
true
nix-repl> # and, in another twist:
[ f ] == map f [ f ]
false
```
Nixpkgs relies on sets containing functions being comparable, so we cannot
simply deprecate this behavior. Due to changes to the object model used by
Lix ***all* comparisons above now evaluate to `true`**. This is considered
a breaking change because eval results may differ, but we also consider it
minor because the optimization is unsound (c.f. `let l = [NaN]; in l == l`
evaluates to `true` even though floating point `NaN` is incomparable). Lix
intends to remove this optimization altogether in the future, but until we
can do that we instead make it slightly less broken to allow other, *real*
optimizations. Function equality comparison remains **undefined behavior**
and should not be relied upon in Nixlang code that intends to be portable.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- `nix eval --write-to` has been removed [fj#974](https://git.lix.systems/lix-project/lix/issues/974) [fj#227](https://git.lix.systems/lix-project/lix/issues/227) [cl/4045](https://gerrit.lix.systems/c/lix/+/4045)
`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.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Remove the `parse-toml-timestamps` experimental feature
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.
Many thanks to [Emily](https://git.lix.systems/emilazy) for this.
- Reject overflowing TOML integer literals [cl/3916](https://gerrit.lix.systems/c/lix/+/3916)
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.
Many thanks to [Emily](https://git.lix.systems/emilazy) for this.
- uid-range depends on cgroups [cl/3230](https://gerrit.lix.systems/c/lix/+/3230)
`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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
## Features
- Add `inputs.self.submodules` flake attribute [fj#942](https://git.lix.systems/lix-project/lix/issues/942) [cl/3839](https://gerrit.lix.systems/c/lix/+/3839)
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.
Many thanks to [Eelco Dolstra](https://github.com/edolstra) and [ورد](https://git.lix.systems/janw4ld) for this.
- Lix supports HTTP/3 behind `--http3` [fj#1033](https://git.lix.systems/lix-project/lix/issues/1033)
Lix now supports HTTP/3 for file transfers when the linked curl version
supports it.
By default, HTTP/3 is disabled notably due to performance issues reported in
mid-2024. [More details
here](https://daniel.haxx.se/blog/2024/06/10/http-3-in-curl-mid-2024/).
As of 2025-11-14, [NixOS official cache](https://cache.nixos.org) supports
HTTP/3 via Fastly. [More info
here](https://github.com/NixOS/infra/commit/157fa70e46afbd6338a32407be461fce05c57bf8).
To enable HTTP/3:
* Use `--http3` for individual transfers.
* Add `http3 = true` in your Nix configuration for permanent activation.
To disable it, use `--no-http3`.
**Note**:
* `--no-http2 --http3` will still enable both HTTP/2 and HTTP/3.
* `--http2 --http3` will prioritize HTTP/3 and fall back to HTTP/2 (and then
HTTP/1.1).
These are current CLI limitations. In the future, we plan to replace `--httpX`
options with `--max-http-version [1,2,3]` for easier version selection in Lix
transfers.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Add hyperlinks in attr set printing [cl/3790](https://gerrit.lix.systems/c/lix/+/3790)
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"; }
```
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Experimental integer coercion in interpolated strings [cl/3198](https://gerrit.lix.systems/c/lix/+/3198)
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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito), [delroth](https://github.com/delroth), [eldritch horrors](https://git.lix.systems/pennae), and [winter](https://git.lix.systems/winter) for this.
- nix-eval-jobs: support `--no-instantiate` flag [fj#987](https://git.lix.systems/lix-project/lix/issues/987)
`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.
Many thanks to [mic92](https://github.com/mic92) and [ma27](https://git.lix.systems/ma27) for this.
## Improvements
- Assess current profile generations pointers in `nix doctor` [cl/3108](https://gerrit.lix.systems/c/lix/+/3108)
Added a new check to `nix doctor` that verifies whether the current generation of
a Nix profile can be resolved. This helps users diagnose issues with broken or
misconfigured profile symlinks.
This helps determining if you have broken symlinks or misconfigured packaging.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Improved susbtituter query speed
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).
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Hitting Control-C twice always terminates Lix [cl/3574](https://gerrit.lix.systems/c/lix/+/3574)
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
```
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- `--keep-failed` chowns the build directory to the user that request the build
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.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Better debuggability on fixed-output hash mismatches
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.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Add --raw flag to `nix-instantiate --eval` for unescaped output [gh#12119](https://github.com/NixOS/nix/pull/12119) [cl/2886](https://gerrit.lix.systems/c/lix/+/2886)
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.
Many thanks to [Martin Fischer](https://github.com/not-my-profile), [infinisil](https://github.com/infinisil), and [Raito Bezarius](https://git.lix.systems/raito) for this.
- Allow `nix store ls` to read nar listings from binary cache stores. [cl/3225](https://gerrit.lix.systems/c/lix/+/3225)
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.
Many thanks to [Victor Fuentes](https://git.lix.systems/vlinkz) for this.
- show tree with references that lead to an output cycle [fj#551](https://git.lix.systems/lix-project/lix/issues/551)
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.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- Lix now enables parallel marking in boehm-gc [fj#983](https://git.lix.systems/lix-project/lix/issues/983) [cl/3880](https://gerrit.lix.systems/c/lix/+/3880)
This brings a fairly modest performance improvement (~38% for `nixpkgs search hello`) to evaluation, especially in scenarios that necessitate larger heap sizes.
Many thanks to [Eelco Dolstra](https://github.com/edolstra) and [Seth Flynn](https://git.lix.systems/getchoo) for this.
- `disallowedRequisites` now reports chains of disallowed requisites [fj#334](https://git.lix.systems/lix-project/lix/issues/334) [fj#626](https://git.lix.systems/lix-project/lix/issues/626) [gh#10877](https://github.com/NixOS/nix/issues/10877)
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
```
Many thanks to [ma27](https://git.lix.systems/ma27) and [Robert Hensing](https://github.com/roberth) for this.
- Stack traces now summarize involved derivations at the bottom [cl/4493](https://gerrit.lix.systems/c/lix/+/4493)
When evaluation errors and a stack trace is printed,
For example, if I add Nheko to a NixOS `environment.systemPackages` without adding `olm-3.2.16` `nixpkgs.config.permittedInsecurePackages`, then without `--show-trace`, I previously got this:
```
error:
… while calling the 'head' builtin
at /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/lib/attrsets.nix:1701:13:
1700| if length values == 1 || pred here (elemAt values 1) (head values) then
1701| head values
| ^
1702| else
… while evaluating the attribute 'value'
at /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/lib/modules.nix:1118:7:
1117| // {
1118| value = addErrorContext "while evaluating the option `${showOption loc}':" value;
| ^
1119| inherit (res.defsFinal') highestPrio;
(stack trace truncated; use '--show-trace' to show the full trace)
error: Package olm-3.2.16 in /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/pkgs/by-name/ol/olm/package.nix:37 is marked as insecure, refusing to evaluate.
< -snip the whole explanation about olm's CVEs- >
```
This doesn't tell me anything about where `olm-3.2.16` came from.
With `--show-trace`, there's 1155 lines to sift through, but does contain lines like "while evaluating derivation 'nheko-0.12.1'".
With this change, those lines are summarized and collected at the bottom, regardless of `--show-trace`:
```
error:
… while calling the 'head' builtin
at /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/lib/attrsets.nix:1701:13:
1700| if length values == 1 || pred here (elemAt values 1) (head values) then
1701| head values
| ^
1702| else
… while evaluating the attribute 'value'
at /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/lib/modules.nix:1118:7:
1117| // {
1118| value = addErrorContext "while evaluating the option `${showOption loc}':" value;
| ^
1119| inherit (res.defsFinal') highestPrio;
(stack trace truncated; use '--show-trace' to show the full trace)
error: Package olm-3.2.16 in /nix/store/9v6qa656sq3xc58vkxslqy646p0ajj61-source/pkgs/by-name/ol/olm/package.nix:37 is marked as insecure, refusing to evaluate.
< -snip the whole explanation about olm's CVEs- >
note: trace involved the following derivations:
derivation 'etc'
derivation 'dbus-1'
derivation 'system-path'
derivation 'nheko-0.12.1'
derivation 'mtxclient-0.10.1'
```
Now we finally know that olm was evaluated because of Nheko, without sifting through *thousands* of lines of error message.
Many thanks to [Qyriad](https://git.lix.systems/Qyriad) for this.
- Symbols reuses once-allocated Value to reduce garbage collected allocations [cl/3308](https://gerrit.lix.systems/c/lix/+/3308) [cl/3300](https://gerrit.lix.systems/c/lix/+/3300) [cl/3314](https://gerrit.lix.systems/c/lix/+/3314) [cl/3310](https://gerrit.lix.systems/c/lix/+/3310) [cl/3312](https://gerrit.lix.systems/c/lix/+/3312) [cl/3313](https://gerrit.lix.systems/c/lix/+/3313)
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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito), [eldritch horrors](https://git.lix.systems/pennae), [Tom Hubrecht](https://git.lix.systems/tom-hubrecht), [xokdvium](https://github.com/xokdvium), and [NaN-git](https://github.com/NaN-git) for this.
## Fixes
- `build-dir` no longer defaults to `temp-dir` [cl/3453](https://gerrit.lix.systems/c/lix/+/3453)
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/b` in the default configuration).
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Global certificate authorities are copied inside the builder's environment [gh#12698](https://github.com/NixOS/nix/issues/12698) [fj#885](https://git.lix.systems/lix-project/lix/issues/885) [cl/3765](https://gerrit.lix.systems/c/lix/+/3765)
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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [Emily](https://git.lix.systems/emilazy) for this.
- libstore: exponential backoff for downloads [lix#932](https://git.lix.systems/lix-project/lix/issues/932) [cl/3856](https://gerrit.lix.systems/c/lix/+/3856)
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.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- Fix develop shells for derivations with escape codes [fj#991](https://git.lix.systems/lix-project/lix/issues/991) [cl/4154](https://gerrit.lix.systems/c/lix/+/4154) [cl/4155](https://gerrit.lix.systems/c/lix/+/4155)
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.
Many thanks to [Qyriad](https://git.lix.systems/Qyriad) for this.
- nix-store --delete: always remove obsolete hardlinks [cl/3188](https://gerrit.lix.systems/c/lix/+/3188)
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.
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Report GC statistics correctly [cl/3188](https://gerrit.lix.systems/c/lix/+/3188)
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.
```
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
- Fallback to safe temp dir when build-dir is unwritable [fj#876](https://git.lix.systems/lix-project/lix/issues/876) [cl/3501](https://gerrit.lix.systems/c/lix/+/3501)
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.
- Parse overflowing JSON number literals as floatingpoint [cl/3919](https://gerrit.lix.systems/c/lix/+/3919)
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.
Many thanks to [Emily](https://git.lix.systems/emilazy) for this.
- Fix handling of OSC codes in terminal output [fj#160](https://git.lix.systems/lix-project/lix/issues/160) [cl/3143](https://gerrit.lix.systems/c/lix/+/3143)
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.
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
- Fix nix develop for derivations that rejects dependencies with structured attrs [fj#997](https://git.lix.systems/lix-project/lix/issues/997) [cl/4182](https://gerrit.lix.systems/c/lix/+/4182)
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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- nix-eval-jobs: retain NIX_PATH [cl/3859](https://gerrit.lix.systems/c/lix/+/3859)
`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).
Many thanks to [ma27](https://git.lix.systems/ma27) and [mic92](https://github.com/mic92) for this.
- Remove reliance on Bash for remote stores via SSH [fj#830](https://git.lix.systems/lix-project/lix/issues/830) [fj#805](https://git.lix.systems/lix-project/lix/issues/805) [fj#304](https://git.lix.systems/lix-project/lix/issues/304) [cl/3159](https://gerrit.lix.systems/c/lix/+/3159)
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.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- repl-overlays now work in the debugger for flakes [fj#777](https://git.lix.systems/lix-project/lix/issues/777) [cl/3398](https://gerrit.lix.systems/c/lix/+/3398)
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.
Many thanks to [jade](https://git.lix.systems/jade) for this.
- `nix-shell` default shell directory is not `/tmp` anymore for `$NIX_BUILD_TOP` [fj#940](https://git.lix.systems/lix-project/lix/issues/940)
Previously, Lix `nix-shell`s could exit non-zero status when `stdenv`'s `dumpVars` phase failed to write to `$NIX_BUILD_TOP/env-vars`, despite `dumpVars` being intended as a debugging aid.
This happens when `TMPDIR` is not set and defaults therefore to `/tmp`, resulting in a `/tmp/env-vars` global file that every `nix-shell` wants to write.
We fix this issue by reusing a pre-created, unique, and writable location, as the build top directory, avoiding shell exiting from write failures silently.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- libstore/binary-cache-store: don't cache narinfo on nix copy, remove negative entry [cl/3789](https://gerrit.lix.systems/c/lix/+/3789)
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.
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
- Lix libraries can now be linked statically [fj#789](https://git.lix.systems/lix-project/lix/issues/789) [cl/3775](https://gerrit.lix.systems/c/lix/+/3775) [cl/3778](https://gerrit.lix.systems/c/lix/+/3778)
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.
Many thanks to [alois31](https://git.lix.systems/alois31) for this.
- add description to zsh completions [fj#910](https://git.lix.systems/lix-project/lix/issues/910) [cl/3632](https://gerrit.lix.systems/c/lix/+/3632)
Emit descriptions when completing args in zsh completions. This uses the descriptions we already
provided in NIX\_GET\_COMPLETIONS.
Many thanks to [matthewbauer](https://github.com/matthewbauer) for this.
## Miscellany
- Deprecation of CA derivations, dynamic derivations, and impure derivations [fj#815](https://git.lix.systems/lix-project/lix/issues/815)
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.
+546
View File
@@ -0,0 +1,546 @@
# Lix 2.95 "Kakigōri" (2026-03-13)
# Lix 2.95.0 (2026-03-13)
## Breaking Changes
- Deprecate shadowing internal files through the Nix search path [lix#998](https://git.lix.systems/lix-project/lix/issues/998) [cl/4632](https://gerrit.lix.systems/c/lix/+/4632)
As Lix uses the path `<nix/fetchurl.nix>` for bootstrapping purposes, the ability to shadow it by adding `nix=/some/path` (or `/other/path` that contains a `nix` directory) to the search path is not desirable.
To alleviate potential issues, Lix now emits a warning when the Nix search path contains potential shadows for internal files, which will be changed to an error in a future release.
The warning can be disabled by enabling the deprecated feature `nix-path-shadow`.
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- More deprecated features [cl/2092](https://gerrit.lix.systems/c/lix/+/2092) [cl/2310](https://gerrit.lix.systems/c/lix/+/2310) [cl/2311](https://gerrit.lix.systems/c/lix/+/2311) [cl/4638](https://gerrit.lix.systems/c/lix/+/4638) [cl/4652](https://gerrit.lix.systems/c/lix/+/4652) [cl/4764](https://gerrit.lix.systems/c/lix/+/4764)
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.
- `broken-string-indentation` indented strings (those starting with `''`) might produce unintended results due to how the whitespace stripping is done. Those cases will now warn the user.
- `broken-string-escape` "escaped" characters without a properly defined escape sequence evaluate to "themselves". This is in most cases unintended behaviour, both for writing regexes, and using legacy or uncommon escape sequences like `\f`. The user will now be warned, if those are present.
- `floating-without-zero` so far, one was able to declare a float using something like `.123`. This can cause confusion about accessing attributes. Floating point numbers must now always include the leading zero, i.e. `0.123`
- `rec-set-merges` Attribute sets like `{ foo = {}; foo.bar = 42;}` implicitly merge at parse time, however if one of them is marked as recursive but not the others then the recursive attribute may get lost (order-dependent). Therefore, merging attrs with mixed-`rec` is now forbidden.
- `rec-set-dynamic-attrs` Dynamic attributes have weird semantics in the presence of recursive attrsets (they evaluate *after* the rest of the set). This is now forbidden.
- `or-as-identifier` `or` as an identifier has always been weird since the `or` (almost-)keyword has been introduced. We are deprecating the backcompat hacks from the early days of Nix in favor of making `or` a full and proper keyword.
- `tokens-no-whitespace` Function applications without space around the arguments like `0a`, `0.00.0` or `foo"1"2` are now forbidden. The same applies to list elements. The primary reason for this deprecation is to remove foot guns around surprising tokenization rules regarding number literals, but this will also free up some syntax for other purposes (e.g. `r""` strings) for reuse at some point in the future.
- `shadow-internal-symbols` has been expanded to also forbid shadowing `null`, `true` and `false`.
- `ancient-let` deprecation has been turned into a full parser error instead of a warning.
- `rec-set-overrides` deprecation has been turned into a full parser error instead of a warning.
Many thanks to [piegames](https://git.lix.systems/piegames), [rootile (Rutile)](https://git.lix.systems/rootile), and [eldritch horrors](https://git.lix.systems/pennae) for this.
- Move `/root/.cache/nix` to `/var/cache/nix` by default [lix#634](https://git.lix.systems/lix-project/lix/issues/634) [cl/4671](https://gerrit.lix.systems/c/lix/+/4671)
By default, Lix attempts to locate a cache directory for its operations (such
as the narinfo cache) by checking the value of `$XDG_CACHE_DIR`.
However, since the Nix daemon is a system service, using `$XDG_CACHE_DIR` is
not typical in this context.
To address this, systemd provides a better solution. Specifically, when
`CacheDirectory=` is set in the `[Service]` section of a systemd unit, it
automatically sets the `$CACHE_DIRECTORY` environment variable and systemd will
manage that cache directory for us.
Now, our systemd unit includes `CacheDirectory=nix`, which sets the
`$CACHE_DIRECTORY` and takes precedence over `$XDG_CACHE_DIR`.
If the daemon is run under user units, systemd will automatically set
`$XDG_CACHE_DIR`.
If neither of these variables is set, Lix falls back to its default behavior.
By default, Lix will try to find a cache directory for its various operations
(e.g. narinfo cache) by looking into `$XDG_CACHE_DIR`.
In summary, what was stored in `/root/.cache/nix` is now moved to
`/var/cache/nix/nix`.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Remove `fetch-closure` experimental feature [lix#1010](https://git.lix.systems/lix-project/lix/issues/1010) [cl/4595](https://gerrit.lix.systems/c/lix/+/4595)
The `fetch-closure` experimental feature has been removed.
Outside of allowing the user to import closure from binary cache,
`fetchClosure` also allowed you to do the following:
* rewrite non-CA path to CA
* reject non-CA paths at fetching time
* reject CA paths at fetching time
Some people are using those mechanism to prevent users from having to build any
package and force going via the declared cache or as a way to use ancient/old
software without paying the evaluation cost of a second nixpkgs.
Both use cases are somewhat of an antipattern in Nix semantics. If the user
cannot fetch a program directly via the substituter mechanism and fall back to
local build, this is a feature *and* a misconfiguration. If the user cannot build
certain derivations because they are too expensive, the build directives should
pass `-j0` or similar.
As for the second usecase, there's a different way to do it that also allows to
have a way to reproduce the paths that are hardcoded in that file, perform
`import (fetchurl "https://my-cache/${hashparts storepath}.drv")` rather, i.e.
an IFD to a possibly well known name. The backend can generate them on the fly
or once, and possess stable names.
Finally, as for the non-CA → CA features, Lix removed ca-derivations.
fetchClosure offers ca-derivations-like features which suffers from similar
shortcomings albeit lessened. It only follows that we should deprecate
and remove these capabilities.
Many thanks to [just1602](https://git.lix.systems/just1602) for this.
## Features
- `nix store add-path` now supports references [cl/5205](https://gerrit.lix.systems/c/lix/+/5205)
Lix supports two categories of hashes in store paths: input-addressed and output-addressed.
Currently, in Nix language, there is no way to produce output-addressed paths with references, as fixed-output derivations forbid references.
However, the Nix store actually *supports* references in output-addressed paths.
This is very useful for importing build products created outside of Lix that reference dependency store paths since such build products have no associated derivation so don't make any sense to input-address.
Previously, output-addressed paths with references could only be created by writing a custom client to the rather-baroque Nix daemon protocol; now it's available in the CLI.
Using `nix store add-path --references-list-json REFS_LIST_FILE SOME_PATH` with a JSON list of string store paths, you can now create such paths with the Lix CLI.
They may be consumed from Nix language using something like `builtins.storePath` or the following which also works in pure evaluation mode:
```nix
# Hack from https://git.lix.systems/lix-project/lix/issues/402#issuecomment-5889
path:
builtins.appendContext path {
${path} = {
path = true;
};
}
```
Many thanks to [jade](https://git.lix.systems/jade) for this.
- Add `builtins.warn` for emitting warnings from Nix code [cl/2248](https://gerrit.lix.systems/c/lix/+/2248)
Lix now has a builtin function for emitting warnings.
Like `builtins.trace`, it takes two arguments: the message to emit, and the expression to return.
_Unlike_ `builtins.trace`, `builtins.warn` requires the first argument — the message — to be a string.
In the future we may extend `builtins.warn` to accept a more structured API.
To go along with this, we also have two new config settings:
- [`debugger-on-warn`](@docroot@/command-ref/conf-file.md#conf-debugger-on-warn), which, when used with `--debugger`, makes `builtins.warn` also function like [`builtins.break`](@docroot@/language/builtins.md#builtins-break).
- [`abort-on-warn`](@docroot@/command-ref/conf-file.md#conf-abort-on-warn), which aborts evaluation entirely after the warning is emitted.
Many thanks to [Emilia Bopp](https://git.lix.systems/milibopp) and [Qyriad](https://git.lix.systems/Qyriad) for this.
- `keep-env-derivations` is now supported for nix3 CLI (`nix profile`) [lix#1095](https://git.lix.systems/lix-project/lix/issues/1095) [cl/5332](https://gerrit.lix.systems/c/lix/+/5332)
The `keep-env-derivations` feature is now available for `nix profile`. This allows users to prevent the garbage collection of derivations used to install a profile, even when `keep-derivations = false` (set to `true` by default).
Previously, `nix-env` supported this feature, but `nix profile` **never** did. This caused issues when garbage collection removed the associated `.drv` files, which are required, for example, by vulnerability management tools (e.g. [vulnix](https://github.com/nix-community/vulnix)) for proper operation.
This issue has now been resolved.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Make `log-format` a setting [cl/4686](https://gerrit.lix.systems/c/lix/+/4686)
The [`--log-format` CLI option](@docroot@/command-ref/opt-common.md#opt-log-format) can now be set in [`nix.conf`](@docroot@/command-ref/conf-file.md#conf-log-format)!
For example, you can now persistently enable the `multiline-with-logs` log format [added in Lix 2.91](@docroot@/release-notes/rl-2.91.md) by adding the following to your `nix.conf`:
```conf
log-format = multiline-with-logs
```
Or the equivalent in a NixOS configuration:
```nix
{
nix.settings.log-format = "multiline-with-logs";
}
```
Many thanks to [Qyriad](https://git.lix.systems/Qyriad) for this.
- Allow remote builders to be configured using TOML [cl/4533](https://gerrit.lix.systems/c/lix/+/4533)
Lix now supports configuring remote builders using a TOML file instead of the old, very cursed and incomprehensible format.
This comes with not only a human-understandable file, but also with better messages and error reports on misconfiguration.
A more detailed Documentation can be found on the [distributed-builds](@docroot@/advanced-topics/distributed-builds.md) documentation page.
Many thanks to [rootile (Rutile)](https://git.lix.systems/rootile) and [Qyriad](https://git.lix.systems/Qyriad) for this.
- Emit warnings when encountering IFD with `warn-import-from-derivation` [nix#13279](https://github.com/NixOS/nix/pull/13279) [cl/3879](https://gerrit.lix.systems/c/lix/+/3879)
Instead of only being able to toggle the use of [Import from
Derivation](https://nix.dev/manual/nix/stable/language/import-from-derivation) with
`allow-import-from-derivation`, Lix is now able to warn users whenever IFD is encountered with
`warn-import-from-derivation`.
Many thanks to [Seth Flynn](https://git.lix.systems/getchoo), [gustavderdrache](https://github.com/gustavderdrache), and [Eelco Dolstra](https://github.com/edolstra) for this.
## Improvements
- Collect Flakes untrusted settings into one prompt [lix#682](https://git.lix.systems/lix-project/lix/issues/682) [cl/2921](https://gerrit.lix.systems/c/lix/+/2921)
When working with Flakes containing untrusted settings, a prompt is shown for each setting, asking whether to vet or approve it. This looks like:
```
nix flake lock
warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
The following settings require your decision:
- allow-dirty = false
- sandbox = false
Do you want to allow configuration settings to be applied?
This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all)
```
In Flakes with a large number of settings to approve or reject, this process can become tedious as each option must be handled individually.
To address this, all untrusted settings are now consolidated into a single prompt: allowing for bulk acceptance permanently or not, rejection, or detailed review. For example:
### Scrutiny scenario
```console
nix flake lock
warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
The following settings require your decision:
- allow-dirty = false
- sandbox = false
Do you want to allow configuration settings to be applied?
This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) n
warning: you can set 'accept-flake-config' to 'false' to automatically reject configuration options supplied by flakes
Do you want to allow setting 'allow-dirty = false'? (yes for now/Allow always/no for now) y
Do you want to allow setting 'sandbox = false'? (yes for now/Allow always/no for now) n
```
### Reject everything scenario
```console
nix flake lock
warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
The following settings require your decision:
- allow-dirty = false
- sandbox = false
Do you want to allow configuration settings to be applied?
This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) N
Rejecting all untrusted nix.conf entries
warning: you can set 'accept-flake-config' to 'false' to automatically reject configuration options supplied by flakes
```
### Accept everything scenario
```console
nix flake lock
warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
The following settings require your decision:
- allow-dirty = false
- sandbox = false
Do you want to allow configuration settings to be applied?
This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) y
```
### Accept everything PERMANENTLY scenario
Note that accepting everything permanently will authorize these options for any
further operations.
The file containing this trust information is usually located in
`~/.local/share/nix/trusted-settings.json` and can be edited manually to revoke
this permission until Lix provides a first-class command for this manipulation.
```console
nix flake lock
warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page)
The following settings require your decision:
- allow-dirty = false
- sandbox = false
Do you want to allow configuration settings to be applied?
This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) A
```
Many thanks to [isabelroses](https://git.lix.systems/isabelroses), [Raito Bezarius](https://git.lix.systems/raito), and [eldritch horrors](https://git.lix.systems/pennae) for this.
- `--check` or `--rebuild` is clearer about a missing path [lix#485](https://git.lix.systems/lix-project/lix/issues/485)
Previously, when running Lix with --check or --rebuild, failures often surfaced
as an unhelpful error:
> "some outputs of '...' are not valid, so checking is not possible"
This message could mean two different things:
- The requested output paths don't exist at all, or,
- Some outputs exist but are not known to Lix
Lix cannot reliably distinguish these cases, so it treated them the same.
We've updated the error messages to clarify what Lix can determine: whether any
valid outputs (> 0) are present or whether no outputs are available.
When no valid outputs can be found, Lix will now suggest building the derivation
normally (without --check or --rebuild) before trying again.
When some valid outputs are present, Lix now reports which ones are valid,
shows the full list of known outputs, and also suggests building the derivation
normally.
In the future, Lix may automate this recovery step when it knows how to rebuild
the paths, but implementing that safely requires more extensive changes to the
codebase.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- `nix develop` no longer ignores the env variable `SSL_CERT_FILE` [cl/5042](https://gerrit.lix.systems/c/lix/+/5042)
Running `nix develop` and `nix print-dev-env` on shells that define the environment variable `SSL_CERT_FILE` now works correctly by exporting that variable inside the built shell.
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- Linux sandbox launch overhead greatly reduced [cl/5030](https://gerrit.lix.systems/c/lix/+/5030) [cl/5073](https://gerrit.lix.systems/c/lix/+/5073) [cl/5074](https://gerrit.lix.systems/c/lix/+/5074)
Sandboxed builds are now much cheaper to launch on Linux, with constant management
overhead. This will mostly be noticeable when building derivation trees containing
many small derivations like nixpkgs' `writeFile` or `runCommand` with scripts that
exit quickly. In synthetic tests we have seen build times of 3000 small runCommand
drop from 80 seconds to 14 seconds, which is the most optimistic case in practice.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- mTLS store connections via a plugin [cl/3754](https://gerrit.lix.systems/c/lix/+/3754) [cl/3696](https://gerrit.lix.systems/c/lix/+/3696) [cl/3697](https://gerrit.lix.systems/c/lix/+/3697) [cl/3698](https://gerrit.lix.systems/c/lix/+/3698)
To support use cases requiring mutual TLS (mTLS) authentication when connecting
to remote Nix stores, e.g. private stores, we have introduced a **contributed**
mTLS plugin extending the Lix store interface.
This design follows an extensibility model which was brought up [by a proposal
of making Kerberos authentication possible in Lix
directly](https://gerrit.lix.systems/c/lix/+/3637).
This mTLS plugin serves as a concrete example of how store connection
mechanisms can be modularized through external plugins, without extending Lix
core. This idea can be generalized to integrate automatic certificate renewal
or advanced integrations with secrets engine or posture checks.
It enables custom TLS client certificates to be used for authenticating against
a remote store that enforces mTLS.
To use the plugin, configure Lix manually by setting in your `nix.conf`:
```
plugin-files = /a/path/to/libplugin_mtls_store.so
```
Currently, this must be done explicitly. In the future, Nixpkgs will provide a
mechanism to reference an up-to-date and curated set of plugins automatically.
Making plugins easily consumable outside of Nixpkgs (e.g., from external plugin
registries or binary distributions) remains an open question and will require
further design.
Contributed plugins come with significantly reduced **stability** and
**maintenance** guarantees compared to the Lix core. We encourage users who
depend on a given plugin to take on maintenance responsibilities and apply for
ownership within the Lix mono-repository. These plugins are subject to removal
at any time.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito), [eldritch horrors](https://git.lix.systems/pennae), [mic92](https://github.com/mic92), [vlaci](https://github.com/vlaci), and [nkk0](https://github.com/nkk0) for this.
- Add an indication of nix-shell nesting depth [lix#826](https://git.lix.systems/lix-project/lix/issues/826) [cl/4657](https://gerrit.lix.systems/c/lix/+/4657)
When in a nix shell (either via a `nix-shell` or a `nix develop` invocation), a variable `NIX_SHELL_LEVEL` is exported to indicate the nesting depth of nix shells.
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- `nix store delete` can now unlink a GC root before deleting its closure [cl/4660](https://gerrit.lix.systems/c/lix/+/4660)
Ever build something, and then you want to delete it and whatever dependencies it downloaded?
Before you had to resolve the `result` symlink and copy it, then delete it, *then* `nix store delete --delete-closure --skip-live` on the path you copied.
Now you can just pass `--unlink` and the `result` symlink itself.
Many thanks to [Qyriad](https://git.lix.systems/Qyriad) for this.
- `nix path-info` no longer lies to the user about fetching paths [lix#323](https://git.lix.systems/lix-project/lix/issues/323) [cl/4866](https://gerrit.lix.systems/c/lix/+/4866)
When running `nix path-info` with an installable that is not present in the store, Lix no longer
tells the user which paths are missing and that they will be fetched, as the documentation clearly
states that this command does not fetch missing paths.
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- Derivations can now be printed in detail in `nix repl` [cl/3842](https://gerrit.lix.systems/c/lix/+/3842)
Traditionally derivations printed in the REPL would only print a formatted object
representing the path of the derivation file it refers to. This makes inspecting
the enhanced derivation attribute sets encountered from `mkDerivation` or similar
wrappers more difficult. Even the `:p`/`:print` command would not elaborate attribute sets
tagged as a derivation.
With this change you can now use `:p`/`:print` to directly inspect a derivation
by providing one as the top-level object. Derivation attribute sets will only be
printed two levels deep and internal derivation attrsets will remain in unexpanded
path form as before. `drvAttrs` will also be elided as these attributes are already
present in the top-level attribute set of the derivation. These heuristics provide
a balance between readability and functionality. When the `:p`/`:print` is omitted,
a bare derivation is printed in the path format as before.
Many thanks to [Lunaphied](https://git.lix.systems/Lunaphied) for this.
- Reject `__json` in structured attributes derivations [lix#380](https://git.lix.systems/lix-project/lix/issues/380) [cl/5286](https://gerrit.lix.systems/c/lix/+/5286)
In structured attributes derivations, `__json` is used internally to store the
JSON representation of the `env` attribute field that users can set.
Unfortunately, a user can set `__json` *and* enable structured attributes,
resulting in a broken derivation from a semantic point of view.
As no user can benefit from setting `__json` *and* enable structured attributes,
we disallow that possibility and throw an error from now on.
This is not seen as a breaking change because there's no user code that can
benefit from this behavior, hence, it's an improvement to user experience.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Shells support `$NIX_LOG_FD` now [lix#336](https://git.lix.systems/lix-project/lix/issues/336) [cl/4694](https://gerrit.lix.systems/c/lix/+/4694) [cl/4695](https://gerrit.lix.systems/c/lix/+/4695)
Lix's "debugging" shells (`nix3-develop` and `nix-shell`) now set the
`$NIX_LOG_FD` environment variable.
This means that [hook logging in
stdenv](https://github.com/NixOS/nixpkgs/pull/310387) appears while debugging
derivations via `nix3-develop` or `nix-shell`.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Supplementary groups are now supported for daemon authentication [lix#968](https://git.lix.systems/lix-project/lix/issues/968) [cl/5021](https://gerrit.lix.systems/c/lix/+/5021)
macOS, FreeBSD and Linux now support receiving supplementary groups during UNIX domain authentication to a Lix daemon.
This change is particularly beneficial for systemd units with `DynamicUser=true` that need to connect to a Lix daemon, using a `SupplementaryGroups=` allocated by systemd in the context of the process. This is desirable if you wish to harden Lix clients.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito), [Tom Hubrecht](https://git.lix.systems/tom-hubrecht), [alois31](https://git.lix.systems/alois31), and [eldritch horrors](https://git.lix.systems/pennae) for this.
## Fixes
- Nix shells' `$NIX_BUILD_TOP` are shorter [lix#1044](https://git.lix.systems/lix-project/lix/issues/1044) [cl/4663](https://gerrit.lix.systems/c/lix/+/4663)
Following the changes in 2.94.0 to shorten build directory paths, aimed at [resolving UNIX domain socket length issues](https://gerrit.lix.systems/c/lix/+/4168/13) and [improving nix-shell](https://git.lix.systems/lix-project/lix/issues/940), we inadvertently introduced an excessively long path for the `$NIX_BUILD_TOP` environment variable used by Nix shells (their effective temporary `/build` directory).
To fix this, we replaced the `build-top-$HASH` directory name with simply `build-top`, reducing these paths by at least 30 characters.
We also added a test to ensure that Nix shells do not introduce more than 50 extra characters relative to their base directory (e.g., `/tmp` when `$TMPDIR` is not set).
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) for this.
- Fix resolving of symlinks in flake paths [lix#106](https://git.lix.systems/lix-project/lix/issues/106) [lix#12286](https://git.lix.systems/lix-project/lix/pulls/12286) [cl/4783](https://gerrit.lix.systems/c/lix/+/4783)
Flake paths are now canonicalized to resolve symlinks. This ensures that when a flake is accessed via a symlink, paths are resolved relative to the target directory, not the symlink's location.
Many thanks to [stevalkr](https://github.com/stevalkr) and [xyenon](https://git.lix.systems/xyenon) for this.
- The REPL no longer considers failed loads for `:reload` [lix#50](https://git.lix.systems/lix-project/lix/issues/50) [cl/4864](https://gerrit.lix.systems/c/lix/+/4864) [cl/4865](https://gerrit.lix.systems/c/lix/+/4865) [cl/4700](https://gerrit.lix.systems/c/lix/+/4700) [cl/4889](https://gerrit.lix.systems/c/lix/+/4889)
The [REPL](@docroot@/command-ref/new-cli/nix3-repl.md) allows "loading" files, flakes, and expressions into the environment, with the commands `:load`/`:l`, `:load-flake`/`:lf`, and `:add`/`:a` respectively.
The results of those stay in the environment as-is even if their sources change, until the `:reload` command is used.
However `:reload` would re-perform *all* instances of `:l`/`:lf`/`:a`, meaning you would get things like this:
```nix
nix-repl> :l /tmp/texting.nix
error: getting status of '/tmp/texting.nix': No such file or directory
# oops, typo.
nix-repl> :l /tmp/testing.nix
# Do some stuff…
nix-repl> :reload
error: getting status of '/tmp/texting.nix': No such file or directory
```
This is pretty silly, but also *incredibly* annoying, as it would stop there and *not* reload the correct files anymore.
This effectively meant typoing any of the load commands would make `:reload` useless for the rest of the entire `nix repl` session!
This has been fixed, so now only *successful* loads count towards `:reload`.
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [Qyriad](https://git.lix.systems/Qyriad) for this.
- Consistently use commit hash as rev when locking git inputs [cl/4762](https://gerrit.lix.systems/c/lix/+/4762)
Lix will now use commit hashes instead of tag object hashes in the `rev` field
when fetching git inputs by tag in `flake.lock` and `builtins.fetchTree` output.
Note that this means that Lix may change some `flake.lock` files on re-locking. Old `flake.lock` files still remain valid.
Many thanks to [goldstein](https://git.lix.systems/goldstein) for this.
## Development
- Functional lang migration [lix#856](https://git.lix.systems/lix-project/lix/issues/856) [cl/3213](https://gerrit.lix.systems/c/lix/+/3213)
We have done it! The functional/lang framework has now been fully migrated to functional2/lang.
This means: no more `just clean` and `just install` mess and whatever because one removed a test.
The lang test suite is also getting a face lift, with an improved folder structure and restructuring of many tests.
Only the first CL of the chain is provided but there's way more changes associated to this project.
Many thanks to [piegames](https://git.lix.systems/piegames) and [rootile (Rutile)](https://git.lix.systems/rootile) for this.
## Miscellany
- Warn instead of erroring when the final destination of a transfer changes in-flight [lix#1004](https://git.lix.systems/lix-project/lix/issues/1004) [cl/4641](https://gerrit.lix.systems/c/lix/+/4641)
Lix will now emit a warning during downloads where the final destination changes suddently mid-transfer instead of throwing an error.
This transfer behavior has been known to happen very rarely while fetching from some CDNs.
Many thanks to [Tom Hubrecht](https://git.lix.systems/tom-hubrecht) for this.
- `impersonate-linux-26` setting removed [cl/5047](https://gerrit.lix.systems/c/lix/+/5047)
Linux 3.0 was released 15 years ago. The `impersonate-linux-26` setting was added
14 years ago with no mention of it being necessary to build anything, only saying
that it improves determinism—which isn't accurate since impersonating Linux 2.6.x
still allows the version string to change, and the final component of the version
does still change with each Linux release. Since this setting should be no longer
necessary in modern systems and workarounds for building old code exist (by using
e.g. `setarch --uname-2.6` to wrap builds) we are removing this setting from Lix.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Default to showing build logs in the new-style (nix3) CLI [cl/4674](https://gerrit.lix.systems/c/lix/+/4674)
Lix will now show logs by default, in addition to the progress bar, when invoked through the new-style "nix3" CLI (`nix build`, etc)
Many thanks to [K900](https://git.lix.systems/K900) for this.
- Lix daemons are now fully socket-activated on systemd setups [lix#1030](https://git.lix.systems/lix-project/lix/issues/1030)
When launched by systemd, Lix no longer uses a persistent daemon process and uses systemd socket
activation instead. This is necessary to support the `cgroups` and `auto-allocate-uids` features
and may improve observability of daemon behavior with common systemd-based monitoring solutions.
The old behavior with a single persistent daemon is still available, but disabled by default. It
is not possible to enable both a persistent daemon and socket activation, starting one stops the
other automatically. Existing installations should not require any changes when they're updated.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
- Plugin interfaces have changed (again) [lix#359](https://git.lix.systems/lix-project/lix/issues/359) [cl/4933](https://gerrit.lix.systems/c/lix/+/4933) [cl/4934](https://gerrit.lix.systems/c/lix/+/4934)
The `RegisterPrimOp` class used to register builtins has been removed. Plugins
must now call `PluginPrimOps::add` from their `nix_plugin_entry` with the same
parameters previously passed to `RegisterRrimOp` to register any new builtins.
The `GlobalConfig::Register` helper class has also been removed. Adding config
options to the system is now done with `GlobalConfig::registerGlobalConfig`; a
plugin can add config values by calling this function from `nix_plugin_entry`.
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
+12 -2
View File
@@ -70,10 +70,15 @@ def do_include(content: str, relative_md_path: Path, source_root: Path, search_p
def recursive_replace(data, book_root, search_path):
match data:
# XXX FUTURE: drop sections once mdBook is at 0.5.0 or above in nixpkgs
case {'sections': sections}:
return data | dict(
sections = [recursive_replace(section, book_root, search_path) for section in sections],
)
case {'items': items}:
return data | dict(
items = [recursive_replace(item, book_root, search_path) for item in items],
)
case {'Chapter': chapter}:
path_to_chapter = Path(chapter['path'])
chapter_content = chapter['content']
@@ -90,6 +95,11 @@ 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)
@@ -114,10 +124,10 @@ def main():
context, book = json.load(sys.stdin)
# book_root is the directory where book contents leave (ie, src/)
book_root = Path(context['root']) / context['config']['book']['src']
book_root = Path(context['root']) / context['config']['book'].get('src', 'src')
# includes pointing into @generated@ will look here
search_path = Path(os.environ['MDBOOK_SUBSTITUTE_SEARCH'])
search_path = Path(os.environ['MANUAL_SUBSTITUTE_SEARCH'])
# Find @var@ in all parts of our recursive book structure.
replaced_content = recursive_replace(book, book_root, search_path)
+32 -32
View File
@@ -8,7 +8,7 @@
tag ? "latest",
bundleNixpkgs ? true,
channelName ? "nixpkgs",
channelURL ? "https://nixos.org/channels/nixpkgs-unstable",
channelURL ? "https://channels.nixos.org/nixpkgs-unstable",
extraPkgs ? [ ],
maxLayers ? 100,
nixConf ? { },
@@ -62,38 +62,37 @@ let
++ autoLayered
++ extraPkgs;
users =
{
users = {
root = {
uid = 0;
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/root";
gid = 0;
groups = [ "root" ];
description = "System administrator";
};
root = {
uid = 0;
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/root";
gid = 0;
groups = [ "root" ];
description = "System administrator";
};
nobody = {
uid = 65534;
shell = "${pkgs.shadow}/bin/nologin";
home = "/var/empty";
gid = 65534;
groups = [ "nobody" ];
description = "Unprivileged account (don't use!)";
nobody = {
uid = 65534;
shell = "${pkgs.shadow}/bin/nologin";
home = "/var/empty";
gid = 65534;
groups = [ "nobody" ];
description = "Unprivileged account (don't use!)";
};
}
// lib.listToAttrs (
map (n: {
name = "nixbld${toString n}";
value = {
uid = 30000 + n;
gid = 30000;
groups = [ "nixbld" ];
description = "Nix build user ${toString n}";
};
}
// lib.listToAttrs (
map (n: {
name = "nixbld${toString n}";
value = {
uid = 30000 + n;
gid = 30000;
groups = [ "nixbld" ];
description = "Nix build user ${toString n}";
};
}) (lib.lists.range 1 32)
);
}) (lib.lists.range 1 32)
);
groups = {
root.gid = 0;
@@ -361,7 +360,8 @@ let
"org.opencontainers.image.version" = pkgs.nix.version;
"org.opencontainers.image.description" =
"Minimal Lix container image, with some batteries included.";
} // lib.optionalAttrs (lixRevision != null) { "org.opencontainers.image.revision" = lixRevision; };
}
// lib.optionalAttrs (lixRevision != null) { "org.opencontainers.image.revision" = lixRevision; };
};
meta = {
@@ -381,7 +381,7 @@ image
pkgs.buildPackages.runCommand "docker-image-tarball-${pkgs.nix.version}"
{
nativeBuildInputs = [ pkgs.buildPackages.bubblewrap ];
meta.description = "Docker image tarball with Lix for ${pkgs.system}";
meta.description = "Docker image tarball with Lix for ${pkgs.stdenv.hostPlatform.system}";
}
''
mkdir -p $out/nix-support
Generated
+17 -19
View File
@@ -3,17 +3,15 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
"lastModified": 1751685974,
"narHash": "sha256-NKw96t+BgHIYzHUjkTK95FqYRVKB8DHpVhefWSz/kTw=",
"rev": "549f2762aebeff29a2e5ece7a7dc0f955281a1d1",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/flake-compat/archive/549f2762aebeff29a2e5ece7a7dc0f955281a1d1.tar.gz"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
"type": "tarball",
"url": "https://git.lix.systems/lix-project/flake-compat/archive/main.tar.gz"
}
},
"lowdown-src": {
@@ -35,11 +33,11 @@
"nix2container": {
"flake": false,
"locked": {
"lastModified": 1724996935,
"narHash": "sha256-njRK9vvZ1JJsP8oV2OgkBrpJhgQezI03S7gzskCcHos=",
"lastModified": 1767195068,
"narHash": "sha256-+OMnL79ZjqM/PCz2hoQ12MnXNoSSfBGnsYBOZnA9XbI=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "fa6bb0a1159f55d071ba99331355955ae30b3401",
"rev": "bb6801be998ba857a62c002cb77ece66b0a57298",
"type": "github"
},
"original": {
@@ -108,16 +106,16 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1749522908,
"narHash": "sha256-eWANkhWXFL1MmaxzsZ9bhLCNT8OVs7CC+OXaSDGlA8A=",
"lastModified": 1773082486,
"narHash": "sha256-TKUDrM0nKUo5s/b8jhjXa2prcu5KU5Cck3HBTRLDjfo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e5cb99555c45a13dcc5f1317462238530b0066b7",
"rev": "7f8b8875bdb38a70c7b5ceb9ba6a6a8d69859e16",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05-small",
"ref": "nixos-25.11-small",
"repo": "nixpkgs",
"type": "github"
}
@@ -125,11 +123,11 @@
"pre-commit-hooks": {
"flake": false,
"locked": {
"lastModified": 1733318908,
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
"lastModified": 1769939035,
"narHash": "sha256-Fok2AmefgVA0+eprw2NDwqKkPGEI5wvR+twiZagBvrg=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
"rev": "a8ca480175326551d6c4121498316261cbb5b260",
"type": "github"
},
"original": {
+63 -36
View File
@@ -2,7 +2,7 @@
description = "Lix: A modern, delicious implementation of the Nix package manager";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05-small";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11-small";
nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
# Required because Nix 2.18 is not in Nixpkgs ≥ 25.05 anymore.
@@ -24,7 +24,7 @@
flake = false;
};
flake-compat = {
url = "github:edolstra/flake-compat";
url = "https://git.lix.systems/lix-project/flake-compat/archive/main.tar.gz";
flake = false;
};
};
@@ -88,7 +88,7 @@
else
"pre${
builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")
}_${self.shortRev or "dirty"}";
}-dev_${self.shortRev or "dirty"}";
linux32BitSystems = [ "i686-linux" ];
linux64BitSystems = [
@@ -100,6 +100,7 @@
"x86_64-darwin"
"aarch64-darwin"
];
nonDarwinSystems = linuxSystems;
systems = linuxSystems ++ darwinSystems;
# If you add something here, please update the list in doc/manual/src/contributing/hacking.md.
@@ -175,9 +176,13 @@
{
nixStable = prev.nix;
# Nix 2.18 has been removed from Nixpkgs ≥ 25.05, so we need to reintroduce it ourselves for our tests.
nixVersions = prev.nixVersions // {
nix_2_18 = nix_2_18.outputs.packages.${currentStdenv.hostPlatform.system}.default;
# Nix 2.18 has been removed from Nixpkgs ≥ 25.05, so we need to reintroduce it ourselves for our tests.
nix_2_18 =
nix_2_18.outputs.packages.${currentStdenv.hostPlatform.system}.default.overrideAttrs
(_: {
pname = "nix";
});
};
# Forward from the previous stage as we dont want it to pick the lowdown override
@@ -219,6 +224,7 @@
lix-clang-tidy = final.callPackage ./subprojects/lix-clang-tidy { };
nix-eval-jobs = final.callPackage ./subprojects/nix-eval-jobs {
stdenv = currentStdenv;
srcDir = ./subprojects/nix-eval-jobs;
};
@@ -238,6 +244,23 @@
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 =
assert lib.versionAtLeast prev.lowdown.version "2.0.0";
prev.lowdown;
capnproto = prev.capnproto.overrideAttrs (old: {
patches =
old.patches or [ ]
++ [
# backport of https://github.com/capnproto/capnproto/pull/1810
./misc/capnproto-promise-nodiscard.patch
]
++ lib.optionals (lib.versionOlder old.version "1.2.0") [
# backport of https://github.com/capnproto/capnproto/pull/2296
./misc/capnproto-monotonic-clocks-are-a-lie.patch
];
});
};
in
{
@@ -252,6 +275,22 @@
# 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
'';
}
);
devShell = forAllSystems (system: {
default = self.devShells.${system}.default;
clang = self.devShells.${system}.native-clangStdenvPackages;
@@ -326,7 +365,10 @@
;
}
// {
nix-eval-jobs = forAllSystems (system: self.packages.${system}.nix-eval-jobs.tests.nix-eval-jobs);
# the n-e-j test suite is unusably slow in darwin ci. disbled until anywho fixes this.
nix-eval-jobs = (lib.genAttrs nonDarwinSystems) (
system: self.packages.${system}.nix-eval-jobs.tests.nix-eval-jobs
);
# This is x86_64-linux only, just because we have significantly
# cheaper x86_64-linux compute in CI.
@@ -365,48 +407,30 @@
'';
# clang-tidy run against the Lix codebase using the Lix clang-tidy plugin
clang-tidy =
clang-tidy = forAllSystems (
system:
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
pkgs = nixpkgsFor.${system}.native;
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
'';
evalNixpkgs = nixpkgsFor.x86_64-linux.native.callPackage ./tests/nixpkgs/eval.nix {
inherit nixpkgs-regression;
};
nixpkgsLibTests = forAllSystems (
system:
let
nixpkgsFor.${system}.native.callPackage ./tests/nixpkgs/lib.nix {
inherit nixpkgs system;
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" { nixVersions.latest = nix; }).attrpathsSuperset {
evalSystem = system;
})
];
}
);
};
@@ -486,7 +510,7 @@
dockerImage =
let
pkgs = nixpkgsFor.${system}.native;
nix2container' = import nix2container { inherit pkgs system; };
nix2container' = import nix2container { inherit pkgs; };
in
import ./docker.nix {
inherit pkgs;
@@ -518,8 +542,11 @@
inherit stdenv versionSuffix;
busybox-sandbox-shell = pkgs.busybox-sandbox-shell or pkgs.default-busybox-sandbox;
internalApiDocs = false;
includeSanitizerLibs = true;
# Use LLD in the dev shell by default for faster link times.
useLld = stdenv.hostPlatform.isLinux;
};
pre-commit = self.hydraJobs.pre-commit.${pkgs.system} or { };
pre-commit = self.hydraJobs.pre-commit.${pkgs.stdenv.hostPlatform.system} or { };
in
pkgs.callPackage nix.mkDevShell {
pre-commit-checks = pre-commit;
+2 -2
View File
@@ -33,7 +33,7 @@ install: (install-custom)
# Run tests (usually requires `install`) with extra options
test *OPTIONS:
meson test -C build --print-errorlogs {{ OPTIONS }}
meson test -C build --print-errorlogs --max-lines 10000 {{ OPTIONS }}
# Run unit tests only
test-unit *OPTIONS: (test "--suite" "check")
@@ -43,7 +43,7 @@ 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
cd tests/functional2 && python -m pytest -v {{ OPTIONS }}
alias clang-tidy := lint
+10
View File
@@ -0,0 +1,10 @@
# 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
+1
View File
@@ -0,0 +1 @@
# noqa: N999 # consistency with rest of the codebase
+104 -84
View File
@@ -1,93 +1,113 @@
from typing import List, NamedTuple
import dataclasses
from enum import Enum
from textwrap import dedent, indent
from typing import NamedTuple
from common import cxx_literal, generate_file, load_data
KNOWN_KEYS = set([
'name',
'type',
'constructorArgs',
'implementation',
'impure',
'renameInGlobalScope',
])
from common import cxx_literal, generate_file, load_data, get_argument_parser
class BuiltinConstant(NamedTuple):
name: str
type: str
implementation: str
impure: bool
rename_in_global_scope: bool
documentation: str
def parse(datum):
unknown_keys = set(datum.keys()) - KNOWN_KEYS
if unknown_keys:
raise Exception('unknown keys', unknown_keys)
return BuiltinConstant(
name = datum['name'],
type = datum['type'],
implementation = ('{' + ', '.join([f'NewValueAs::{datum["type"]}', *datum['constructorArgs']]) + '}') if 'constructorArgs' in datum else datum['implementation'],
impure = datum.get('impure', False),
rename_in_global_scope = datum.get('renameInGlobalScope', True),
documentation = datum.content,
)
VALUE_TYPES = {
'attrs': 'nAttrs',
'boolean': 'nBool',
'integer': 'nInt',
'list': 'nList',
'null': 'nNull',
'string': 'nString',
}
HUMAN_TYPES = {
'attrs': 'set',
'boolean': 'Boolean',
'integer': 'integer',
'list': 'list',
'null': 'null',
'string': 'string',
}
def main():
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('--header', help='Path of the header to generate')
ap.add_argument('--docs', help='Path of the documentation file to generate')
ap.add_argument('defs', help='Builtin definition files', nargs='+')
args = ap.parse_args()
builtin_constants = load_data(args.defs, BuiltinConstant.parse)
generate_file(args.header, builtin_constants, lambda constant:
# `builtins` is magic and must come first
'' if constant.name == 'builtins' else constant.name,
lambda constant:
f'''{'if (!evalSettings.pureEval) ' if constant.impure else ''}{{
addConstant({cxx_literal(('__' if constant.rename_in_global_scope else '') + constant.name)}, {constant.implementation}, {{
.type = {VALUE_TYPES[constant.type]},
.doc = {cxx_literal(constant.documentation)},
.impureOnly = {cxx_literal(constant.impure)},
}});
}}
''')
generate_file(args.docs, builtin_constants, lambda constant: constant.name, lambda constant:
f'''<dt id="builtins-{constant.name}">
<a href="#builtins-{constant.name}"><code>{constant.name}</code></a> ({HUMAN_TYPES[constant.type]})
</dt>
<dd>
{constant.documentation}
''' + ('''> **Note**
IMPURE_NOTE = """
> **Note**
>
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
''' if constant.impure else '') + '''</dd>
"""
''')
if __name__ == '__main__':
class TypeName(NamedTuple):
human: str
code: str
class BuiltinType(TypeName, Enum):
attrs = TypeName("set", "nAttrs")
boolean = TypeName("boolean", "nBool")
integer = TypeName("integer", "nInt")
list = TypeName("list", "nList")
null = TypeName("null", "nNull")
string = TypeName("string", "nString")
@classmethod
def from_string(cls, t_name: str) -> "BuiltinType":
for t in cls:
if t_name == t.name:
return t
msg = f"Invalid builtin type: {t_name}"
raise ValueError(msg)
@dataclasses.dataclass
class BuiltinConstant:
name: str
documentation: str
# Fields with different name in the Post than in here
# our fields
type: BuiltinType = dataclasses.field(init=False)
# Post fields
type_str: dataclasses.InitVar[str]
constructor_args: dataclasses.InitVar[list[str] | None] = None
implementation: str = ""
impure: bool = False
rename_in_global_scope: bool = True
def __post_init__(self, type_str: str, constructor_args: list[str] | None):
self.type = BuiltinType.from_string(type_str)
if constructor_args is not None:
args = [f"NewValueAs::{type_str}"] + constructor_args
self.implementation = f"{{{','.join(args)}}}"
@property
def code(self) -> str:
cond = "if (!evalSettings.pureEval) " if self.impure else ""
return dedent(f"""
{cond} {{
addConstant(
{cxx_literal(("__" if self.rename_in_global_scope else "") + self.name)},
{self.implementation},
{{
.type = {self.type.code},
.doc = {cxx_literal(self.documentation)},
.impureOnly = {cxx_literal(self.impure)},
}}
);
}}
""")
@property
def docs(self) -> str:
indentation = " " * 3
return dedent(f"""
<dt id="builtins-{self.name}">
<a href="#builtins-{self.name}"><code>{self.name}</code></a> ({self.type.human})
</dt>
<dd>
{indent(self.documentation, indentation)}
{indent(IMPURE_NOTE, indentation) if self.impure else ""}
</dd>
""")
def main():
args = get_argument_parser().parse_args()
builtin_constants = load_data(args.defs, BuiltinConstant)
generate_file(
args.header,
builtin_constants,
lambda constant:
# `builtins` is magic and must come first
"" if constant.name == "builtins" else constant.name,
lambda b: b.code,
)
generate_file(args.docs, builtin_constants, lambda constant: constant.name, lambda b: b.docs)
if __name__ == "__main__":
main()
+74 -66
View File
@@ -1,82 +1,90 @@
from typing import List, NamedTuple, Optional
import dataclasses
from textwrap import dedent, indent
from build_experimental_features import ExperimentalFeature
from common import cxx_literal, generate_file, load_data
from common import (
cxx_literal,
generate_file,
load_data,
get_argument_parser,
get_experimental_features,
)
KNOWN_KEYS = set([
'name',
'implementation',
'renameInGlobalScope',
'args',
'experimentalFeature',
])
class Builtin(NamedTuple):
@dataclasses.dataclass
class Builtin:
name: str
implementation: str
rename_in_global_scope: bool
args: List[str]
experimental_feature: Optional[str]
documentation: str
args: list[str]
experimental_feature: str | None = None
implementation: str = ""
rename_in_global_scope: bool = True
def parse(datum):
unknown_keys = set(datum.keys()) - KNOWN_KEYS
if unknown_keys:
raise Exception('unknown keys', unknown_keys)
return Builtin(
name = datum['name'],
implementation = datum['implementation'] if 'implementation' in datum else f'prim_{datum["name"]}',
rename_in_global_scope = datum.get('renameInGlobalScope', True),
args = datum['args'],
experimental_feature = datum.get('experimentalFeature', None),
documentation = datum.content,
def __post_init__(self):
self.implementation = self.implementation or f"prim_{self.name}"
def generate_code(self, experimental_features: dict[str, str]) -> str:
xf = experimental_features[self.experimental_feature]
cond = (
f"if (experimentalFeatureSettings.isEnabled({xf})) "
if self.experimental_feature
else ""
)
return dedent(f"""
{cond}{{
addPrimOp({{
.name = {cxx_literal(("__" if self.rename_in_global_scope else "") + self.name)},
.args = {cxx_literal(self.args)},
.arity = {len(self.args)},
.doc = {cxx_literal(self.documentation)},
.fun = {self.implementation},
.experimentalFeature = {xf},
}});
}}
""")
@property
def docs(self) -> str:
return dedent(f"""
<dt id="builtins-{self.name}">
<a href="#builtins-{self.name}"><code>{self.name} {
" ".join([f"<var>{arg}</var>" for arg in self.args])
}</code></a>
</dt>
<dd>
{indent(self.documentation, " " * 3)}
{
f"This function is only available if the [{self.experimental_feature}](@docroot@/contributing/experimental-features.md#xp-feature-{self.experimental_feature}) experimental feature is enabled."
if self.experimental_feature is not None
else ""
}
</dd>
""")
def main():
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('--header', help='Path of the header to generate')
ap.add_argument('--docs', help='Path of the documentation file to generate')
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
ap.add_argument('defs', help='Builtin definition files', nargs='+')
ap = get_argument_parser()
ap.add_argument(
"--experimental-features", help="Directory containing the experimental feature definitions"
)
args = ap.parse_args()
builtins = load_data(args.defs, Builtin.parse)
builtins = load_data(args.defs, Builtin)
experimental_feature_names = set([builtin.experimental_feature for (_, builtin) in builtins])
experimental_feature_names.discard(None)
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
experimental_features = dict(map(lambda path_and_feature:
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
experimental_features[None] = 'std::nullopt'
experimental_features = get_experimental_features(
args.experimental_features, [b.experimental_feature for (_, b) in builtins]
)
generate_file(args.header, builtins, lambda builtin: builtin.name, lambda builtin:
f'''{'' if builtin.experimental_feature is None else f'if (experimentalFeatureSettings.isEnabled({experimental_features[builtin.experimental_feature]})) '}{{
addPrimOp({{
.name = {cxx_literal(('__' if builtin.rename_in_global_scope else '') + builtin.name)},
.args = {cxx_literal(builtin.args)},
.arity = {len(builtin.args)},
.doc = {cxx_literal(builtin.documentation)},
.fun = {builtin.implementation},
.experimentalFeature = {experimental_features[builtin.experimental_feature]},
}});
}}
''')
generate_file(args.docs, builtins, lambda builtin: builtin.name, lambda builtin:
f'''<dt id="builtins-{builtin.name}">
<a href="#builtins-{builtin.name}"><code>{builtin.name} {' '.join([f'<var>{arg}</var>' for arg in builtin.args])}</code></a>
</dt>
<dd>
generate_file(
args.header,
builtins,
lambda builtin: builtin.name,
lambda b: b.generate_code(experimental_features),
)
generate_file(args.docs, builtins, lambda builtin: builtin.name, lambda b: b.docs)
{builtin.documentation}
''' + (f'''This function is only available if the [{builtin.experimental_feature}](@docroot@/contributing/experimental-features.md#xp-feature-{builtin.experimental_feature}) experimental feature is enabled.
''' if builtin.experimental_feature is not None else '') + '''</dd>
''')
if __name__ == '__main__':
if __name__ == "__main__":
main()
@@ -1,58 +0,0 @@
from typing import NamedTuple
from common import cxx_literal, generate_file, load_data
KNOWN_KEYS = set([
'name',
'internalName',
])
class ExperimentalFeature(NamedTuple):
name: str
internal_name: str
description: str
def parse(datum):
unknown_keys = set(datum.keys()) - KNOWN_KEYS
if unknown_keys:
raise ValueError('unknown keys', unknown_keys)
return ExperimentalFeature(
name = datum['name'],
internal_name = datum['internalName'],
description = datum.content,
)
def main():
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('--deprecated', action='store_true', help='Generate deprecated features')
ap.add_argument('--header', help='Path of the declaration header to generate')
ap.add_argument('--impl-header', help='Path of the implementation header to generate')
ap.add_argument('--descriptions', help='Path of the description file to generate')
ap.add_argument('--shortlist', help='Path of the shortlist file to generate')
ap.add_argument('defs', help='Experimental feature definition files', nargs='+')
args = ap.parse_args()
features = load_data(args.defs, ExperimentalFeature.parse)
generate_file(args.header, features, lambda feature: feature.name, lambda feature:
f' {feature.internal_name},\n')
generate_file(args.impl_header, features, lambda feature: feature.name, lambda feature:
f''' {{
.tag = {"Dep" if args.deprecated else "Xp"}::{feature.internal_name},
.name = {cxx_literal(feature.name)},
.description = {cxx_literal(feature.description)},
}},
''')
generate_file(args.descriptions, features, lambda feature: feature.name, lambda feature:
f'''## [`{feature.name}`]{{#{"dp" if args.deprecated else "xp"}-feature-{feature.name}}}
{feature.description}
''')
generate_file(args.shortlist, features, lambda feature: feature.name, lambda feature:
f' - [`{feature.name}`](@docroot@/contributing/{"deprecated" if args.deprecated else "experimental"}-features.md#{"dp" if args.deprecated else "xp"}-feature-{feature.name})\n')
if __name__ == '__main__':
main()
+105
View File
@@ -0,0 +1,105 @@
import dataclasses
from enum import Enum
from textwrap import dedent
from typing import ClassVar, NamedTuple
from common import cxx_literal, generate_file, load_data, get_argument_parser
class FeatureTypeNames(NamedTuple):
code_tag: str
doc_tag: str
class TimelineEvent(NamedTuple):
date: str
release: str
message: str
cls: list[int]
class FeatureType(FeatureTypeNames, Enum):
experimental = FeatureTypeNames("Xp", "xp")
deprecated = FeatureTypeNames("Dep", "dp")
@dataclasses.dataclass
class ExtraFeature:
name: str
internal_name: str
documentation: str
timeline: list[TimelineEvent] = dataclasses.field(default_factory=list)
type: ClassVar[FeatureType]
@property
def code(self) -> str:
return dedent(f"""
{{
.tag = {ExtraFeature.type.code_tag}::{self.internal_name},
.name = {cxx_literal(self.name)},
.description = {cxx_literal(self.documentation)},
}},
""")
@property
def docs(self) -> str:
timeline = (
f"""
### Timeline
{
"\n ".join(
[
f"- {event.date}, {event.release}: {event.message} [{", ".join([f'[CL {cl}](https://git.lix.systems/c/lix/+/{cl})' for cl in event.cls])}]"
for event in self.timeline
]
)
}
"""
if self.timeline
else ""
)
return dedent(f"""
## [`{self.name}`]{{#{ExtraFeature.type.doc_tag}-feature-{self.name}}}
{self.documentation.replace("\n", f"\n{' ' * 3}")}
{timeline}
""")
@property
def short_docs(self) -> str:
return f" - [`{self.name}`](@docroot@/contributing/{ExtraFeature.type.name}-features.md#{ExtraFeature.type.doc_tag}-feature-{self.name})\n"
def main():
ap = get_argument_parser()
ap.add_argument("--deprecated", action="store_true", help="Generate deprecated features")
ap.add_argument("--impl-header", help="Path of the implementation header to generate")
ap.add_argument("--shortlist", help="Path of the shortlist file to generate")
args = ap.parse_args()
ExtraFeature.type = FeatureType.deprecated if args.deprecated else FeatureType.experimental
def load(**kwargs) -> ExtraFeature:
kwargs["timeline"] = [TimelineEvent(**args) for args in kwargs.get("timeline", [])]
return ExtraFeature(**kwargs)
features = load_data(args.defs, load)
generate_file(
args.header,
features,
lambda feature: feature.name,
lambda feature: f" {feature.internal_name},\n",
)
generate_file(args.impl_header, features, lambda feature: feature.name, lambda f: f.code)
generate_file(args.docs, features, lambda feature: feature.name, lambda f: f.docs)
generate_file(args.shortlist, features, lambda feature: feature.name, lambda f: f.short_docs)
if __name__ == "__main__":
main()
+136 -120
View File
@@ -1,141 +1,157 @@
from typing import List, NamedTuple, Optional
import dataclasses
from textwrap import dedent
from typing import Any
from build_experimental_features import ExperimentalFeature
from common import cxx_literal, generate_file, load_data
from common import (
cxx_literal,
generate_file,
load_data,
get_experimental_features,
get_argument_parser,
)
KNOWN_KEYS = set([
'name',
'internalName',
'platforms',
'type',
'settingType',
'default',
'defaultExpr',
'defaultText',
'aliases',
'experimentalFeature',
'deprecated',
])
class Setting(NamedTuple):
name: str
internal_name: str
description: str
platforms: Optional[List[str]]
setting_type: str
default_expr: str
default_text: str
aliases: List[str]
experimental_feature: Optional[str]
deprecated: bool
PLATFORM_WARNING = """
> **Note**
> This setting is only available on {platforms} systems.
def parse(datum):
unknown_keys = set(datum.keys()) - KNOWN_KEYS
if unknown_keys:
raise ValueError('unknown keys', unknown_keys)
default_text = f'`{nix_conf_literal(datum["default"])}`' if 'default' in datum else datum['defaultText']
if default_text == '``':
default_text = '*empty*'
return Setting(
name = datum['name'],
internal_name = datum['internalName'],
description = datum.content,
platforms = datum.get('platforms', None),
setting_type = f'Setting<{datum["type"]}>' if 'type' in datum else datum['settingType'],
default_expr = cxx_literal(datum['default']) if 'default' in datum else datum['defaultExpr'],
default_text = default_text,
aliases = datum.get('aliases', []),
experimental_feature = datum.get('experimentalFeature', None),
deprecated = datum.get('deprecated', False),
)
"""
platform_names = {
'darwin': 'Darwin',
'linux': 'Linux',
}
def nix_conf_literal(v):
if v is None:
return ''
elif isinstance(v, bool) and v == False: # 0 == False
return 'false'
elif isinstance(v, bool) and v == True: # 1 == True
return 'true'
elif isinstance(v, int):
return str(v)
elif isinstance(v, str):
return v
elif isinstance(v, list):
return ' '.join([nix_conf_literal(item) for item in v])
else:
raise NotImplementedError(f'Cannot represent {repr(v)} in nix.conf')
def indent(prefix, body):
return ''.join(['\n' if line == '' else f'{prefix}{line}\n' for line in body.split('\n')])
def main():
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('--kernel', help='Name of the kernel Lix will run on')
ap.add_argument('--header', help='Path of the header to generate')
ap.add_argument('--docs', help='Path of the documentation file to generate')
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
ap.add_argument('defs', help='Setting definition files', nargs='+')
args = ap.parse_args()
settings = load_data(args.defs, Setting.parse)
experimental_feature_names = set([setting.experimental_feature for (_, setting) in settings])
experimental_feature_names.discard(None)
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
experimental_features = dict(map(lambda path_and_feature:
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
experimental_features[None] = 'std::nullopt'
generate_file(args.header, settings, lambda setting: setting.name, lambda setting:
f'''{setting.setting_type} {setting.internal_name} {{
this,
{setting.default_expr},
{cxx_literal(setting.name)},
{cxx_literal(setting.description)},
{cxx_literal(setting.aliases)},
true,
{experimental_features[setting.experimental_feature]},
{cxx_literal(setting.deprecated)}
}};
''' if setting.platforms is None or args.kernel in setting.platforms else '')
generate_file(args.docs, settings, lambda setting: setting.name, lambda setting:
f'''- <span id="conf-{setting.name}">[`{setting.name}`](#conf-{setting.name})</span>
{indent(" ", setting.description)}
''' + (f''' > **Note**
> This setting is only available on {', '.join([platform_names[platform] for platform in setting.platforms])} systems.
''' if setting.platforms is not None else '') + (f''' > **Warning**
XP_WARNING = """
> **Warning**
> This setting is part of an
> [experimental feature](@docroot@/contributing/experimental-features.md).
To change this setting, you need to make sure the corresponding experimental feature,
[`{setting.experimental_feature}`](@docroot@/contributing/experimental-features.md#xp-feature-{setting.experimental_feature}),
[`{feature}`](@docroot@/contributing/experimental-features.md#xp-feature-{feature}),
is enabled.
For example, include the following in [`nix.conf`](#):
```
extra-experimental-features = {setting.experimental_feature}
{setting.name} = ...
extra-experimental-features = {feature}
{name} = ...
```
''' if setting.experimental_feature is not None else '') + (''' > **Warning**
"""
DEPR_WARNING = """
> **Warning**
> This setting is deprecated and will be removed in a future version of Lix.
''' if setting.deprecated else '') + f''' **Default:** {setting.default_text}
"""
''' + (f''' **Deprecated alias:** {', '.join([f'`{item}`' for item in setting.aliases])}
''' if setting.aliases != [] else ''))
@dataclasses.dataclass
class Setting:
name: str
internal_name: str
documentation: str
if __name__ == '__main__':
default_text: str = ""
setting_type: str = ""
default_expr: str = ""
platforms: list[str] = dataclasses.field(default_factory=list)
aliases: list[str] = dataclasses.field(default_factory=list)
experimental_feature: str | None = None
deprecated: bool = False
default: dataclasses.InitVar[str | None] = None
type_str: dataclasses.InitVar[str | None] = None
def __post_init__(self, default: Any, type_str: str | None):
if default is not None: # is not None nor an empty String
self.default_text = f"`{nix_conf_literal(default)}`"
self.default_expr = self.default_expr or cxx_literal(default)
self.default_text = self.default_text or "*empty*"
if type_str is not None:
self.setting_type = f"Setting<{type_str}>"
def generate_code(self, experimental_features: dict[str | None, str]) -> str:
indentation = " " * 4
expr = (indent(indentation, self.default_expr) + indentation) if "\n" in self.default_expr else self.default_expr
return dedent(f"""
{self.setting_type} {self.internal_name} {{
this,
{expr},
{cxx_literal(self.name)},
{cxx_literal(self.documentation)},
{cxx_literal(self.aliases)},
true,
{experimental_features[self.experimental_feature]},
{cxx_literal(self.deprecated)}
}};
""")
@property
def docs(self) -> str:
indentation = " " * 3
platforms = [p.capitalize() for p in self.platforms]
aliases = [f"`{item}`" for item in self.aliases]
description = dedent(f"""
{indent(indentation, self.documentation)}
{indent(indentation, PLATFORM_WARNING.format(platforms=str(platforms)[1:-1])) if self.platforms else ""}
{indent(indentation, XP_WARNING.format(feature=self.experimental_feature, name=self.name)) if self.experimental_feature is not None else ""}
{indent(indentation, DEPR_WARNING) if self.deprecated else ""}
**Default:** {self.default_text}
{f"**Deprecated alias:** {str(aliases)[1:-1]}\n" if self.aliases else ""}
""")
return f'- <span id="conf-{self.name}">[`{self.name}`](#conf-{self.name})</span>' + indent(
" ", # indent by two space to make it part of the list point
description,
)
platform_names = {"darwin": "Darwin", "linux": "Linux"}
def nix_conf_literal(v: Any) -> str:
if v is None:
return ""
if v is False:
return "false"
if v is True:
return "true"
if isinstance(v, int):
return str(v)
if isinstance(v, str):
return v
if isinstance(v, list):
return " ".join([nix_conf_literal(item) for item in v])
msg = f"Cannot represent {v!r} in nix.conf"
raise NotImplementedError(msg)
def indent(prefix: str, body: str) -> str:
return "".join(["\n" if not line else f"{prefix}{line}\n" for line in body.split("\n")])
def main():
ap = get_argument_parser()
ap.add_argument("--kernel", help="Name of the kernel Lix will run on")
ap.add_argument(
"--experimental-features", help="Directory containing the experimental feature definitions"
)
args = ap.parse_args()
settings = load_data(args.defs, Setting)
experimental_features = get_experimental_features(
args.experimental_features, [s.experimental_feature for (_, s) in settings]
)
generate_file(
args.header,
settings,
lambda setting: setting.name,
lambda setting: setting.generate_code(experimental_features)
if not setting.platforms or args.kernel in setting.platforms
else "",
)
generate_file(args.docs, settings, lambda setting: setting.name, lambda setting: setting.docs)
if __name__ == "__main__":
main()
+68
View File
@@ -0,0 +1,68 @@
#!@python@
# ruff: noqa: SIM112 # ignore lowercase env variable names for capnpc as we have them in lower case as arguments
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 = Path.cwd()
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_file in request.requestedFiles:
deps += " ".join(f"{input_file.filename}.{o}" for o in outputs)
deps += ":"
for dep in input_file.imports:
if dep.name.startswith("/"):
for candidate in (Path(i + dep.name) for i in include):
if candidate.exists():
deps += " " + str(candidate)
break
else:
msg = "not handling relative includes"
raise RuntimeError(msg)
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"] = str(Path.cwd())
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()
+95 -42
View File
@@ -1,60 +1,113 @@
import argparse
import re
from collections.abc import Callable
from pathlib import Path
from typing import Any
import frontmatter
import pathlib
from collections import defaultdict
def cxx_escape_character(c):
if ord(c) >= 0x20 and ord(c) < 0x7f and c != '"' and c != '?' and c != '\\':
def cxx_escape_character(c: str) -> str:
if 0x20 <= ord(c) < 0x7F and c != '"' and c != "?" and c != "\\":
return c
elif c == '\t':
return r'\t'
elif c == '\n':
return r'\n'
elif c == '\r':
return r'\r'
elif c == '"':
return r'\"'
elif c == '?':
return r'\?'
elif c == '\\':
return r'\\'
elif ord(c) <= 0xffff:
return str.format(r'\u{:04x}', ord(c))
else:
return str.format(r'\U{:08x}', ord(c))
if c == "\t":
return r"\t"
if c == "\n":
return r"\n"
if c == "\r":
return r"\r"
if c == '"':
return r"\""
if c == "?":
return r"\?"
if c == "\\":
return r"\\"
if ord(c) <= 0xFFFF:
return str.format(r"\u{:04x}", ord(c))
return str.format(r"\U{:08x}", ord(c))
def cxx_literal(v):
def cxx_literal(v: Any) -> str:
if v is None:
return 'std::nullopt'
elif isinstance(v, bool) and v == False: # 0 == False
return 'false'
elif isinstance(v, bool) and v == True: # 1 == True
return 'true'
elif isinstance(v, int):
return "std::nullopt"
if v is False:
return "false"
if v is True:
return "true"
if isinstance(v, int):
return str(v)
elif isinstance(v, str):
return ''.join(['"', *(cxx_escape_character(c) for c in v), '"'])
elif isinstance(v, list):
return f'{{{", ".join([cxx_literal(item) for item in v])}}}'
else:
raise NotImplementedError(f'cannot represent {repr(v)} in C++')
if isinstance(v, str):
return "".join(['"', *(cxx_escape_character(c) for c in v), '"'])
if isinstance(v, list):
return f"{{{', '.join([cxx_literal(item) for item in v])}}}"
msg = f"cannot represent {v!r} in C++"
raise NotImplementedError(msg)
def load_data(defs, parse_function):
def get_experimental_features(
base_path: str, human_names: list[str | None]
) -> dict[str | None, str]:
experimental_feature_files = {
f"{base_path}/{xp_name}.md" for xp_name in human_names if xp_name is not None
}
from build_extra_features import ExtraFeature # noqa: PLC0415 # Avoid cyclic import
experimental_features_data = load_data(list(experimental_feature_files), ExtraFeature)
experimental_features: dict[str | None, str] = {
xf.name: f"Xp::{xf.internal_name}" for _, xf in experimental_features_data
}
experimental_features[None] = "std::nullopt"
return experimental_features
FIELD_RENAMES = {"type": "type_str", "content": "documentation"}
def load_data[T](defs: list[str], parse_function: type[T]) -> list[tuple[str, T]]:
data = []
for path in defs:
try:
datum = frontmatter.load(path)
data.append((path, parse_function(datum)))
datum = {
# convert camelCase to snake_case
re.sub(r"(?<=.)([A-Z])", lambda m: f"_{m.group(1).lower()}", k): v
for k, v in frontmatter.load(path).to_dict().items()
}
for post_name, field_name in FIELD_RENAMES.items():
if post_name in datum:
datum[field_name] = datum.pop(post_name)
data.append((path, parse_function(**datum)))
except Exception as e:
e.add_note(f'in {path}')
e.add_note(f"in {path}")
raise
return data
def generate_file(path, data, sort_key_function, generate_function):
def generate_file[T](
path: str | None,
data: list[T],
sort_key_function: Callable[[T], str],
generate_function: Callable[[T], str],
):
if path is not None:
with open(path, 'w') as out:
for path, datum in sorted(data, key=lambda pathAndDatum: sort_key_function(pathAndDatum[1])):
with Path(path).open("w") as out:
for path, datum in sorted(
data, key=lambda path_and_datum: sort_key_function(path_and_datum[1])
):
try:
out.write(generate_function(datum))
text = generate_function(datum)
out.write(text)
except Exception as e:
e.add_note(f'in {path}')
e.add_note(f"in {path}")
raise
def get_argument_parser() -> argparse.ArgumentParser:
ap = argparse.ArgumentParser()
ap.add_argument("--header", help="Path of the header to generate")
ap.add_argument("--docs", help="Path of the documentation file to generate")
ap.add_argument("defs", help="Builtin definition files", nargs="+")
return ap
+474 -218
View File
@@ -1,7 +1,22 @@
#include "lix/libstore/path.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/c-calls.hh"
#include "lix/libutil/error.hh"
#include "lix/libutil/file-descriptor.hh"
#include "lix/libutil/logging-rpc.hh"
#include "lix/libutil/logging.hh"
#include "lix/libutil/rpc.hh"
#include "lix/libutil/types-rpc.hh" // IWYU pragma: keep
#include "lix/libutil/types.hh"
#include <algorithm>
#include <chrono>
#include <capnp/rpc-twoparty.h>
#include <cstring>
#include <exception>
#include <kj/async.h>
#include <kj/time.h>
#include <set>
#include <memory>
#include <string>
#include <tuple>
#if __APPLE__
#include <sys/time.h>
@@ -17,13 +32,29 @@
#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;
bool initialized = false, used = false;
kj::Promise<void> init(InitContext context) override;
kj::Promise<void> buildImpl(BuildContext context);
kj::Promise<void> build(BuildContext context) override;
};
}
std::string escapeUri(std::string uri)
{
std::replace(uri.begin(), uri.end(), '/', '_');
@@ -38,7 +69,7 @@ static std::string makeLockFilename(const std::string & storeUri) {
// This avoids issues with the escaped URI being very long and causing
// path too long errors, while also avoiding any possibility of collision
// caused by simple truncation.
auto hash = hashString(HashType::SHA256, storeUri).to_string(Base::Base32, false);
auto hash = hashString(HashType::SHA256, storeUri).to_string(HashFormat::Base32, false);
return escapeUri(storeUri).substr(0, 48) + "-" + hash.substr(0, 16);
}
@@ -53,11 +84,278 @@ 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
kj::Promise<Result<void>> startLogThread(std::string buildDescription, std::string drvPath)
try {
if (!logPipe.readSide) {
co_return result::success();
}
logPipe.writeSide.close();
// NOTE this is very similar to handleBuilderOutput in DerivationGoal, but unlike
// the derivation goal we do not need to handle EIO from a pty here. we also have
// no timeouts or limits to keep track of, which makes deduplication less useful.
auto act = logger->startActivity(
lvlInfo, actBuild, buildDescription, Logger::Fields{drvPath, storeUri, 1, 1}
);
std::map<ActivityId, Activity> activities;
auto reader = AIO().lowLevelProvider.wrapInputFd(logPipe.readSide.get());
LogLineSplitter splitter;
auto flushLine = [&](const std::string & line) {
if (const auto state =
handleJSONLogMessage(line, act, activities, "the derivation builder"))
{
return *state;
} else {
return act.result(resBuildLogLine, line);
}
};
auto buf = kj::heapArray<char>(4096);
while (true) {
const auto got = co_await reader->tryRead(buf.begin(), 1, buf.size());
if (got == 0) {
break;
}
std::string_view data{buf.begin(), got};
while (!data.empty()) {
if (auto line = splitter.feed(data)) {
if (flushLine(*line) == Logger::BufferState::NeedsFlush) {
TRY_AWAIT(act.getLogger().flush());
}
}
}
}
if (auto line = splitter.finish(); !line.empty()) {
(void) flushLine(line);
TRY_AWAIT(act.getLogger().flush());
}
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
};
struct AcceptedBuild final : rpc::build_remote::HookInstance::AcceptedBuild::Server
{
ref<Store> store;
StorePath drvPath;
BuilderConnection builder;
bool used = false;
AcceptedBuild(ref<Store> store, StorePath drvPath, BuilderConnection builder)
: store(store)
, drvPath(drvPath)
, builder(std::move(builder))
{
}
kj::Promise<void> runImpl(RunContext context);
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 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 */
(void) sys::mkdir(currentLoad, 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.to_string(),
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 {
auto act = logger->startActivity(
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)
{
{
logger = makeJSONLogger(*logger);
/* Ensure we don't get any SSH passphrase or host key popups. */
unsetenv("DISPLAY");
unsetenv("SSH_ASKPASS");
@@ -70,240 +368,183 @@ static int main_build_remote(AsyncIoRoot & aio, std::string programName, Strings
verbosity = (Verbosity) std::stoll(argv.front());
FdSource source(STDIN_FILENO);
auto conn = aio.kj.lowLevelProvider->wrapUnixSocketFd(1);
capnp::TwoPartyServer srv(kj::heap<Instance>());
srv.accept(*conn, 1).wait(aio.kj.waitScope);
return 0;
}
}
kj::Promise<void> Instance::init(InitContext context)
{
try {
if (initialized) {
throw Error("build hook can only be initialized once");
}
logger = rpc::log::makeRpcLoggerClient(context.getParams().getLogger());
/* Read the parent's settings. */
while (readInt(source)) {
auto name = readString(source);
auto value = readString(source);
for (const auto & [name, value] : rpc::to<StringMap>(context.getParams().getSettings())) {
settings.set(name, value);
}
auto maxBuildJobs = settings.maxBuildJobs;
maxBuildJobs = settings.maxBuildJobs;
settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
initPlugins();
// 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 = aio.blockOn(openStore(settings.storeUri, {}, AllowDaemon::Disallow));
initialized = true;
/* 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>())
currentLoad = std::string { localStore->config().stateDir } + currentLoadName;
else
currentLoad = settings.nixStateDir + currentLoadName;
context.getResults().initResult().setGood();
} catch (...) {
RPC_FILL(context.getResults(), initResult, std::current_exception());
}
std::shared_ptr<Store> sshStore;
AutoCloseFD bestSlotLock;
return kj::READY_NOW;
}
auto machines = getMachines();
debug("got %d remote builders", machines.size());
kj::Promise<void> Instance::buildImpl(BuildContext context)
try {
if (!initialized) {
throw Error("build hook not fully initialized");
}
if (machines.empty()) {
std::cerr << "# decline-permanently\n";
return 0;
// 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));
/* 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>()) {
currentLoad = std::string{localStore->config().stateDir} + currentLoadName;
} else {
currentLoad = settings.nixStateDir + currentLoadName;
}
auto machines = getMachines();
debug("got %d remote builders", machines.size());
if (machines.empty()) {
context.getResults().initResult().initGood().setDeclinePermanently();
co_return;
}
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 result = TRY_AWAIT(connectToBuilder(
store, drvPath, machines, maxBuildJobs, amWilling, neededSystem, requiredFeatures
));
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;
}
}
std::optional<StorePath> drvPath;
std::string storeUri;
auto builder = std::get_if<BuilderConnection>(&result);
assert(builder);
while (true) {
auto ac = context.getResults().initResult().initGood().initAccept();
ac.setMachine(kj::heap<AcceptedBuild>(store, drvPath, std::move(*builder)));
} catch (...) {
RPC_FILL(context.getResults(), initResult, std::current_exception());
}
try {
auto s = readString(source);
if (s != "try") return 0;
} catch (EndOfFile &) { return 0; }
kj::Promise<void> Instance::build(BuildContext context)
try {
if (used) {
throw Error("build hooks can only accept a single job");
}
used = true; // lock out other rpc calls during processing
co_await buildImpl(context);
TRY_AWAIT(logger->flush());
used = context.getResults().getResult().getGood().isAccept();
} catch (...) {
RPC_FILL(context.getResults(), getResult, std::current_exception());
}
auto amWilling = readInt(source);
auto neededSystem = readString(source);
drvPath = store->parseStorePath(readString(source));
auto requiredFeatures = readStrings<std::set<std::string>>(source);
kj::Promise<void> AcceptedBuild::run(RunContext context)
{
try {
auto oldLogger = logger;
logger = rpc::log::makeRpcLoggerClient(context.getParams().getLogger());
TRY_AWAIT(oldLogger->flush());
KJ_DEFER({
delete logger;
logger = oldLogger;
});
/* 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 = aio.blockOn(bestMachine->openStore());
aio.blockOn(sshStore->connect());
storeUri = bestMachine->storeUri;
} catch (std::exception & e) { // NOLINT(lix-foreign-exceptions)
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;
}
if (used) {
throw Error("build hooks builds are single-use items");
}
used = true;
co_await runImpl(context);
TRY_AWAIT(logger->flush());
} catch (...) {
RPC_FILL(context.getResults(), getResult, std::current_exception());
}
}
connected:
close(5);
kj::Promise<void> AcceptedBuild::runImpl(RunContext context)
{
try {
auto logHandler = builder.startLogThread(
fmt("%s on '%s'",
rpc::to<std::string_view>(context.getParams().getDescription()),
builder.storeUri),
store->printStorePath(drvPath)
);
assert(sshStore);
auto & sshStore = builder.sshStore;
auto & storeUri = builder.storeUri;
std::cerr << "# accept\n" << storeUri << "\n";
auto inputs = readStrings<PathSet>(source);
auto wantedOutputs = readStrings<StringSet>(source);
auto inputs = rpc::to<std::set<StorePath>>(context.getParams().getInputs(), *store);
auto wantedOutputs = rpc::to<std::set<std::string>>(context.getParams().getWantedOutputs());
auto lockFileName = currentLoad + "/" + makeLockFilename(storeUri) + ".upload-lock";
AutoCloseFD uploadLock = openLockFile(lockFileName, true);
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));
auto act = logger->startActivity(
lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri)
);
if (!unsafeLockFileSingleThreaded(uploadLock.get(), ltWrite, std::chrono::minutes(15)))
printError("somebody is hogging the upload lock for '%s', continuing...");
auto result = TRY_AWAIT(
AIO().timeoutAfter(15 * kj::MINUTES, lockFileAsync(uploadLock.get(), ltWrite))
);
if (!result) {
printError("somebody is hogging the upload lock for '%s', continuing...", storeUri);
}
}
auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri));
aio.blockOn(copyPaths(
*store,
*sshStore,
store->parseStorePathSet(inputs),
NoRepair,
NoCheckSigs,
substitute
));
auto act = logger->startActivity(
lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri)
);
TRY_AWAIT(copyPaths(*store, *sshStore, inputs, NoRepair, NoCheckSigs, substitute));
}
uploadLock.reset();
auto drv = aio.blockOn(store->readDerivation(*drvPath));
auto drv = TRY_AWAIT(store->readDerivation(drvPath));
std::optional<BuildResult> optResult;
@@ -311,7 +552,7 @@ connected:
// stores), we assume we are. This is necessary for backwards
// compat.
bool trustedOrLegacy = ({
std::optional trusted = aio.blockOn(sshStore->isTrustedClient());
std::optional trusted = TRY_AWAIT(sshStore->isTrustedClient());
!trusted || *trusted;
});
@@ -330,46 +571,61 @@ connected:
//
// 2. Changing the `inputSrcs` set changes the associated
// output ids, which break CA derivations
if (!drv.inputDrvs.empty())
drv.inputSrcs = store->parseStorePathSet(inputs);
optResult = aio.blockOn(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);
if (!drv.inputDrvs.empty()) {
drv.inputSrcs = inputs;
}
optResult =
TRY_AWAIT(sshStore->buildDerivation(drvPath, (const BasicDerivation &) drv));
} else {
aio.blockOn(copyClosure(
*store, *sshStore, StorePathSet{*drvPath}, NoRepair, NoCheckSigs, substitute
TRY_AWAIT(copyClosure(
*store, *sshStore, StorePathSet{drvPath}, NoRepair, NoCheckSigs, substitute
));
auto res = aio.blockOn(sshStore->buildPathsWithResults({
DerivedPath::Built {
.drvPath = makeConstantStorePath(*drvPath),
.outputs = OutputsSpec::All {},
}
}));
auto res = TRY_AWAIT(sshStore->buildPathsWithResults({DerivedPath::Built{
.drvPath = makeConstantStorePath(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
);
}
StorePathSet missingPaths;
auto outputPaths = drv.outputsAndPaths(*store);
for (auto & [outputName, outputPath] : outputPaths) {
if (!aio.blockOn(store->isValidPath(outputPath.second)))
if (!TRY_AWAIT(store->isValidPath(outputPath.second))) {
missingPaths.insert(outputPath.second);
}
}
if (!missingPaths.empty()) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
auto act = logger->startActivity(
lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri)
);
if (auto localStore = store.try_cast_shared<LocalStore>())
for (auto & path : missingPaths)
localStore->locksHeld.insert(store->printStorePath(path)); /* FIXME: ugly */
aio.blockOn(
TRY_AWAIT(
copyPaths(*sshStore, *store, missingPaths, NoRepair, NoCheckSigs, NoSubstitute)
);
}
return 0;
// drop store connection, let log handler process any remaining input
builder.sshStore = nullptr;
TRY_AWAIT(logHandler);
context.getResults().initResult().setGood();
} catch (...) {
RPC_FILL(context.getResults(), initResult, std::current_exception());
}
}
+103
View File
@@ -0,0 +1,103 @@
#include "lix/libcmd/legacy.hh"
#include "lix/libstore/builtins.hh"
#include "lix/libstore/builtins/buildenv.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/error.hh"
#include "lix/libutil/file-system.hh"
#include "lix/libutil/logging.hh"
#include "lix/libutil/strings.hh"
#include "lix/libutil/types.hh"
#include <string_view>
using std::literals::operator""sv;
namespace nix {
static int main_builtin_builder(AsyncIoRoot & aio, std::string programName, Strings argv)
{
logger = makeJSONLogger(*logger);
std::map<std::string, std::string> env;
auto argvIt = argv.begin();
const auto argvEnd = argv.end();
// we do not use the argument parsing functions we have in libmain here, neither
// the legacy versions nor the newer ones. the legacy version could work, but we
// want to provide two sets of arguments separated by `--` and would need rather
// unpleasant state handling to use the legacy parser. the more modern parser is
// entirely incapable of doing this for us since it's all statically configured.
const auto getArg = [&](std::string_view desc) {
if (argvIt == argvEnd) {
throw Error("expected a value for %s", desc);
}
return *argvIt++;
};
if (auto val = string2Int<int>(getArg("verbosity"))) {
verbosity = verbosityFromIntClamped(*val);
} else {
throw Error("expected a verbosity argument");
}
while (argvIt != argvEnd) {
const auto arg = getArg("option");
if (arg == "--") {
break;
} else if (!arg.starts_with("--")) {
throw Error("unexpected builtin option %s", arg);
}
auto value = unescapeNul(getArg(arg));
globalConfig.set(arg.substr(2), value);
}
while (argvIt != argvEnd) {
const auto key = getArg("builder argument");
if (!key.starts_with("--")) {
throw Error("unexpected builtin builder argument %s", key);
}
env[unescapeNul(key.substr(2))] = unescapeNul(getArg(key));
}
auto getAttr = [&](const std::string & name) {
auto i = env.find(name);
if (i == env.end()) {
throw Error("attribute '%s' missing", name);
}
return i->second;
};
const auto builder = getAttr("builder");
if (builder == "builtin:fetchurl") {
const auto outputHashMode = getAttr("outputHashMode");
const auto hash = outputHashMode == "flat" ? [&] -> std::optional<Hash> {
const auto ht = parseHashTypeOpt(getAttr("outputHashAlgo"));
return newHashAllowEmpty(getAttr("outputHash"), ht);
}()
: std::nullopt;
BuiltinFetchurl{
.storePath = getAttr("out"),
.mainUrl = getAttr("url"),
.unpack = getOr(env, "unpack", "0") == "1",
.executable = getOr(env, "executable", "0") == "1",
.hash = hash,
}
.run(aio);
} else if (builder == "builtin:buildenv") {
builtinBuildenv(getAttr("out"), tokenizeString<Strings>(getAttr("derivations")), getAttr("manifest"));
} else if (builder == "builtin:unpack-channel") {
builtinUnpackChannel(getAttr("out"), getAttr("channelName"), getAttr("src"));
} else {
throw Error("unknown builtin builder %s", builder);
}
return 0;
}
void registerLegacyBuiltinBuilder()
{
LegacyCommandRegistry::add("builtin-builder", main_builtin_builder);
}
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
///@file
namespace nix {
void registerLegacyBuiltinBuilder();
}
+8 -10
View File
@@ -4,9 +4,7 @@
#include "lix/libutil/result.hh"
#include <iostream>
using std::cout;
#include <sstream>
namespace nix {
@@ -42,31 +40,31 @@ static std::string makeNode(std::string_view id, std::string_view label,
dotQuote(id), dotQuote(label), dotQuote(colour));
}
kj::Promise<Result<void>> printDotGraph(ref<Store> store, StorePathSet && roots)
kj::Promise<Result<std::string>> formatDotGraph(ref<Store> store, StorePathSet && roots)
try {
StorePathSet workList(std::move(roots));
StorePathSet doneSet;
std::stringstream result;
cout << "digraph G {\n";
result << "digraph G {\n";
while (!workList.empty()) {
auto path = std::move(workList.extract(workList.begin()).value());
if (!doneSet.insert(path).second) continue;
cout << makeNode(std::string(path.to_string()), path.name(), "#ff0000");
result << makeNode(std::string(path.to_string()), path.name(), "#ff0000");
for (auto & p : TRY_AWAIT(store->queryPathInfo(path))->references) {
if (p != path) {
workList.insert(p);
cout << makeEdge(std::string(p.to_string()), std::string(path.to_string()));
result << makeEdge(std::string(p.to_string()), std::string(path.to_string()));
}
}
}
cout << "}\n";
co_return result::success();
result << "}\n";
co_return result.str();
} catch (...) {
co_return result::current_exception();
}
+1 -2
View File
@@ -5,6 +5,5 @@
namespace nix {
kj::Promise<Result<void>> printDotGraph(ref<Store> store, StorePathSet && roots);
kj::Promise<Result<std::string>> formatDotGraph(ref<Store> store, StorePathSet && roots);
}
+16 -18
View File
@@ -5,9 +5,7 @@
#include "lix/libutil/result.hh"
#include <iostream>
using std::cout;
#include <sstream>
namespace nix {
@@ -47,21 +45,21 @@ static std::string makeNode(const ValidPathInfo & info)
(info.path.isDerivation() ? "derivation" : "output-path"));
}
kj::Promise<Result<void>> printGraphML(ref<Store> store, StorePathSet && roots)
kj::Promise<Result<std::string>> formatGraphML(ref<Store> store, StorePathSet && roots)
try {
StorePathSet workList(std::move(roots));
StorePathSet doneSet;
std::pair<StorePathSet::iterator, bool> ret;
std::stringstream result;
cout << "<?xml version='1.0' encoding='utf-8'?>\n"
<< "<graphml xmlns='http://graphml.graphdrawing.org/xmlns'\n"
<< " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
<< " xsi:schemaLocation='http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd'>\n"
<< "<key id='narSize' for='node' attr.name='narSize' attr.type='long'/>"
<< "<key id='name' for='node' attr.name='name' attr.type='string'/>"
<< "<key id='type' for='node' attr.name='type' attr.type='string'/>"
<< "<graph id='G' edgedefault='directed'>\n";
result << "<?xml version='1.0' encoding='utf-8'?>\n"
<< "<graphml xmlns='http://graphml.graphdrawing.org/xmlns'\n"
<< " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
<< " xsi:schemaLocation='http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd'>\n"
<< "<key id='narSize' for='node' attr.name='narSize' attr.type='long'/>"
<< "<key id='name' for='node' attr.name='name' attr.type='string'/>"
<< "<key id='type' for='node' attr.name='type' attr.type='string'/>"
<< "<graph id='G' edgedefault='directed'>\n";
while (!workList.empty()) {
auto path = std::move(workList.extract(workList.begin()).value());
@@ -70,20 +68,20 @@ try {
if (ret.second == false) continue;
auto info = TRY_AWAIT(store->queryPathInfo(path));
cout << makeNode(*info);
result << makeNode(*info);
for (auto & p : info->references) {
if (p != path) {
workList.insert(p);
cout << makeEdge(path.to_string(), p.to_string());
result << makeEdge(path.to_string(), p.to_string());
}
}
}
cout << "</graph>\n";
cout << "</graphml>\n";
co_return result::success();
result << "</graph>\n";
result << "</graphml>\n";
co_return result.str();
} catch (...) {
co_return result::current_exception();
}
+1 -2
View File
@@ -5,6 +5,5 @@
namespace nix {
kj::Promise<Result<void>> printGraphML(ref<Store> store, StorePathSet && roots);
kj::Promise<Result<std::string>> formatGraphML(ref<Store> store, StorePathSet && roots);
}
+2
View File
@@ -4,6 +4,7 @@ legacy_sources = files(
# `build-remote` is not really legacy (it powers all remote builds), but it's
# not a `nix3` command.
'build-remote.cc',
'builtin-builder.cc',
'dotgraph.cc',
'graphml.cc',
'nix-build.cc',
@@ -19,6 +20,7 @@ legacy_sources = files(
legacy_headers = files(
'build-remote.hh',
'builtin-builder.hh',
'nix-build.hh',
'nix-channel.hh',
'nix-collect-garbage.hh',
+82 -58
View File
@@ -9,6 +9,7 @@
#include "lix/libstore/store-api.hh"
#include "lix/libstore/local-fs-store.hh"
#include "lix/libstore/globals.hh"
#include "lix/libutil/c-calls.hh"
#include "lix/libutil/current-process.hh"
#include "lix/libstore/derivations.hh"
#include "lix/libmain/shared.hh"
@@ -18,10 +19,13 @@
#include "lix/libcmd/common-eval-args.hh"
#include "lix/libexpr/attr-path.hh"
#include "lix/libcmd/legacy.hh"
#include "lix/libutil/finally.hh"
#include "lix/libutil/processes.hh"
#include "lix/libutil/regex.hh"
#include "lix/libutil/shlex.hh"
#include "nix-build.hh"
#include "lix/libstore/temporary-dir.hh"
#include "lix/libutil/strings.hh"
extern char * * environ __attribute__((weak)); // Man what even is this
@@ -29,7 +33,7 @@ namespace nix {
using namespace std::string_literals;
static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings argv)
static int main_nix_build(AsyncIoRoot & aio, std::string programName, Strings argv)
{
auto dryRun = false;
auto runEnv = std::regex_search(programName, regex::parse("nix-shell$"));
@@ -187,7 +191,12 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
if (packages && fromArgs)
throw UsageError("'-p' and '-E' are mutually exclusive");
AutoDelete tmpDir(createTempDir("", myName));
AutoDelete tmpDir(createTempDir(myName));
// NOTE: we assume there's no `build-top` directory created inside of `tmpDir` and we have
// ownership of this.
auto buildTopTmpDir = tmpDir + "/build-top";
createDirs(buildTopTmpDir);
if (outLink.empty())
outLink = (Path) tmpDir + "/result";
@@ -204,7 +213,7 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
auto autoArgsWithInNixShell = autoArgs;
if (runEnv) {
auto newArgs = evaluator->buildBindings(autoArgsWithInNixShell->size() + 1);
newArgs.alloc("inNixShell").mkBool(true);
newArgs.alloc("inNixShell") = {NewValueAs::boolean, true};
for (auto & i : *autoArgs) newArgs.insert(i);
autoArgsWithInNixShell = newArgs.finish();
}
@@ -224,8 +233,9 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
left = {"default.nix"};
}
if (runEnv)
setenv("IN_NIX_SHELL", pure ? "pure" : "impure", 1);
if (runEnv) {
(void) sys::setenv("IN_NIX_SHELL", pure ? "pure" : "impure", 1);
}
DrvInfos drvs;
@@ -262,8 +272,7 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
if (attrPaths.empty()) attrPaths = {""};
for (auto e : exprs) {
Value vRoot;
state->eval(e, vRoot);
Value vRoot = state->eval(e);
std::function<bool(const Value & v)> takesNixShellAttr;
takesNixShellAttr = [&](const Value & v) {
@@ -272,7 +281,7 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
}
bool add = false;
if (v.type() == nFunction) {
if (auto pattern = dynamic_cast<AttrsPattern *>(v.lambda.fun->pattern.get())) {
if (auto pattern = dynamic_cast<AttrsPattern *>(v.lambda().fun->pattern.get())) {
for (auto & i : pattern->formals) {
if (evaluator->symbols[i.name] == "inNixShell") {
add = true;
@@ -285,12 +294,12 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
};
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(
*state,
i,
takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs,
vRoot
).first);
Value v(
findAlongAttrPath(
*state, i, takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs, vRoot
)
.first
);
state->forceValue(v, noPos);
getDerivations(
*state,
@@ -346,8 +355,7 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
"(import <nixpkgs> {}).bashInteractive",
CanonPath::fromCwd());
Value v;
state->eval(expr, v);
Value v = state->eval(expr);
auto drv = getDerivation(*state, v, false);
if (!drv)
@@ -397,7 +405,9 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
buildPaths(pathsToBuild);
if (dryRun) return;
if (dryRun) {
return 0;
}
if (shellDrv) {
auto shellDrvOutputs =
@@ -418,25 +428,37 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
env["__ETC_PROFILE_SOURCED"] = "1";
}
// Set NIX_SHELL_LEVEL
env["NIX_SHELL_LEVEL"] = std::to_string(
getEnvNonEmpty("NIX_SHELL_LEVEL")
.and_then([](std::string lvl) { return string2Int<size_t>(lvl); })
.value_or(0)
+ 1
);
// We re-export similarly to what occurs inside of a derivation goal `NIX_LOG_FD` to stderr.
// So that stdenv hooks that logs information can be observed inside this debugging tool.
env["NIX_LOG_FD"] = "2";
// Don't use defaultTempDir() here! We want to preserve the user's TMPDIR for the shell
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = getEnvNonEmpty("TMPDIR").value_or("/tmp");
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] =
getEnvNonEmpty("TMPDIR").value_or(buildTopTmpDir);
env["NIX_STORE"] = store->config().storeDir;
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
auto passAsFile = tokenizeString<StringSet>(getOr(drv.env, "passAsFile", ""));
bool keepTmp = false;
int fileNr = 0;
for (auto & var : drv.env)
if (passAsFile.count(var.first)) {
keepTmp = true;
auto fn = ".attr-" + std::to_string(fileNr++);
Path p = (Path) tmpDir + "/" + fn;
writeFile(p, var.second);
env[var.first + "Path"] = p;
} else
} else {
env[var.first] = var.second;
}
std::string structuredAttrsRC;
@@ -469,7 +491,6 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
env["NIX_ATTRS_SH_FILE"] = attrsSH;
env["NIX_ATTRS_JSON_FILE"] = attrsJSON;
keepTmp = true;
}
}
@@ -479,24 +500,13 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
lose the current $PATH directories. */
auto rcfile = (Path) tmpDir + "/rc";
auto tz = getEnv("TZ");
std::string rc = fmt(
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"
"%2%"
"%3%"
// always clear PATH.
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
"unset PATH;"
"dontAddDisableDepTrack=1;\n",
shellEscape(tmpDir),
(keepTmp
? "trap _nix_shell_clean_tmpdir EXIT; "
"exitHooks+=(_nix_shell_clean_tmpdir); "
"failureHooks+=(_nix_shell_clean_tmpdir); "
: "_nix_shell_clean_tmpdir; "),
(pure
? ""
: "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc; p=$PATH; ")
);
std::string rc =
fmt("%1%"
// always clear PATH.
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
"unset PATH;"
"dontAddDisableDepTrack=1;\n",
(pure ? "" : "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc; p=$PATH; "));
rc += structuredAttrsRC;
rc += fmt(
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
@@ -526,27 +536,37 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
vomit("Sourcing nix-shell with file %s and contents:\n%s", rcfile, rc);
writeFile(rcfile, rc);
Strings envStrs;
for (auto & i : env)
envStrs.push_back(i.first + "=" + i.second);
auto args = interactive
? Strings{"bash", "--rcfile", rcfile}
: Strings{"bash", rcfile};
auto envPtrs = stringsToCharPtrs(envStrs);
environ = envPtrs.data();
auto argPtrs = stringsToCharPtrs(args);
restoreProcessContext();
auto args = interactive ? Strings{"--rcfile", rcfile} : Strings{rcfile};
// We are going to run an interactive command, do not let the logger send a line.
logger->pause();
execvp(shell->c_str(), argPtrs.data());
printMsg(lvlChatty, "running shell: %s", concatMapStringsSep(" ", args, shellEscape));
throw SysError("executing shell '%s'", *shell);
RunningProgram proc = runProgram2({
.program = *shell,
.searchPath = true,
.args = args,
.environment = env,
});
// NOTE: we wait and return the status check immediately.
// If there's interruption, we will swallow it and wait again for termination.
auto toExitStatus = [](int waitRes) {
if (WIFEXITED(waitRes)) {
return WEXITSTATUS(waitRes);
} else if (WIFSIGNALED(waitRes)) {
return 128 + WTERMSIG(waitRes);
} else {
return 255;
}
};
try {
return toExitStatus(proc.wait());
} catch (Interrupted &) {
return toExitStatus(proc.wait());
}
}
else {
@@ -580,7 +600,9 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
buildPaths(pathsToBuild);
if (dryRun) return;
if (dryRun) {
return 0;
}
std::vector<StorePath> outPaths;
@@ -609,6 +631,8 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
for (auto & path : outPaths)
std::cout << store->printStorePath(path) << '\n';
}
return 0;
}
void registerLegacyNixBuildAndNixShell() {
+30 -12
View File
@@ -8,7 +8,9 @@
#include "lix/libexpr/eval-settings.hh" // for defexpr
#include "lix/libstore/temporary-dir.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/c-calls.hh"
#include "lix/libutil/regex.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/users.hh"
#include "nix-channel.hh"
@@ -43,7 +45,7 @@ static void readChannels()
// Writes the list of channels.
static void writeChannels()
{
auto channelsFD = AutoCloseFD{open(channelsList.c_str(), O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, 0644)};
auto channelsFD = sys::open(channelsList, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, 0644);
if (!channelsFD)
throw SysError("opening '%1%' for writing", channelsList);
for (const auto & channel : channels)
@@ -65,13 +67,18 @@ static void addChannel(const std::string & url, const std::string & name)
static Path profile;
// Remove a channel.
static void removeChannel(const std::string & name)
{
static kj::Promise<Result<void>> removeChannel(const std::string & name)
try {
readChannels();
channels.erase(name);
writeChannels();
runProgram(settings.nixBinDir + "/nix-env", true, { "--profile", profile, "--uninstall", name });
TRY_AWAIT(runProgram(
settings.nixBinDir + "/nix-env", true, {"--profile", profile, "--uninstall", name}
));
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
static Path nixDefExpr;
@@ -127,8 +134,14 @@ static void update(AsyncIoRoot & aio, const StringSet & channelNames)
bool unpacked = false;
if (std::regex_search(filename, regex::parse("\\.tar\\.(gz|bz2|xz)$"))) {
runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath +
"{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" });
aio.blockOn(runProgram(
settings.nixBinDir + "/nix-build",
false,
{"--no-out-link",
"--expr",
"import " + unpackChannelPath + "{ name = \"" + cname + "\"; channelName = \""
+ name + "\"; src = builtins.storePath \"" + filename + "\"; }"}
));
unpacked = true;
}
@@ -158,15 +171,16 @@ static void update(AsyncIoRoot & aio, const StringSet & channelNames)
for (auto & expr : exprs)
envArgs.push_back(std::move(expr));
envArgs.push_back("--quiet");
runProgram(settings.nixBinDir + "/nix-env", false, envArgs);
aio.blockOn(runProgram(settings.nixBinDir + "/nix-env", false, envArgs));
// Make the channels appear in nix-env.
struct stat st;
if (lstat(nixDefExpr.c_str(), &st) == 0) {
if (sys::lstat(nixDefExpr, &st) == 0) {
if (S_ISLNK(st.st_mode))
// old-skool ~/.nix-defexpr
if (unlink(nixDefExpr.c_str()) == -1)
if (sys::unlink(nixDefExpr) == -1) {
throw SysError("unlinking %1%", nixDefExpr);
}
} else if (errno != ENOENT) {
throw SysError("getting status of %1%", nixDefExpr);
}
@@ -244,7 +258,7 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings
case cRemove:
if (args.size() != 1)
throw UsageError("'--remove' requires one argument");
removeChannel(args[0]);
aio.blockOn(removeChannel(args[0]));
break;
case cList:
if (!args.empty())
@@ -259,7 +273,11 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings
case cListGenerations:
if (!args.empty())
throw UsageError("'--list-generations' expects no arguments");
std::cout << runProgram(settings.nixBinDir + "/nix-env", false, {"--profile", profile, "--list-generations"}) << std::flush;
std::cout << aio.blockOn(runProgram(
settings.nixBinDir + "/nix-env",
false,
{"--profile", profile, "--list-generations"}
)) << std::flush;
break;
case cRollback:
if (args.size() > 1)
@@ -271,7 +289,7 @@ static int main_nix_channel(AsyncIoRoot & aio, std::string programName, Strings
} else {
envArgs.push_back("--rollback");
}
runProgram(settings.nixBinDir + "/nix-env", false, envArgs);
aio.blockOn(runProgram(settings.nixBinDir + "/nix-env", false, envArgs));
break;
}
+12 -20
View File
@@ -1,3 +1,4 @@
#include "lix/libutil/c-calls.hh"
#include "lix/libutil/file-system.hh"
#include "lix/libstore/store-api.hh"
#include "lix/libstore/store-cast.hh"
@@ -24,9 +25,11 @@ bool dryRun = false;
static void removeOldGenerations(std::string dir, NeverAsync = {})
{
if (access(dir.c_str(), R_OK) != 0) return;
if (sys::access(dir, R_OK) != 0) {
return;
}
bool canWrite = access(dir.c_str(), W_OK) == 0;
bool canWrite = sys::access(dir, W_OK) == 0;
for (auto & i : readDirectory(dir)) {
checkInterrupt();
@@ -61,7 +64,7 @@ static int main_nix_collect_garbage(AsyncIoRoot & aio, std::string programName,
{
bool removeOld = false;
GCOptions options;
GCOptions options = {.action = GCOptions::gcDeleteDead};
LegacyArgs(aio, programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help")
@@ -72,12 +75,13 @@ static int main_nix_collect_garbage(AsyncIoRoot & aio, std::string programName,
else if (*arg == "--delete-older-than") {
removeOld = true;
deleteOlderThan = getArg(*arg, arg, end);
}
else if (*arg == "--dry-run") dryRun = true;
else if (*arg == "--max-freed")
} else if (*arg == "--dry-run") {
options.action = GCOptions::gcReturnDead;
} else if (*arg == "--max-freed") {
options.maxFreed = std::max(getIntArg<int64_t>(*arg, arg, end, true), (int64_t) 0);
else
} else {
return false;
}
return true;
}).parseCmdline(argv);
@@ -89,24 +93,12 @@ static int main_nix_collect_garbage(AsyncIoRoot & aio, std::string programName,
}
// Run the actual garbage collector.
if (!dryRun) {
options.action = GCOptions::gcDeleteDead;
} else {
options.action = GCOptions::gcReturnDead;
}
auto store = aio.blockOn(openStore());
auto & gcStore = require<GcStore>(*store);
GCResults results;
PrintFreed freed(true, results);
PrintFreed freed(options.action, results);
aio.blockOn(gcStore.collectGarbage(options, results));
if (dryRun) {
// Only print results for dry run; when !dryRun, paths will be printed as they're deleted.
for (auto & i : results.paths) {
printInfo("%s", i);
}
}
return 0;
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ static int main_nix_copy_closure(AsyncIoRoot & aio, std::string programName, Str
printVersion("nix-copy-closure");
else if (*arg == "--gzip" || *arg == "--bzip2" || *arg == "--xz") {
if (*arg != "--gzip")
warn("'%1%' is not implemented, falling back to gzip", *arg);
printTaggedWarning("'%1%' is not implemented, falling back to gzip", *arg);
gzip = true;
} else if (*arg == "--from")
toMode = false;
+274 -221
View File
@@ -1,6 +1,7 @@
#include "lix/libcmd/cmd-profiles.hh"
#include "lix/libexpr/attr-path.hh"
#include "lix/libcmd/common-eval-args.hh"
#include "lix/libexpr/value.hh"
#include "lix/libstore/derivations.hh"
#include "lix/libutil/terminal.hh"
#include "lix/libexpr/eval.hh"
@@ -150,11 +151,11 @@ static void getAllExprs(Evaluator & state,
continue;
}
/* Load the expression on demand. */
auto vArg = state.mem.allocValue();
vArg->mkString(path2.canonical().abs());
Value vArg = {NewValueAs::string, path2.canonical().abs()};
if (seen.size() == maxAttrs)
throw Error("too many Nix expressions in directory '%1%'", path);
attrs.alloc(attrName).mkApp(&state.builtins.get("import"), vArg);
attrs.alloc(attrName
) = {NewValueAs::app, state.mem, state.builtins.get("import"), vArg};
}
else if (st.type == InputAccessor::tDirectory)
/* `path2' is a directory (with no default.nix in it);
@@ -163,15 +164,13 @@ static void getAllExprs(Evaluator & state,
}
}
static void loadSourceExpr(EvalState & state, const SourcePath & path_, Value & v)
static Value loadSourceExpr(EvalState & state, const SourcePath & path_)
{
auto path = state.ctx.paths.checkSourcePath(path_);
auto st = path.stat();
if (isNixExpr(state.ctx.paths, path, st))
state.evalFile(path, v);
return state.evalFile(path);
/* The path is a directory. Put the Nix expressions in the
directory in a set, with the file name of each expression as
@@ -181,10 +180,10 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path_, Value &
directory). */
else if (st.type == InputAccessor::tDirectory) {
auto attrs = state.ctx.buildBindings(maxAttrs);
attrs.alloc("_combineChannels").mkList(0);
attrs.alloc("_combineChannels") = Value::EMPTY_LIST;
StringSet seen;
getAllExprs(state.ctx, path, seen, attrs);
v.mkAttrs(attrs);
return {NewValueAs::attrs, attrs};
}
else throw Error("path '%s' is not a directory or a Nix expression", path);
@@ -195,10 +194,9 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
std::string systemFilter, Bindings & autoArgs,
const std::string & pathPrefix, DrvInfos & elems)
{
Value vRoot;
loadSourceExpr(state, nixExprPath, vRoot);
Value vRoot = loadSourceExpr(state, nixExprPath);
Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, pathPrefix, autoArgs, vRoot).first);
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
@@ -317,9 +315,9 @@ std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches)
matches.clear();
for (auto & [name, match] : newest) {
if (multiple.find(name) != multiple.end())
warn(
"there are multiple derivations named '%1%'; using the first one",
name);
printTaggedWarning(
"there are multiple derivations named '%1%'; using the first one", name
);
matches.push_back(match);
}
@@ -418,14 +416,12 @@ static void queryInstSources(EvalState & state,
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
case srcNixExprs: {
Value vArg;
loadSourceExpr(state, *instSource.nixExprPath, vArg);
Value vArg = loadSourceExpr(state, *instSource.nixExprPath);
for (auto & i : args) {
Expr & eFun = state.ctx.parseExprFromString(i, CanonPath::fromCwd());
Value vFun, vTmp;
state.eval(eFun, vFun);
vTmp.mkApp(&vFun, &vArg);
Value vFun = state.eval(eFun);
Value vTmp = {NewValueAs::app, state.ctx.mem, vFun, vArg};
getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true);
}
@@ -477,10 +473,9 @@ static void queryInstSources(EvalState & state,
}
case srcAttrPath: {
Value vRoot;
loadSourceExpr(state, *instSource.nixExprPath, vRoot);
Value vRoot = loadSourceExpr(state, *instSource.nixExprPath);
for (auto & i : args) {
Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first);
getDerivations(state, v, "", *instSource.autoArgs, elems, true);
}
break;
@@ -515,8 +510,7 @@ static bool keep(EvalState & state, DrvInfo & drv)
static void setMetaFlag(EvalState & state, DrvInfo & drv,
const std::string & name, const std::string & value)
{
auto v = state.ctx.mem.allocValue();
v->mkString(value);
Value v = {NewValueAs::string, value};
drv.setMeta(state, name, v);
}
@@ -686,8 +680,12 @@ static void upgradeDerivations(Globals & globals,
{
const char * action = compareVersions(drvName.version, bestVersion) <= 0
? "upgrading" : "downgrading";
printInfo("%1% '%2%' to '%3%'",
action, i.queryName(*state), bestElem->queryName(*state));
printInfo(
"%1% '%2%' to '%3%'",
Uncolored(action),
i.queryName(*state),
bestElem->queryName(*state)
);
newElems.push_back(*bestElem);
} else newElems.push_back(i);
@@ -845,7 +843,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
);
}
if (split == workingElems.end())
warn("selector '%s' matched no installed derivations", selector);
printTaggedWarning("selector '%s' matched no installed derivations", selector);
for (auto removedElem = split; removedElem != workingElems.end(); removedElem++) {
printInfo("uninstalling '%s'", removedElem->queryName(*state));
}
@@ -886,8 +884,7 @@ static bool cmpElemByName(EvalState & state, DrvInfo & a, DrvInfo & b)
typedef std::list<Strings> Table;
void printTable(Table & table)
std::string formatTable(Table & table)
{
auto nrColumns = table.size() > 0 ? table.front().size() : 0;
@@ -902,18 +899,22 @@ void printTable(Table & table)
if (j->size() > widths[column]) widths[column] = j->size();
}
std::stringstream result;
for (auto & i : table) {
Strings::iterator j;
size_t column;
for (j = i.begin(), column = 0; j != i.end(); ++j, ++column) {
std::string s = *j;
replace(s.begin(), s.end(), '\n', ' ');
cout << s;
result << s;
if (column < nrColumns - 1)
cout << std::string(widths[column] - s.size() + 2, ' ');
result << std::string(widths[column] - s.size() + 2, ' ');
}
cout << std::endl;
result << std::endl;
}
return result.str();
}
@@ -1124,205 +1125,250 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
return;
}
RunPager pager;
withPager([&](Pager & pager) {
Table table;
std::ostringstream xmlStream;
XMLWriter xml(true, xmlStream);
xml.openElement("items");
Table table;
std::ostringstream dummy;
XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
XMLOpenElement xmlRoot(xml, "items");
for (auto & i : elems) {
try {
if (i.hasFailed()) continue;
//Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
if (globals.prebuiltOnly &&
!validPaths.count(i.queryOutPath(*state)) &&
!substitutablePaths.count(i.queryOutPath(*state)))
continue;
/* For table output. */
Strings columns;
/* For XML output. */
XMLAttrs attrs;
if (printStatus) {
auto outPath = i.queryOutPath(*state);
bool hasSubs = substitutablePaths.count(outPath);
bool isInstalled = installed.count(outPath);
bool isValid = validPaths.count(outPath);
if (xmlOutput) {
attrs["installed"] = isInstalled ? "1" : "0";
attrs["valid"] = isValid ? "1" : "0";
attrs["substitutable"] = hasSubs ? "1" : "0";
} else
columns.push_back(
(std::string) (isInstalled ? "I" : "-")
+ (isValid ? "P" : "-")
+ (hasSubs ? "S" : "-"));
}
if (xmlOutput)
attrs["attrPath"] = i.attrPath;
else if (printAttrPath)
columns.push_back(i.attrPath);
if (xmlOutput) {
auto drvName = DrvName(i.queryName(*state));
attrs["name"] = drvName.fullName;
attrs["pname"] = drvName.name;
attrs["version"] = drvName.version;
} else if (printName) {
columns.push_back(i.queryName(*state));
}
if (compareVersions) {
/* Compare this element against the versions of the
same named packages in either the set of available
elements, or the set of installed elements. !!!
This is O(N * M), should be O(N * lg M). */
std::string version;
VersionDiff diff = compareVersionAgainstSet(*state, i, otherElems, version);
char ch;
switch (diff) {
case cvLess: ch = '>'; break;
case cvEqual: ch = '='; break;
case cvGreater: ch = '<'; break;
case cvUnavail: ch = '-'; break;
default: abort();
for (auto & i : elems) {
try {
if (i.hasFailed()) {
continue;
}
if (xmlOutput) {
if (diff != cvUnavail) {
attrs["versionDiff"] = ch;
attrs["maxComparedVersion"] = version;
// Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
if (globals.prebuiltOnly && !validPaths.count(i.queryOutPath(*state))
&& !substitutablePaths.count(i.queryOutPath(*state)))
{
continue;
}
/* For table output. */
Strings columns;
/* For XML output. */
XMLAttrs attrs;
if (printStatus) {
auto outPath = i.queryOutPath(*state);
bool hasSubs = substitutablePaths.count(outPath);
bool isInstalled = installed.count(outPath);
bool isValid = validPaths.count(outPath);
if (xmlOutput) {
attrs["installed"] = isInstalled ? "1" : "0";
attrs["valid"] = isValid ? "1" : "0";
attrs["substitutable"] = hasSubs ? "1" : "0";
} else {
columns.push_back(
(std::string) (isInstalled ? "I" : "-") + (isValid ? "P" : "-")
+ (hasSubs ? "S" : "-")
);
}
} else {
auto column = (std::string) "" + ch + " " + version;
if (diff == cvGreater && shouldANSI(StandardOutputStream::Stdout))
column = ANSI_RED + column + ANSI_NORMAL;
columns.push_back(column);
}
}
if (xmlOutput) {
if (i.querySystem(*state) != "") attrs["system"] = i.querySystem(*state);
}
else if (printSystem)
columns.push_back(i.querySystem(*state));
if (printDrvPath) {
auto drvPath = i.queryDrvPath(*state);
if (xmlOutput) {
if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
} else
columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-");
}
if (xmlOutput)
attrs["outputName"] = i.queryOutputName(*state);
if (printOutPath && !xmlOutput) {
DrvInfo::Outputs outputs = i.queryOutputs(*state);
std::string s;
for (auto & j : outputs) {
if (!s.empty()) s += ';';
if (j.first != "out") { s += j.first; s += "="; }
s += store.printStorePath(*j.second);
attrs["attrPath"] = i.attrPath;
} else if (printAttrPath) {
columns.push_back(i.attrPath);
}
columns.push_back(s);
}
if (printDescription) {
auto descr = i.queryMetaString(*state, "description");
if (xmlOutput) {
if (descr != "") attrs["description"] = descr;
} else
columns.push_back(descr);
}
if (xmlOutput) {
XMLOpenElement item(xml, "item", attrs);
DrvInfo::Outputs outputs = i.queryOutputs(*state, printOutPath);
for (auto & j : outputs) {
XMLAttrs attrs2;
attrs2["name"] = j.first;
if (j.second)
attrs2["path"] = store.printStorePath(*j.second);
xml.writeEmptyElement("output", attrs2);
auto drvName = DrvName(i.queryName(*state));
attrs["name"] = drvName.fullName;
attrs["pname"] = drvName.name;
attrs["version"] = drvName.version;
} else if (printName) {
columns.push_back(i.queryName(*state));
}
if (printMeta) {
StringSet metaNames = i.queryMetaNames(*state);
for (auto & j : metaNames) {
if (compareVersions) {
/* Compare this element against the versions of the
same named packages in either the set of available
elements, or the set of installed elements. !!!
This is O(N * M), should be O(N * lg M). */
std::string version;
VersionDiff diff = compareVersionAgainstSet(*state, i, otherElems, version);
char ch;
switch (diff) {
case cvLess:
ch = '>';
break;
case cvEqual:
ch = '=';
break;
case cvGreater:
ch = '<';
break;
case cvUnavail:
ch = '-';
break;
default:
abort();
}
if (xmlOutput) {
if (diff != cvUnavail) {
attrs["versionDiff"] = ch;
attrs["maxComparedVersion"] = version;
}
} else {
auto column = (std::string) "" + ch + " " + version;
if (diff == cvGreater && shouldANSI(StandardOutputStream::Stdout)) {
column = ANSI_RED + column + ANSI_NORMAL;
}
columns.push_back(column);
}
}
if (xmlOutput) {
if (i.querySystem(*state) != "") {
attrs["system"] = i.querySystem(*state);
}
} else if (printSystem) {
columns.push_back(i.querySystem(*state));
}
if (printDrvPath) {
auto drvPath = i.queryDrvPath(*state);
if (xmlOutput) {
if (drvPath) {
attrs["drvPath"] = store.printStorePath(*drvPath);
}
} else {
columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-");
}
}
if (xmlOutput) {
attrs["outputName"] = i.queryOutputName(*state);
}
if (printOutPath && !xmlOutput) {
DrvInfo::Outputs outputs = i.queryOutputs(*state);
std::string s;
for (auto & j : outputs) {
if (!s.empty()) {
s += ';';
}
if (j.first != "out") {
s += j.first;
s += "=";
}
s += store.printStorePath(*j.second);
}
columns.push_back(s);
}
if (printDescription) {
auto descr = i.queryMetaString(*state, "description");
if (xmlOutput) {
if (descr != "") {
attrs["description"] = descr;
}
} else {
columns.push_back(descr);
}
}
if (xmlOutput) {
XMLOpenElement item(xml, "item", attrs);
DrvInfo::Outputs outputs = i.queryOutputs(*state, printOutPath);
for (auto & j : outputs) {
XMLAttrs attrs2;
attrs2["name"] = j;
Value * v = i.queryMeta(*state, j);
if (!v)
printError(
"derivation '%s' has invalid meta attribute '%s'",
i.queryName(*state), j);
else {
if (v->type() == nString) {
attrs2["type"] = "string";
attrs2["value"] = v->string.s;
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nInt) {
attrs2["type"] = "int";
attrs2["value"] = fmt("%1%", v->integer);
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nFloat) {
attrs2["type"] = "float";
attrs2["value"] = fmt("%1%", v->fpoint);
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nBool) {
attrs2["type"] = "bool";
attrs2["value"] = v->boolean ? "true" : "false";
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nList) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
for (auto elem : v->listItems()) {
if (elem->type() != nString) continue;
XMLAttrs attrs3;
attrs3["value"] = elem->string.s;
xml.writeEmptyElement("string", attrs3);
attrs2["name"] = j.first;
if (j.second) {
attrs2["path"] = store.printStorePath(*j.second);
}
xml.writeEmptyElement("output", attrs2);
}
if (printMeta) {
StringSet metaNames = i.queryMetaNames(*state);
for (auto & j : metaNames) {
XMLAttrs attrs2;
attrs2["name"] = j;
Value * v = i.queryMeta(*state, j);
if (!v) {
printError(
"derivation '%s' has invalid meta attribute '%s'", i.queryName(*state), j
);
} else {
if (v->type() == nString) {
attrs2["type"] = "string";
attrs2["value"] = v->str();
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nInt) {
attrs2["type"] = "int";
attrs2["value"] = fmt("%1%", v->integer());
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nFloat) {
attrs2["type"] = "float";
attrs2["value"] = fmt("%1%", v->fpoint());
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nBool) {
attrs2["type"] = "bool";
attrs2["value"] = v->boolean() ? "true" : "false";
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nList) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
for (auto & elem : v->listItems()) {
if (elem.type() != nString) {
continue;
}
XMLAttrs attrs3;
attrs3["value"] = elem.str();
xml.writeEmptyElement("string", attrs3);
}
} else if (v->type() == nAttrs) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
Bindings & attrs = *v->attrs();
for (auto & i : attrs) {
const Attr & a(*attrs.get(i.name));
if (a.value.type() != nString) {
continue;
}
XMLAttrs attrs3;
attrs3["type"] = globals.state->symbols[i.name];
attrs3["value"] = a.value.str();
xml.writeEmptyElement("string", attrs3);
}
}
} else if (v->type() == nAttrs) {
attrs2["type"] = "strings";
XMLOpenElement m(xml, "meta", attrs2);
Bindings & attrs = *v->attrs;
for (auto &i : attrs) {
Attr & a(*attrs.find(i.name));
if(a.value->type() != nString) continue;
XMLAttrs attrs3;
attrs3["type"] = globals.state->symbols[i.name];
attrs3["value"] = a.value->string.s;
xml.writeEmptyElement("string", attrs3);
}
}
}
}
} else {
table.push_back(columns);
}
} else
table.push_back(columns);
cout.flush();
cout.flush();
} catch (AssertionError & e) {
printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName(*state));
} catch (Error & e) {
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName(*state));
throw;
} catch (AssertionError & e) {
printMsg(
lvlTalkative,
"skipping derivation named '%1%' which gives an assertion failure",
i.queryName(*state)
);
} catch (Error & e) {
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName(*state));
throw;
}
}
}
if (!xmlOutput) printTable(table);
// </items>
xml.closeElement();
if (!xmlOutput) {
pager << formatTable(table);
} else {
pager << xmlStream.str();
}
});
}
static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs)
{
if (opFlags.size() > 0)
@@ -1373,20 +1419,27 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs
auto [gens, curGen] = findGenerations(globals.profile);
RunPager pager;
for (auto & i : gens) {
tm t;
if (!localtime_r(&i.creationTime, &t)) throw Error("cannot convert time");
logger->cout("%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02| %||",
i.number,
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec,
i.number == curGen ? "(current)" : "");
}
withPager([&](Pager & pager) {
for (auto & i : gens) {
tm t;
if (!localtime_r(&i.creationTime, &t)) {
throw Error("cannot convert time");
}
pager << fmt(
"%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02| %||\n",
i.number,
t.tm_year + 1900,
t.tm_mon + 1,
t.tm_mday,
t.tm_hour,
t.tm_min,
t.tm_sec,
i.number == curGen ? "(current)" : ""
);
}
});
}
static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opArgs)
{
if (opFlags.size() > 0)
+3 -4
View File
@@ -34,11 +34,10 @@ void processExpr(EvalState & state, const Strings & attrPaths,
return;
}
Value vRoot;
state.eval(e, vRoot);
Value vRoot = state.eval(e);
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
Value v(findAlongAttrPath(state, i, autoArgs, vRoot).first);
state.forceValue(v, noPos);
NixStringContext context;
@@ -47,7 +46,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
if (autoArgs.empty())
vRes = v;
else
state.autoCallFunction(autoArgs, v, vRes, noPos);
vRes = state.autoCallFunction(autoArgs, v, noPos);
if (output == okRaw)
std::cout << *state.coerceToString(noPos, vRes, context, "while generating the nix-instantiate output", StringCoercionMode::Strict);
// We intentionally don't output a newline here. The default PS1 for Bash in NixOS starts with a newline
+160 -97
View File
@@ -17,11 +17,17 @@
#include "graphml.hh"
#include "lix/libcmd/legacy.hh"
#include "lix/libstore/path-with-outputs.hh"
#include "lix/libutil/serialise.hh"
#include "nix-store.hh"
#include <cstdint>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <ostream>
#include <ranges>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -85,6 +91,16 @@ try {
if (i == drv.outputs.end())
throw Error("derivation '%s' does not have an output named '%s'",
store2->printStorePath(path.path), j);
if (!outputPaths.contains(i->first)) {
throw Error(
"Possible SQLite database corruption: derivation '%s' output map contains only "
"outputs '{%s}', not '%s'\n"
"Note: derivation output maps are stored in the SQLite database.",
store2->printStorePath(path.path),
concatStringsSep(", ", std::views::keys(outputPaths)),
i->first
);
}
auto outPath = outputPaths.at(i->first);
auto retPath = store->printStorePath(outPath);
if (store2) {
@@ -274,6 +290,7 @@ try {
graph. Topological sorting is used to keep the tree relatively
flat. */
static void printTree(
std::ostream & ostream,
std::shared_ptr<Store> store,
AsyncIoRoot & aio,
const StorePath & path,
@@ -283,11 +300,11 @@ static void printTree(
)
{
if (!done.insert(path).second) {
cout << fmt("%s%s [...]\n", firstPad, store->printStorePath(path));
ostream << fmt("%s%s [...]\n", firstPad, store->printStorePath(path));
return;
}
cout << fmt("%s%s\n", firstPad, store->printStorePath(path));
ostream << fmt("%s%s\n", firstPad, store->printStorePath(path));
auto info = aio.blockOn(store->queryPathInfo(path));
@@ -301,6 +318,7 @@ static void printTree(
for (const auto &[n, i] : enumerate(sorted)) {
bool last = n + 1 == sorted.size();
printTree(
ostream,
store,
aio,
i,
@@ -359,17 +377,15 @@ opQuery(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
if (!query) query = qOutputs;
RunPager pager;
switch (*query) {
withPager([&](Pager & pager) {
switch (*query) {
case qOutputs: {
for (auto & i : opArgs) {
auto outputs = aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), true, forceRealise)
);
for (auto & outputPath : outputs)
cout << fmt("%1%\n", store->printStorePath(outputPath));
auto outputs =
aio.blockOn(maybeUseOutputs(store, store->followLinksToStorePath(i), true, forceRealise));
for (auto & outputPath : outputs) {
pager << fmt("%1%\n", store->printStorePath(outputPath));
}
}
break;
}
@@ -380,54 +396,55 @@ opQuery(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
case qReferrersClosure: {
StorePathSet paths;
for (auto & i : opArgs) {
auto ps = aio.blockOn(maybeUseOutputs(
store, store->followLinksToStorePath(i), useOutput, forceRealise
));
auto ps = aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), useOutput, forceRealise)
);
for (auto & j : ps) {
if (query == qRequisites) {
aio.blockOn(store->computeFSClosure(j, paths, false, includeOutputs));
}
else if (query == qReferences) {
for (auto & p : aio.blockOn(store->queryPathInfo(j))->references)
} else if (query == qReferences) {
for (auto & p : aio.blockOn(store->queryPathInfo(j))->references) {
paths.insert(p);
}
else if (query == qReferrers) {
}
} else if (query == qReferrers) {
StorePathSet tmp;
aio.blockOn(store->queryReferrers(j, tmp));
for (auto & i : tmp)
for (auto & i : tmp) {
paths.insert(i);
}
else if (query == qReferrersClosure)
}
} else if (query == qReferrersClosure) {
aio.blockOn(store->computeFSClosure(j, paths, true));
}
}
}
auto sorted = aio.blockOn(store->topoSortPaths(paths));
for (StorePaths::reverse_iterator i = sorted.rbegin();
i != sorted.rend(); ++i)
cout << fmt("%s\n", store->printStorePath(*i));
for (StorePaths::reverse_iterator i = sorted.rbegin(); i != sorted.rend(); ++i) {
pager << fmt("%s\n", store->printStorePath(*i));
}
break;
}
case qDeriver:
for (auto & i : opArgs) {
auto info = aio.blockOn(store->queryPathInfo(store->followLinksToStorePath(i)));
cout << fmt("%s\n", info->deriver ? store->printStorePath(*info->deriver) : "unknown-deriver");
pager << fmt(
"%s\n", info->deriver ? store->printStorePath(*info->deriver) : "unknown-deriver"
);
}
break;
case qValidDerivers: {
StorePathSet result;
for (auto & i : opArgs) {
auto derivers =
aio.blockOn(store->queryValidDerivers(store->followLinksToStorePath(i)));
auto derivers = aio.blockOn(store->queryValidDerivers(store->followLinksToStorePath(i)));
for (const auto & i : derivers) {
result.insert(i);
}
}
auto sorted = aio.blockOn(store->topoSortPaths(result));
for (StorePaths::reverse_iterator i = sorted.rbegin();
i != sorted.rend(); ++i)
cout << fmt("%s\n", store->printStorePath(*i));
for (StorePaths::reverse_iterator i = sorted.rbegin(); i != sorted.rend(); ++i) {
pager << fmt("%s\n", store->printStorePath(*i));
}
break;
}
@@ -436,95 +453,112 @@ opQuery(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
auto path = aio.blockOn(useDeriver(store, store->followLinksToStorePath(i)));
Derivation drv = aio.blockOn(store->derivationFromPath(path));
StringPairs::iterator j = drv.env.find(bindingName);
if (j == drv.env.end())
throw Error("derivation '%s' has no environment binding named '%s'",
store->printStorePath(path), bindingName);
cout << fmt("%s\n", j->second);
if (j == drv.env.end()) {
throw Error(
"derivation '%s' has no environment binding named '%s'",
store->printStorePath(path),
bindingName
);
}
pager << fmt("%s\n", j->second);
}
break;
case qHash:
case qSize:
for (auto & i : opArgs) {
for (auto & j : aio.blockOn(maybeUseOutputs(
store, store->followLinksToStorePath(i), useOutput, forceRealise
)))
for (auto & j : aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), useOutput, forceRealise)
))
{
auto info = aio.blockOn(store->queryPathInfo(j));
if (query == qHash) {
assert(info->narHash.type == HashType::SHA256);
cout << fmt("%s\n", info->narHash.to_string(Base::Base32, true));
} else if (query == qSize)
cout << fmt("%d\n", info->narSize);
pager << fmt("%s\n", info->narHash.to_string(HashFormat::Base32));
} else if (query == qSize) {
pager << fmt("%d\n", info->narSize);
}
}
}
break;
case qTree: {
StorePathSet done;
for (auto & i : opArgs)
printTree(store, aio, store->followLinksToStorePath(i), "", "", done);
for (auto & i : opArgs) {
std::stringstream tmp;
printTree(tmp, store, aio, store->followLinksToStorePath(i), "", "", done);
pager << tmp.str();
}
break;
}
case qGraph: {
StorePathSet roots;
for (auto & i : opArgs)
for (auto & j : aio.blockOn(maybeUseOutputs(
store, store->followLinksToStorePath(i), useOutput, forceRealise
)))
for (auto & i : opArgs) {
for (auto & j : aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), useOutput, forceRealise)
))
{
roots.insert(j);
}
aio.blockOn(printDotGraph(ref<Store>::unsafeFromPtr(store), std::move(roots)));
}
pager << aio.blockOn(formatDotGraph(ref<Store>::unsafeFromPtr(store), std::move(roots)));
break;
}
case qGraphML: {
StorePathSet roots;
for (auto & i : opArgs)
for (auto & j : aio.blockOn(maybeUseOutputs(
store, store->followLinksToStorePath(i), useOutput, forceRealise
)))
for (auto & i : opArgs) {
for (auto & j : aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), useOutput, forceRealise)
))
{
roots.insert(j);
}
aio.blockOn(printGraphML(ref<Store>::unsafeFromPtr(store), std::move(roots)));
}
pager << aio.blockOn(formatGraphML(ref<Store>::unsafeFromPtr(store), std::move(roots)));
break;
}
case qResolve: {
for (auto & i : opArgs)
cout << fmt("%s\n", store->printStorePath(store->followLinksToStorePath(i)));
for (auto & i : opArgs) {
pager << fmt("%s\n", store->printStorePath(store->followLinksToStorePath(i)));
}
break;
}
case qRoots: {
StorePathSet args;
for (auto & i : opArgs)
for (auto & p : aio.blockOn(maybeUseOutputs(
store, store->followLinksToStorePath(i), useOutput, forceRealise
)))
for (auto & i : opArgs) {
for (auto & p : aio.blockOn(
maybeUseOutputs(store, store->followLinksToStorePath(i), useOutput, forceRealise)
))
{
args.insert(p);
}
}
StorePathSet referrers;
aio.blockOn(store->computeFSClosure(
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations));
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations
));
auto & gcStore = require<GcStore>(*store);
Roots roots = aio.blockOn(gcStore.findRoots(false));
for (auto & [target, links] : roots)
if (referrers.find(target) != referrers.end())
for (auto & link : links)
cout << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target));
for (auto & [target, links] : roots) {
if (referrers.find(target) != referrers.end()) {
for (auto & link : links) {
pager << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target));
}
}
}
break;
}
default:
abort();
}
}
});
}
static void
@@ -560,15 +594,16 @@ opReadLog(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, Stri
auto & logStore = require<LogStore>(*store);
RunPager pager;
for (auto & i : opArgs) {
auto path = logStore.followLinksToStorePath(i);
auto log = aio.blockOn(logStore.getBuildLog(path));
if (!log)
throw Error("build log of derivation '%s' is not available", logStore.printStorePath(path));
std::cout << *log;
}
withPager([&](Pager & pager) {
for (auto & i : opArgs) {
auto path = logStore.followLinksToStorePath(i);
auto log = aio.blockOn(logStore.getBuildLog(path));
if (!log) {
throw Error("build log of derivation '%s' is not available", logStore.printStorePath(path));
}
pager << *log;
}
});
}
static void
@@ -697,12 +732,8 @@ static void opGC(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlag
}
else {
PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
PrintFreed freed(options.action, results);
aio.blockOn(gcStore.collectGarbage(options, results));
if (options.action != GCOptions::gcDeleteDead)
for (auto & i : results.paths)
cout << i << std::endl;
}
}
@@ -735,7 +766,7 @@ opDelete(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, Strin
auto & gcStore = require<GcStore>(*store);
GCResults results;
PrintFreed freed(true, results);
PrintFreed freed(options.action, results);
aio.blockOn(gcStore.collectGarbage(options, results));
}
@@ -823,7 +854,7 @@ opVerify(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, Strin
else throw UsageError("unknown flag '%1%'", i);
if (aio.blockOn(store->verifyStore(checkContents, repair))) {
warn("not all store errors were fixed");
printTaggedWarning("not all store errors were fixed");
throw Exit(1);
}
}
@@ -846,10 +877,12 @@ opVerifyPath(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, S
aio.blockOn(aio.blockOn(store->narFromPath(path))->drainInto(sink));
auto current = sink.finish();
if (current.first != info->narHash) {
printError("path '%s' was modified! expected hash '%s', got '%s'",
printError(
"path '%s' was modified! expected hash '%s', got '%s'",
store->printStorePath(path),
info->narHash.to_string(Base::SRI, true),
current.first.to_string(Base::SRI, true));
info->narHash.to_string(),
current.first.to_string()
);
status = 1;
}
}
@@ -896,11 +929,11 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
FdSink out(STDOUT_FILENO);
/* Exchange the greeting. */
unsigned int magic = readInt(in);
unsigned int magic = readNum<unsigned>(in);
if (magic != SERVE_MAGIC_1) throw Error("protocol mismatch");
out << SERVE_MAGIC_2 << SERVE_PROTOCOL_VERSION;
out.flush();
ServeProto::Version clientVersion = readInt(in);
ServeProto::Version clientVersion = readNum<unsigned>(in);
ServeProto::ReadConn rconn {
.from = in,
@@ -918,12 +951,12 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
verbosity = lvlError;
settings.keepLog.override(false);
settings.useSubstitutes.override(false);
settings.maxSilentTime.override(readInt(in));
settings.buildTimeout.override(readInt(in));
settings.maxSilentTime.override(readNum<unsigned>(in));
settings.buildTimeout.override(readNum<unsigned>(in));
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
settings.maxLogSize.override(readNum<unsigned long>(in));
if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
auto nrRepeats = readInt(in);
auto nrRepeats = readNum<unsigned>(in);
if (nrRepeats != 0) {
throw Error("client requested repeating builds, but this is not currently implemented");
}
@@ -933,19 +966,19 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
// `nrRepeats` in fact is 0, so we can safely ignore this
// without doing something other than what the client
// asked for.
readInt(in);
readNum<unsigned>(in);
settings.runDiffHook.override(true);
}
if (GET_PROTOCOL_MINOR(clientVersion) >= 7) {
settings.keepFailed.override((bool) readInt(in));
settings.keepFailed.override((bool) readNum<unsigned>(in));
}
};
while (true) {
ServeProto::Command cmd;
try {
cmd = (ServeProto::Command) readInt(in);
cmd = (ServeProto::Command) readNum<unsigned>(in);
} catch (EndOfFile & e) {
break;
}
@@ -953,8 +986,8 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
switch (cmd) {
case ServeProto::Command::QueryValidPaths: {
bool lock = readInt(in);
bool substitute = readInt(in);
bool lock = readNum<unsigned>(in);
bool substitute = readNum<unsigned>(in);
auto paths = ServeProto::Serialise<StorePathSet>::read(rconn);
if (lock && writeAllowed)
for (auto & path : paths)
@@ -997,7 +1030,7 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
}
case ServeProto::Command::ExportPaths: {
readInt(in); // obsolete
readNum<unsigned>(in); // obsolete
aio.blockOn(store->exportPaths(
ServeProto::Serialise<StorePathSet>::read(rconn), out
));
@@ -1043,7 +1076,7 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
}
case ServeProto::Command::QueryClosure: {
bool includeOutputs = readInt(in);
bool includeOutputs = readNum<unsigned>(in);
StorePathSet closure;
aio.blockOn(store->computeFSClosure(
ServeProto::Serialise<StorePathSet>::read(rconn),
@@ -1067,13 +1100,43 @@ opServe(std::shared_ptr<Store> store, AsyncIoRoot & aio, Strings opFlags, String
if (deriver != "")
info.deriver = store->parseStorePath(deriver);
info.references = ServeProto::Serialise<StorePathSet>::read(rconn);
in >> info.registrationTime >> info.narSize >> info.ultimate;
info.registrationTime = readNum<time_t>(in);
info.narSize = readNum<uint64_t>(in);
info.ultimate = readBool(in);
info.sigs = readStrings<StringSet>(in);
info.ca = ContentAddress::parseOpt(readString(in));
if (info.narSize == 0)
throw Error("narInfo is too old and missing the narSize field");
struct SizedSource : Source
{
Source & orig;
size_t remain;
SizedSource(Source & orig, size_t size) : orig(orig), remain(size) {}
size_t read(char * data, size_t len) override
{
if (this->remain <= 0) {
throw EndOfFile("sized: unexpected end-of-file");
}
len = std::min(len, this->remain);
size_t n = this->orig.read(data, len);
this->remain -= n;
return n;
}
size_t drainAll()
{
std::vector<char> buf(8192);
size_t sum = 0;
while (this->remain > 0) {
size_t n = read(buf.data(), buf.size());
sum += n;
}
return sum;
}
};
SizedSource sizedSource(in, info.narSize);
AsyncSourceInputStream stream{sizedSource};
+35 -28
View File
@@ -1,4 +1,5 @@
#include "user-env.hh"
#include "lix/libexpr/value.hh"
#include "lix/libstore/derivations.hh"
#include "lix/libstore/store-api.hh"
#include "lix/libstore/path-with-outputs.hh"
@@ -32,7 +33,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* Construct the whole top level derivation. */
StorePathSet references;
Value manifest = state.ctx.mem.newList(elems.size());
auto manifest = state.ctx.mem.newList(elems.size());
Value vManifest{NewValueAs::list, manifest};
size_t n = 0;
for (auto & i : elems) {
/* Create a pseudo-derivation containing the name, system,
@@ -44,23 +46,30 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
auto attrs = state.ctx.buildBindings(7 + outputs.size());
attrs.alloc(state.ctx.s.type).mkString("derivation");
attrs.alloc(state.ctx.s.name).mkString(i.queryName(state));
attrs.alloc(state.ctx.symbols.sym_type) = {NewValueAs::string, "derivation"};
attrs.alloc(state.ctx.symbols.sym_name) = {NewValueAs::string, i.queryName(state)};
auto system = i.querySystem(state);
if (!system.empty())
attrs.alloc(state.ctx.s.system).mkString(system);
attrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(i.queryOutPath(state)));
attrs.alloc(state.ctx.symbols.sym_system) = {NewValueAs::string, system};
attrs.alloc(state.ctx.symbols.sym_outPath) = {
NewValueAs::string, state.ctx.store->printStorePath(i.queryOutPath(state))
};
if (drvPath)
attrs.alloc(state.ctx.s.drvPath).mkString(state.ctx.store->printStorePath(*drvPath));
attrs.alloc(state.ctx.symbols.sym_drvPath) = {
NewValueAs::string, state.ctx.store->printStorePath(*drvPath)
};
// Copy each output meant for installation.
auto & vOutputs = attrs.alloc(state.ctx.s.outputs);
vOutputs = state.ctx.mem.newList(outputs.size());
auto & vOutputs = attrs.alloc(state.ctx.symbols.sym_outputs);
auto outputsList = state.ctx.mem.newList(outputs.size());
vOutputs = {NewValueAs::list, outputsList};
for (const auto & [m, j] : enumerate(outputs)) {
(vOutputs.listElems()[m] = state.ctx.mem.allocValue())->mkString(j.first);
outputsList->elems[m] = {NewValueAs::string, j.first};
auto outputAttrs = state.ctx.buildBindings(2);
outputAttrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(*j.second));
attrs.alloc(j.first).mkAttrs(outputAttrs);
outputAttrs.alloc(state.ctx.symbols.sym_outPath) = {
NewValueAs::string, state.ctx.store->printStorePath(*j.second)
};
attrs.alloc(j.first) = {NewValueAs::attrs, outputAttrs};
/* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */
@@ -75,12 +84,12 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
for (auto & j : metaNames) {
Value * v = i.queryMeta(state, j);
if (!v) continue;
meta.insert(state.ctx.symbols.create(j), v);
meta.insert(state.ctx.symbols.create(j), *v);
}
attrs.alloc(state.ctx.s.meta).mkAttrs(meta);
attrs.alloc(state.ctx.symbols.sym_meta) = {NewValueAs::attrs, meta};
(manifest.listElems()[n++] = state.ctx.mem.allocValue())->mkAttrs(attrs);
manifest->elems[n++] = {NewValueAs::attrs, attrs};
if (drvPath) references.insert(*drvPath);
}
@@ -89,35 +98,33 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
the store; we need it for future modifications of the
environment. */
std::ostringstream str;
printAmbiguous(manifest, state.ctx.symbols, str, nullptr, std::numeric_limits<int>::max());
printAmbiguous(vManifest, state.ctx.symbols, str, nullptr, std::numeric_limits<int>::max());
auto manifestFile = state.aio.blockOn(state.ctx.store->addTextToStore("env-manifest.nix",
str.str(), references));
/* Get the environment builder expression. */
Value envBuilder;
state.eval(state.ctx.parseExprFromString(
#include "buildenv.nix.gen.hh"
, CanonPath::root), envBuilder);
Value envBuilder = state.eval(state.ctx.parseExprFromString(
#include "buildenv.nix.gen.hh"
, CanonPath::root
));
/* Construct a Nix expression that calls the user environment
builder with the manifest as argument. */
auto attrs = state.ctx.buildBindings(3);
state.ctx.paths.mkStorePathString(manifestFile, attrs.alloc("manifest"));
attrs.insert(state.ctx.symbols.create("derivations"), &manifest);
Value args;
args.mkAttrs(attrs);
attrs.insert(state.ctx.symbols.create("derivations"), vManifest);
Value args = {NewValueAs::attrs, attrs};
Value topLevel;
topLevel.mkApp(&envBuilder, &args);
Value topLevel{NewValueAs::app, state.ctx.mem, envBuilder, args};
/* Evaluate it. */
debug("evaluating user environment builder");
state.forceValue(topLevel, noPos);
NixStringContext context;
Attr & aDrvPath(*topLevel.attrs->find(state.ctx.s.drvPath));
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
Attr & aOutPath(*topLevel.attrs->find(state.ctx.s.outPath));
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
const Attr & aDrvPath(*topLevel.attrs()->get(state.ctx.symbols.sym_drvPath));
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, aDrvPath.value, context, "");
const Attr & aOutPath(*topLevel.attrs()->get(state.ctx.symbols.sym_outPath));
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, aOutPath.value, context, "");
/* Realise the resulting store expression. */
debug("building user environment");
+5 -2
View File
@@ -20,8 +20,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
throw Error("profile '%s' is incompatible with 'nix-env'; please use 'nix profile' instead", userEnv);
auto manifestFile = userEnv + "/manifest.nix";
if (pathExists(manifestFile)) {
Value v;
state.evalFile(CanonPath(manifestFile), v);
Value v = state.evalFile(CanonPath(manifestFile));
Bindings & bindings(*state.ctx.mem.allocBindings(0));
getDerivations(state, v, "", bindings, elems, false);
}
@@ -99,6 +98,10 @@ void ProfileElement::updateStorePaths(
for (auto & output : bfd.outputs) {
storePaths.insert(output.second);
}
if (settings.envKeepDerivations) {
storePaths.insert(bfd.drvPath.path);
}
},
},
buildable.raw()
+24 -12
View File
@@ -4,6 +4,9 @@
#include "lix/libstore/derivations.hh"
#include "lix/libstore/profiles.hh"
#include "lix/libcmd/repl.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/c-calls.hh"
#include "lix/libutil/error.hh"
extern char * * environ __attribute__((weak));
@@ -39,14 +42,15 @@ StoreCommand::StoreCommand()
ref<Store> StoreCommand::getStore()
{
if (!_store)
_store = createStore();
if (!_store) {
_store = createStore(aio());
}
return *_store;
}
ref<Store> StoreCommand::createStore()
ref<Store> StoreCommand::createStore(AsyncIoRoot & in)
{
return aio().blockOn(openStore());
return in.blockOn(openStore());
}
void StoreCommand::run()
@@ -71,16 +75,22 @@ CopyCommand::CopyCommand()
});
}
ref<Store> CopyCommand::createStore()
void CopyCommand::run()
{
return srcUri.empty() ? StoreCommand::createStore() : aio().blockOn(openStore(srcUri));
if (requireStore && srcUri.empty() && dstUri.empty()) {
throw UsageError("you must pass '--from' and/or '--to'");
}
StoreCommand::run();
}
ref<Store> CopyCommand::createStore(AsyncIoRoot & in)
{
return srcUri.empty() ? StoreCommand::createStore(in) : in.blockOn(openStore(srcUri));
}
ref<Store> CopyCommand::getDstStore()
{
if (srcUri.empty() && dstUri.empty())
throw UsageError("you must pass '--from' and/or '--to'");
return aio().blockOn(dstUri.empty() ? openStore() : openStore(dstUri));
}
@@ -301,8 +311,10 @@ void MixEnvironment::setEnviron() {
throw UsageError("--unset does not make sense with --ignore-environment");
for (const auto & var : keep) {
auto val = getenv(var.c_str());
if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
auto val = sys::getenv(var);
if (val) {
stringsEnv.emplace_back(fmt("%s=%s", var, val));
}
}
vectorEnv = stringsToCharPtrs(stringsEnv);
@@ -312,7 +324,7 @@ void MixEnvironment::setEnviron() {
throw UsageError("--keep does not make sense without --ignore-environment");
for (const auto & var : unset)
unsetenv(var.c_str());
(void) sys::unsetenv(var);
}
}
+6 -8
View File
@@ -15,8 +15,6 @@ namespace nix {
extern std::string programPath;
extern char * * savedArgv;
class EvalState;
struct Pos;
class Store;
@@ -39,7 +37,7 @@ struct StoreCommand : virtual Command
StoreCommand();
void run() override;
ref<Store> getStore();
virtual ref<Store> createStore();
virtual ref<Store> createStore(AsyncIoRoot & in);
/**
* Main entry point, with a `Store` provided
*/
@@ -56,10 +54,12 @@ private:
struct CopyCommand : virtual StoreCommand
{
std::string srcUri, dstUri;
bool requireStore = true;
CopyCommand();
ref<Store> createStore() override;
void run() override;
ref<Store> createStore(AsyncIoRoot & in) override;
ref<Store> getDstStore();
};
@@ -171,7 +171,7 @@ struct RawInstallablesCommand : virtual Args, SourceExprCommand
std::vector<FlakeRef> getFlakeRefsForCompletion() override;
private:
protected:
std::vector<std::string> rawInstallables;
};
@@ -220,13 +220,11 @@ struct MixOperateOnOptions : virtual Args
*/
struct BuiltPathsCommand : InstallablesCommand, virtual MixOperateOnOptions
{
private:
protected:
bool recursive = false;
bool all = false;
protected:
Realise realiseMode = Realise::Derivation;
public:
+4 -6
View File
@@ -113,7 +113,7 @@ MixEvalArgs::MixEvalArgs()
```
-I nixpkgs=channel:nixos-21.05
-I nixpkgs=https://nixos.org/channels/nixos-21.05/nixexprs.tar.xz
-I nixpkgs=https://channels.nixos.org/nixos-21.05/nixexprs.tar.xz
```
You can also fetch source trees using [flake URLs](./nix3-flake.md#url-like-syntax) and add them to the
@@ -183,13 +183,11 @@ Bindings * MixEvalArgs::getAutoArgs(Evaluator & state)
{
auto res = state.buildBindings(autoArgs.size());
for (auto & i : autoArgs) {
auto v = state.mem.allocValue();
Value v;
if (i.second[0] == 'E')
state.evalLazily(
state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), *v
);
v = state.evalLazily(state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()));
else
v->mkString(((std::string_view) i.second).substr(1));
v = {NewValueAs::string, ((std::string_view) i.second).substr(1)};
res.insert(state.symbols.create(i.first), v);
}
return res.finish();
+76
View File
@@ -0,0 +1,76 @@
#pragma once
///@file
#include <string_view>
#include <type_traits>
#include <utility>
#include <optional>
#include <ranges>
#include "lix/libutil/args.hh"
namespace nix::cli {
template<typename Enum>
struct enum_cli_traits;
template<typename Enum>
constexpr std::string_view toString(Enum value)
{
for (const auto & [name, val] : enum_cli_traits<Enum>::values) {
if (val == value) {
return name;
}
}
std::terminate();
}
template<typename Enum>
std::optional<Enum> fromString(std::string_view str)
{
for (const auto & [name, val] : enum_cli_traits<Enum>::values) {
if (name == str) {
return val;
}
}
return std::nullopt;
}
template<typename Enum>
void completeAmongEnumChoices(AddCompletions & completions, size_t, std::string_view prefix)
{
for (const auto & [name, _] : enum_cli_traits<Enum>::values) {
if (name.starts_with(prefix)) {
completions.add(name);
}
}
}
template<typename Enum>
Enum parseEnumArg(std::string text)
{
auto valueOpt = fromString<Enum>(text);
if (valueOpt) {
return *valueOpt;
} else {
auto names = std::ranges::views::keys(enum_cli_traits<Enum>::values)
| std::ranges::to<std::set<std::string>>();
auto suggestions = Suggestions::bestMatches(names, text);
throw UsageError(suggestions, "'%s' is not a recognised '%s'", text, enum_cli_traits<Enum>::typeName);
}
}
template<typename Enum>
std::optional<Enum> parseOptionalEnumArg(std::string text)
{
auto target = fromString<Enum>(text);
if (!target && text != "") {
auto names = std::ranges::views::keys(enum_cli_traits<Enum>::values) | std::ranges::to<std::set>();
auto suggestions = Suggestions::bestMatches(names, text);
throw UsageError(suggestions, "'%s' is not a recognised '%s'", text, enum_cli_traits<Enum>::typeName);
}
return target;
}
}
+11 -9
View File
@@ -12,9 +12,10 @@ namespace nix {
InstallableAttrPath::InstallableAttrPath(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec)
ExtendedOutputsSpec extendedOutputsSpec
)
: InstallableValue(state)
, cmd(cmd)
, v(allocRootValue(v))
@@ -22,10 +23,10 @@ InstallableAttrPath::InstallableAttrPath(
, extendedOutputsSpec(std::move(extendedOutputsSpec))
{ }
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
std::pair<Value, PosIdx> InstallableAttrPath::toValue(EvalState & state)
{
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(*evaluator), **v);
state.forceValue(*vRes, pos);
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(*evaluator), *v);
state.forceValue(vRes, pos);
return {vRes, pos};
}
@@ -34,7 +35,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
auto [v, pos] = toValue(state);
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
state, *v, pos, fmt("while evaluating the attribute '%s'", attrPath)
state, v, pos, fmt("while evaluating the attribute '%s'", attrPath)
))
{
return { *derivedPathWithInfo };
@@ -43,7 +44,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
Bindings & autoArgs = *cmd.getAutoArgs(*evaluator);
DrvInfos drvInfos;
getDerivations(state, *v, "", autoArgs, drvInfos, false);
getDerivations(state, v, "", autoArgs, drvInfos, false);
// Backward compatibility hack: group results by drvPath. This
// helps keep .all output together.
@@ -92,9 +93,10 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
InstallableAttrPath InstallableAttrPath::parse(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec)
ExtendedOutputsSpec extendedOutputsSpec
)
{
return {
state, cmd, v,
+7 -5
View File
@@ -20,13 +20,14 @@ class InstallableAttrPath : public InstallableValue
InstallableAttrPath(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec);
ExtendedOutputsSpec extendedOutputsSpec
);
std::string what() const override { return attrPath; };
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
std::pair<Value, PosIdx> toValue(EvalState & state) override;
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
@@ -35,9 +36,10 @@ public:
static InstallableAttrPath parse(
ref<eval_cache::CachingEvaluator> state,
SourceExprCommand & cmd,
Value * v,
Value & v,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec);
ExtendedOutputsSpec extendedOutputsSpec
);
};
}
+19 -27
View File
@@ -26,35 +26,27 @@ InstallableDerivedPath InstallableDerivedPath::parse(
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec)
{
auto derivedPath = std::visit(overloaded {
// If the user did not use ^, we treat the output more
// liberally: we accept a symlink chain or an actual
// store path.
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
auto storePath = store->followLinksToStorePath(prefix);
// Remove this prior to stabilizing the new CLI.
if (storePath.isDerivation()) {
auto oldDerivedPath = DerivedPath::Built {
.drvPath = makeConstantStorePath(storePath),
.outputs = OutputsSpec::All { },
auto derivedPath = std::visit(
overloaded{
// If the user did not use ^, we treat the output more
// liberally: we accept a symlink chain or an actual
// store path.
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
return DerivedPath::Opaque{
.path = store->followLinksToStorePath(prefix),
};
warn(
"The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '%s'",
oldDerivedPath.to_string(*store));
};
return DerivedPath::Opaque {
.path = std::move(storePath),
};
},
// If the user did use ^, we just do exactly what is written.
[&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
auto drv = DerivedPathOpaque::parse(*store, prefix);
return DerivedPath::Built{
.drvPath = std::move(drv),
.outputs = outputSpec,
};
},
},
// If the user did use ^, we just do exactly what is written.
[&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
auto drv = DerivedPathOpaque::parse(*store, prefix);
return DerivedPath::Built {
.drvPath = std::move(drv),
.outputs = outputSpec,
};
},
}, extendedOutputsSpec.raw);
extendedOutputsSpec.raw
);
return InstallableDerivedPath {
store,
std::move(derivedPath),
+4 -5
View File
@@ -7,8 +7,6 @@
#include "lix/libexpr/flake/flake.hh"
#include "lix/libexpr/eval-cache.hh"
#include <nlohmann/json.hpp>
namespace nix {
std::vector<std::string> InstallableFlake::getActualAttrPaths()
@@ -60,7 +58,8 @@ InstallableFlake::InstallableFlake(
DerivedPathsWithInfo InstallableFlake::toDerivedPaths(EvalState & state)
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
auto act =
logger->startActivity(lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
auto attr = getCursor(state);
@@ -136,9 +135,9 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths(EvalState & state)
}};
}
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
std::pair<Value, PosIdx> InstallableFlake::toValue(EvalState & state)
{
return {&getCursor(state)->forceValue(state), noPos};
return {getCursor(state)->forceValue(state), noPos};
}
std::vector<ref<eval_cache::AttrCursor>>

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