Compare commits

...

173 Commits

Author SHA1 Message Date
Sergei Zimmerman
43c713155a Merge pull request #15263 from obsidiansystems/backport-15252-to-2.29-maintenance
[Backport 2.29-maintenance] upload-release: disable containerd image store to preserve gzip layer compression
2026-02-17 02:18:53 +03:00
Amaan Qureshi
6f49cf9c99 upload-release: disable containerd image store to preserve gzip layer compression
(cherry picked from commit 2ccb8a9a56)
2026-02-16 17:52:28 -05:00
internal-nix-ci[bot]
74651a4ef0 Merge pull request #15063 from NixOS/backport-15062-to-2.29-maintenance
[Backport 2.29-maintenance] ci: Drop magic-nix-cache
2026-01-23 01:02:18 +00:00
Sergei Zimmerman
0efca3705b ci: Drop magic-nix-cache
We are now seeing. I guess we are out with the cache. When the API responds with 418 (I'm a teapot)
it seems like the only reasonable solution is to oblige.

error: unable to download 'http://127.0.0.1:37515/7ms9f25xyxavf32pvdc3vb28nzzmkbn3.narinfo': HTTP error 418
       response body:
       GitHub API error: GitHub Actions Cache throttled Magic Nix Cache. Not trying to use it again on this run.
(cherry picked from commit dae41e06e8)
2026-01-23 00:35:09 +00:00
internal-nix-ci[bot]
3b0c593c03 Merge pull request #15032 from NixOS/backport-15031-to-2.29-maintenance
[Backport 2.29-maintenance] ci: Bump magic-nix-cache to disable on 429
2026-01-21 05:16:31 +00:00
Sergei Zimmerman
a86c9ee229 ci: Bump magic-nix-cache to disable on 429
(cherry picked from commit 1555677cd5)
2026-01-21 04:50:03 +00:00
internal-nix-ci[bot]
e5a8eaae25 Merge pull request #14939 from NixOS/backport-14778-to-2.29-maintenance
[Backport 2.29-maintenance] test: add shebangs to shell.nix test scripts
2026-01-07 14:20:38 +00:00
Agustín Covarrubias
2dfc828f37 test: add shebangs to shell.nix test scripts
Fix intermittent SIGSEGV (exit code 139) on macOS when running
  nix-shell and shebang tests inside the nix sandbox.

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

  Potentially closes: #13106

(cherry picked from commit 7b3d7eb634)
2026-01-07 13:50:10 +00:00
internal-nix-ci[bot]
32d8030fe7 Merge pull request #14904 from NixOS/backport-14903-to-2.29-maintenance
[Backport 2.29-maintenance] upload-release.pl: Fix up nix-channels bucket location, use awscli2
2026-01-01 21:25:38 +00:00
Sergei Zimmerman
7055ed76a1 upload-release.pl: Fix up nix-channels bucket location, use awscli2
I messed up and accidentally configured the S3 client to use the same
host as the nix-releases bucket, but nix-channels is us-east-1 and
nix-releases is eu-west-1.

(cherry picked from commit 0900638f1d)
2026-01-01 21:17:39 +00:00
internal-nix-ci[bot]
b36b22e837 Merge pull request #14898 from NixOS/backport-14888-to-2.29-maintenance
[Backport 2.29-maintenance] ci: GitHub releng for release automation
2026-01-01 15:12:20 +00:00
Sergei Zimmerman
eee30e8a6c release-process: Document usage of upload-release.yml workflow
(cherry picked from commit 84ff2ef347)
2026-01-01 14:45:19 +00:00
Sergei Zimmerman
a8149019b6 upload-release: Only upload the newly created tag
(cherry picked from commit 3933e45d52)
2026-01-01 14:45:19 +00:00
Sergei Zimmerman
c3c0c35ae1 upload-release: Also push to GHCR as part of the release process
(cherry picked from commit a1569458cc)
2026-01-01 14:45:19 +00:00
Sergei Zimmerman
ef0ea6002a ci: Add upload-release.yml
This workflow is supposed to automate release uploads by using OIDC
for AWS setup. DockerHub still uses long-lived credentials, but that's
not fixable. In a follow-up we could set up release uploads to GHCR too.

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

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

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

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

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

(cherry picked from commit d19b8d5f99)
2026-01-01 14:45:19 +00:00
Sergei Zimmerman
2b5767afd3 Merge pull request #14885 from NixOS/backport-ci-changes-2.29
Backport CI changes to 2.29-maintenance
2025-12-29 01:09:45 +03:00
Sergei Zimmerman
0a0501527d ci: Make docker-push workflow more configurable
This should allow reusing this workflow (with more tweaks)
in the releng workflow.

(cherry picked from commit c867ed6726)
2025-12-29 00:33:53 +03:00
Sergei Zimmerman
d136ee333f ci: Pin actions in docker-push reusable workflow
(cherry picked from commit fb05f6de0d)
2025-12-29 00:33:52 +03:00
Sergei Zimmerman
9744d19290 ci: Move docker_push_image into a separate workflow
Best reviewed with -w --color-moved. This just moves the code
into a separate workflow. This will allow us to reuse it in
the release job for github releng of releases.

(cherry picked from commit 745983dfc0)
2025-12-29 00:33:49 +03:00
Sergei Zimmerman
30cbda8093 ci: Bump magic-nix-cache with post-build-hook fix
No tagged release with the fix for [^].

[^]: 578f01e147

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

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

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

(cherry picked from commit 92d7381826)
2025-12-29 00:29:43 +03:00
Seth Flynn
4c7676a530 ci: enable use of the experimental installer
(cherry picked from commit 2cbbb63628)
2025-12-29 00:29:38 +03:00
Eelco Dolstra
0501ae1e49 Merge pull request #14763 from roberth/backport-14690-to-2.29
Backport 14690 to 2.29
2025-12-10 13:19:01 +01:00
Robert Hensing
04a86cd3c1 maint: Remove mdbook-linkcheck and support mdbook 0.5.x
Fixes #14628

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

(cherry picked from commit d950f884c2)
2025-12-10 12:31:16 +01:00
internal-nix-ci[bot]
903fccf2fd Merge pull request #14521 from NixOS/backport-14515-to-2.29-maintenance
[Backport 2.29-maintenance] libexpr: Don't use nix::dirOf in prim_dirOf (fix 2.23 regression)
2025-11-09 18:18:05 +00:00
Sergei Zimmerman
19839dbd15 libexpr: Don't use nix::dirOf in prim_dirOf
This gets us back to pre-2.23 behavior of this primop.
Done by inlining the code of `nix::dirOf` from 2.2-maintenance.

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

(cherry picked from commit 86f090837b)
2025-11-09 17:42:55 +00:00
internal-nix-ci[bot]
3f1f531a25 Merge pull request #14495 from NixOS/backport-14491-to-2.29-maintenance
[Backport 2.29-maintenance] Don't crash on flakerefs containing newlines
2025-11-06 19:52:09 +00:00
Eelco Dolstra
50cc70b71e Don't crash on flakerefs containing newlines
Fixes #14311.

(cherry picked from commit c1317017e9)
2025-11-06 19:18:04 +00:00
John Ericson
3adb146014 Merge pull request #14044 from NixOS/mergify/bp/2.29-maintenance/pr-13929
Remove unused function setChildSignalMask() (backport #13929)
2025-09-22 13:34:12 -04:00
Eelco Dolstra
158efe6cc8 Remove unused function setChildSignalMask()
(cherry picked from commit a44dcbff13)
2025-09-22 16:30:58 +00:00
Eelco Dolstra
c9380d9736 Bump version 2025-09-01 18:29:21 +02:00
Jörg Thalheim
a885a36130 Merge pull request #13746 from NixOS/mergify/bp/2.29-maintenance/pr-13741
libexpr: Canonicalize TOML timestamps for toml11 > 4.0 (backport #13741)
2025-08-29 07:35:56 +02:00
mergify[bot]
2851af6784 Merge pull request #13841 from NixOS/mergify/bp/2.29-maintenance/pr-13837
flake: Update nixpkgs (backport #13837)
2025-08-27 08:20:17 +00:00
Sergei Zimmerman
42ddc10d92 flake: Update nixpkgs
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/cd32a774ac52caaa03bcfc9e7591ac8c18617ced?narHash=sha256-VtMQg02B3kt1oejwwrGn50U9Xbjgzfbb5TV5Wtx8dKI%3D' (2025-08-17)
  → 'github:NixOS/nixpkgs/d98ce345cdab58477ca61855540999c86577d19d?narHash=sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8%3D' (2025-08-26)

This update contains d1266642a8722f2a05e311fa151c1413d2b9653c, which
is necessary for the TOML timestamps to get tested via nixpkgsLibTests job.

(cherry picked from commit 625477a7df)
2025-08-27 07:52:40 +00:00
Sergei Zimmerman
a5ab03cb16 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.
   Newer versions cap it at 6 digits unconditionally.

[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 dc769d72cb)
2025-08-19 00:11:21 +03:00
Sergei Zimmerman
b4871a4a94 libexpr: Use table.size() instead of unnecessary loop
(cherry picked from commit d8fc55a46e)
2025-08-19 00:11:20 +03:00
Sergei Zimmerman
027bf13e18 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 a80a5c4dba)
2025-08-19 00:11:19 +03:00
Sergei Zimmerman
3e3d2b7d01 libexpr: Remove extra trailing semicolons (NFC)
This looks really weird after the reformat.

(cherry picked from commit df4e55ffc1)
2025-08-19 00:11:18 +03:00
Sergei Zimmerman
1a55d733ce 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 7ed0229d1a)
2025-08-19 00:11:17 +03:00
John Ericson
9328af84d3 Merge pull request #13787 from NixOS/mergify/bp/2.29-maintenance/pr-13785
flake: nixpkgs: nixos-unstable -> nixos-25.05-small (backport #13785)
2025-08-18 16:56:44 -04:00
Sergei Zimmerman
2aba7ac90d hydra: Fix otherNixes.nix_2_3
25.05 has it marked as insecure, but we don't care about it
for testing purposes.

(cherry picked from commit 051290b155)
2025-08-18 22:52:16 +03:00
Sergei Zimmerman
adc17bace9 git-blame-ignore-revs: Add nixfmt 1.0.0 reformat 2025-08-18 22:51:37 +03:00
Sergei Zimmerman
d6aebd8847 flake: Apply nixfmt 1.0.0 2025-08-18 22:50:52 +03:00
Sergei Zimmerman
c53ac76f7b flake: nixpkgs: nixos-unstable -> nixos-25.05-small
About time we upgraded our nixpkgs flake input. Ideally
we'd have automation to do this.

Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/adaa24fbf46737f3f1b5497bf64bae750f82942e?narHash=sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY%3D' (2025-05-13)
  → 'github:NixOS/nixpkgs/cd32a774ac52caaa03bcfc9e7591ac8c18617ced?narHash=sha256-VtMQg02B3kt1oejwwrGn50U9Xbjgzfbb5TV5Wtx8dKI%3D' (2025-08-17)

(cherry picked from commit fc33681583)
2025-08-18 22:48:03 +03:00
mergify[bot]
2454267de0 Merge pull request #13648 from NixOS/mergify/bp/2.29-maintenance/pr-13393
Fix typo: remove an extra word (backport #13393)
2025-07-31 03:47:43 +00:00
mergify[bot]
9572fdeb3b Merge pull request #13650 from NixOS/mergify/bp/2.29-maintenance/pr-13395
libstore-tests: Don't leak memory in tests (backport #13395)
2025-07-31 03:47:40 +00:00
mergify[bot]
69d2e6eeef Merge pull request #13605 from NixOS/mergify/bp/2.29-maintenance/pr-13282
tests/functional: Add more language tests for `builtins.match` (backport #13282)
2025-07-31 02:16:21 +00:00
mergify[bot]
2870c177d6 Merge pull request #13612 from NixOS/mergify/bp/2.29-maintenance/pr-13305
add documentation of tarball-ttl to nix-channel (backport #13305)
2025-07-31 02:11:59 +00:00
mergify[bot]
b0169fdc5f Merge pull request #13633 from NixOS/mergify/bp/2.29-maintenance/pr-13360
libexpr: Remove non-const overload of `listElems` (backport #13360)
2025-07-31 02:11:56 +00:00
mergify[bot]
7b08e8d20e Merge pull request #13610 from NixOS/mergify/bp/2.29-maintenance/pr-13304
Fix overriding gtest with gmock (backport #13304)
2025-07-31 02:11:52 +00:00
mergify[bot]
aabe327111 Merge pull request #13646 from NixOS/mergify/bp/2.29-maintenance/pr-13382
Update docs (backport #13382)
2025-07-31 02:11:49 +00:00
mergify[bot]
ab4951588b Merge pull request #13620 from NixOS/mergify/bp/2.29-maintenance/pr-13326
docker.nix: Prevent double copy of nixpkgs source tree (backport #13326)
2025-07-31 02:11:46 +00:00
mergify[bot]
b41101c815 Merge pull request #13628 from NixOS/mergify/bp/2.29-maintenance/pr-13351
docker: make sure `nix config check` works (backport #13351)
2025-07-31 01:53:07 +00:00
mergify[bot]
cb73841205 Merge pull request #13626 from NixOS/mergify/bp/2.29-maintenance/pr-13347
Fix broken link in configuration description (backport #13347)
2025-07-31 01:53:04 +00:00
mergify[bot]
931ca7d11a Merge pull request #13635 from NixOS/mergify/bp/2.29-maintenance/pr-13361
Fix a minor typo (backport #13361)
2025-07-31 01:53:01 +00:00
mergify[bot]
b5efc9ac56 Merge pull request #13618 from NixOS/mergify/bp/2.29-maintenance/pr-13321
Modify docker.nix to use mapAttrsToList instead of mapAttrsFlatten (backport #13321)
2025-07-31 01:52:59 +00:00
mergify[bot]
012f429104 Merge pull request #13639 from NixOS/mergify/bp/2.29-maintenance/pr-13373
Fix typo (backport #13373)
2025-07-31 01:52:55 +00:00
mergify[bot]
830dfc3b60 Merge pull request #13641 from NixOS/mergify/bp/2.29-maintenance/pr-13372
Fix broken link (backport #13372)
2025-07-31 01:49:41 +00:00
mergify[bot]
2968e18d37 Merge pull request #13637 from NixOS/mergify/bp/2.29-maintenance/pr-13368
libstore: fix race condition when creating state directories (backport #13368)
2025-07-31 01:49:39 +00:00
mergify[bot]
66a379a6de Merge pull request #13596 from NixOS/mergify/bp/2.29-maintenance/pr-13257
Make the S3 test more robust (backport #13257)
2025-07-31 01:49:36 +00:00
mergify[bot]
1dcd12b819 Merge pull request #13592 from NixOS/mergify/bp/2.29-maintenance/pr-13245
nix-profile{,-daemon}.fish: check for profile in XDG_DATA_HOME (backport #13245)
2025-07-31 01:49:33 +00:00
mergify[bot]
2298df294b Merge pull request #13602 from NixOS/mergify/bp/2.29-maintenance/pr-13277
nix flake archive: add --no-check-sigs option (backport #13277)
2025-07-31 01:49:30 +00:00
mergify[bot]
b4cd61900b Merge pull request #13586 from NixOS/mergify/bp/2.29-maintenance/pr-13232
docs: add another equivalence for the implication operator (backport #13232)
2025-07-30 19:32:55 +00:00
mergify[bot]
2c258dd275 Merge pull request #13594 from NixOS/mergify/bp/2.29-maintenance/pr-13253
export/meson: Don't require `-std=c++2a` for -c libraries in `.pc` files (backport #13253)
2025-07-30 19:13:31 +00:00
mergify[bot]
75bece800d Merge pull request #13599 from NixOS/mergify/bp/2.29-maintenance/pr-13275
Remove propagated-build-inputs when static (backport #13275)
2025-07-30 19:11:57 +00:00
mergify[bot]
582caa9d8f Merge pull request #13580 from NixOS/mergify/bp/2.29-maintenance/pr-13211
libexpr: Actually cache line information in PosTable (backport #13211)
2025-07-30 19:11:53 +00:00
mergify[bot]
8a3d3b2dce Merge pull request #13590 from NixOS/mergify/bp/2.29-maintenance/pr-13244
nix-profile{,-daemon}.fish: fix do not source twice (backport #13244)
2025-07-30 19:06:05 +00:00
mergify[bot]
56069a968b Merge pull request #13582 from NixOS/mergify/bp/2.29-maintenance/pr-13213
docs: fix duplicate anchor (backport #13213)
2025-07-30 13:44:44 +00:00
Sergei Zimmerman
87ee4423ea libstore-tests: Don't leak memory in tests
We shouldn't leak memory in unit tests in order
to make enabling ASAN easier.

(cherry picked from commit 55d12dfc5d)
2025-07-30 13:02:41 +00:00
Egor Konovalov
c9ecc99ce5 Fix link
Remove extra `realise`

(cherry picked from commit df21f24987)
2025-07-30 13:01:39 +00:00
Nikita Krasnov
ceb4d561fa Update docs
(cherry picked from commit 785f3867fd)
2025-07-30 13:00:38 +00:00
Nikita Krasnov
5d58ab8042 Fix broken link
(cherry picked from commit da76bc0cac)
2025-07-30 12:59:29 +00:00
Nikita Krasnov
27a8b457b8 Fix typo
(cherry picked from commit 86dda9884a)
2025-07-30 12:58:23 +00:00
Wolfgang Walther
229e97195a libstore: fix race condition when creating state directories
Running parallel nix in nix can lead to multiple instances trying to
create the state directories and failing on the `createSymlink` step,
because the link already exists.

`replaceSymlink` is already idempotent, so let's use that.

Resolves #2706

(cherry picked from commit d64c922164)
2025-07-30 12:56:36 +00:00
jayeshv
e3f4cef054 Fix a minor typo
(cherry picked from commit 699db04df3)
2025-07-30 12:55:32 +00:00
Sergei Zimmerman
223d3222b3 libexpr: Remove non-const overload of listElems
This overload isn't actually necessary anywhere and
doesn't make much sense. The pointers to `Value`s are
themselves const, but the `Value`s are mutable.
A non-const member function implies that the object itself
can be modified but this doesn't make much sense considering
the return type: `Value * const * `, which is a pointer
to a constant array of pointers to mutable values.

(cherry picked from commit 7b46eb9958)
2025-07-30 12:54:33 +00:00
Pol Dellaiera
a98f742d67 docker: make sure nix config check works
(cherry picked from commit 57c72dee9b)
2025-07-30 12:45:49 +00:00
Luc Perkins
e0ceebe2ee Fix broken link in configuration description
(cherry picked from commit 525078c59d)
2025-07-30 12:43:45 +00:00
Eelco Dolstra
bb0e9b20aa Prevent double copy of nixpkgs source tree
(cherry picked from commit 0a87ba0e39)
2025-07-30 12:40:33 +00:00
PopeRigby
d7ed70841a Modify docker.nix to use mapAttrsToList instead of mapAttrsFlatten
The latter alias is deprecated in favor of the former, and produces a
warning.

(cherry picked from commit cfc15d6921)
2025-07-30 12:39:36 +00:00
Jade Masker
7d1704218f add reference to the tarball-ttl documentation
Co-authored-by: Valentin Gagarin <valentin@gagarin.work>
(cherry picked from commit c0ceaa2d5d)
2025-07-30 12:36:15 +00:00
Jade Masker
44a1e7e88c remove overly verbose mention of fetchTarball
Co-authored-by: Valentin Gagarin <valentin@gagarin.work>
(cherry picked from commit 633d39109b)
2025-07-30 12:36:14 +00:00
Jade Lynn Masker
ed7ebdfad3 add documentation of tarball-ttl to nix-channel
(cherry picked from commit 6badd21b6a)
2025-07-30 12:36:14 +00:00
Farid Zakaria
82fa307ca6 Overriding gtest with gmock
How did this work before...

* Added .direnv/ to gitignore

(cherry picked from commit 58e34a2d27)
2025-07-30 12:35:28 +00:00
Sergei Zimmerman
4d9d307477 tests/functional: Add more language tests for builtins.match
These tests have been collected from nixpkgs f870c6ccc8951fc48aeb293cf3e98ade6ac42668
usage of builtins.match for x86_64-linux eval system. At most 2 matching and
non-matching cases are included for each encountered regex. This should
hopefully add more confidence when possibly trying to switch the regex implementation
in the future.

(cherry picked from commit d555d6b404)
2025-07-30 12:26:20 +00:00
zimbatm
ee39380c12 nix flake archive: add --no-check-sigs option
Allows to copy the archive to a remote host and not get

    error: cannot add path '/nix/store/01x2k4nlxcpyd85nnr0b9gm89rm8ff4x-source' because it lacks a signature by a trusted key

(cherry picked from commit 80a4293486)
2025-07-30 12:24:10 +00:00
Tristan Ross
47ce401222 Remove propagated-build-inputs when static
(cherry picked from commit d07852b5f3)
2025-07-30 12:20:06 +00:00
Eelco Dolstra
78ac959e4c Make the S3 test more robust
Waiting for the minio unit is apparently not reliable enough, so let's
also wait for the port.

(cherry picked from commit ca9696748a)
2025-07-30 12:13:34 +00:00
Sergei Zimmerman
709349b118 export/meson: Don't require -std=c++2a for -c libraries in .pc files
(cherry picked from commit d8da8f0cd6)
2025-07-30 12:11:58 +00:00
Stefan Boca
9106a0b73a nix-profile{,-daemon}.fish: check for profile in XDG_DATA_HOME
...and also NIX_STATE_HOME in nix-profile.fish. This is directly
translated from the bash scripts and makes the fish scripts equivalent
in functionality to the bash scripts.

Note that nix-profile.fish checks for NIX_STATE_HOME and
nix-profile-daemon.fish does not, so the two scripts are no longer
identical.

(cherry picked from commit 751f50f4ad)
2025-07-30 12:04:56 +00:00
Stefan Boca
1b97d7409a nix-profile{,-daemon}.fish: fix do not source twice
Commit b36637c8f7 set
`__ETC_PROFILE_NIX_SOURCED` globally, but this is not enough to prevent
the script from being run again by child shells, because the
variable was not exported and thus not inherited by any child process.
Exporting the variable also agrees with the bash scripts.

Notably, the old behavior broke `nix develop -c fish` in some cases,
because the profile bin directory got prepended to the path, causing
binaries from the profile to override binareis from the devshell.

(cherry picked from commit b9ed3ae36e)
2025-07-30 12:03:51 +00:00
Stefan Boca
ab95054e64 nix-profile{,-daemon}.fish: format with fish_indent
(cherry picked from commit f627b8c721)
2025-07-30 12:03:50 +00:00
Gwenn Le Bihan
a5deed32f7 docs: add another equivalence for the implication operator
the second equivalence, using a if-else expression, aligns much closer to how most humans think about implication, adding it might help some people :)

(cherry picked from commit 51151c2c28)
2025-07-30 12:00:08 +00:00
Peder Bergebakken Sundt
94723d5b72 docs: fix duplicate anchor
`#deriving-path-encoding` is defined in two places, I _think_ this is the correct one to change.

(cherry picked from commit 4c50cf798e)
2025-07-30 11:53:57 +00:00
Sergei Zimmerman
ef8dc34bd0 libexpr: Actually cache line information in PosTable
Previous code had a sneaky bug due to which no caching
actually happened:

```cpp
auto linesForInput = (*lines)[origin->offset];
```

That should have been:
```cpp
auto & linesForInput = (*lines)[origin->offset];
```

See [1].

Now that it also makes sense to make the cache bound in side
in order not to memoize all the sources without freeing any memory.
The default cache size has been chosen somewhat arbitrarily to be ~64k
origins. For reference, 25.05 nixpkgs has ~50k .nix files.

Simple benchmark:

```nix
let
  pkgs = import <nixpkgs> { };
in
builtins.foldl' (acc: el: acc + el.line) 0 (
  builtins.genList (x: builtins.unsafeGetAttrPos "gcc" pkgs) 10000
)
```

(After)

```
$ hyperfine "result/bin/nix eval -f ./test.nix"
Benchmark 1: result/bin/nix eval -f ./test.nix
  Time (mean ± σ):     292.7 ms ±   3.9 ms    [User: 131.0 ms, System: 120.5 ms]
  Range (min … max):   288.1 ms … 300.5 ms    10 runs
```

(Before)

```
hyperfine "nix eval -f ./test.nix"
Benchmark 1: nix eval -f ./test.nix
  Time (mean ± σ):     666.7 ms ±   6.4 ms    [User: 428.3 ms, System: 191.2 ms]
  Range (min … max):   659.7 ms … 681.3 ms    10 runs
```

If the origin happens to be a `all-packages.nix` or similar in size then the
difference is much more dramatic.

[1]: 22e3f0e987

(cherry picked from commit 5ea81f5b8f)
2025-07-30 11:51:53 +00:00
Sergei Zimmerman
bb8b50e4f3 libutil: Add LRUCache::getOrNullptr
For heavier objects it doesn't make sense to return
a std::optional with the copy of the data, when it
can be used by const reference.

(cherry picked from commit 4711720efe)
2025-07-30 11:51:53 +00:00
mergify[bot]
0877680b08 Merge pull request #13561 from NixOS/mergify/bp/2.29-maintenance/pr-13558
meson: Fix `nix_system_cpu` for MIPS and 32 bit ARM systems (backport #13558)
2025-07-27 00:10:00 +00:00
Sergei Zimmerman
e37fce3899 meson: Fix nix_system_cpu for MIPS and 32 bit ARM systems
Prior patches in 54dc5314e8
and 6db6190002 fixed the default
system double for i686 and ppc/ppc64. This also patch also covers
32 bit arm and mips. ARM cpu names are taken from host_machine.cpu()
for a lack of a better option, but host_machine.cpu_family() is
preferred, since that is supposed to be somewhat standard for cross
files. Endianness is handled correctly by looking at host_machine.endian().

This also updates the documentation to be up to date to how system cpu
is translated from the host_machine specification.

(cherry picked from commit 60d124b36e)
2025-07-26 23:29:28 +00:00
Eelco Dolstra
c1f54da018 Merge pull request #13540 from NixOS/mergify/bp/2.29-maintenance/pr-13535
Fix nix_system_cpu on i686-linux (backport #13535)
2025-07-25 02:08:52 +02:00
Eelco Dolstra
a1efe99f5b Fix nix_system_cpu on i686-linux
Fixes #13532.

(cherry picked from commit 54dc5314e8)
2025-07-25 02:53:50 +03:00
Sergei Zimmerman
359227ad14 meson: Correctly handle endianness for PowerPC CPU families
I've missed this while reviewing 6db6190002.
I only built big endian ppc64, so that didn't occur to me.

From meson manual:

> Those porting from autotools should note that Meson does not add
> endianness to the name of the cpu_family. For example, autotools will
> call little endian PPC64 "ppc64le", Meson will not, you must also check
> the .endian() value of the machine for this information.

This code should handle that correctly.

(cherry picked from commit ebd311b7b7)
2025-07-25 02:53:49 +03:00
Sergei Zimmerman
e0d2cf5a89 Merge pull request #13548 from NixOS/mergify/bp/2.29-maintenance/pr-13546
ci: Make it actually possible to disable dogfooding (backport #13546)
2025-07-25 02:53:03 +03:00
Sergei Zimmerman
da770a89e6 ci: Roll back default nix to 2.29.1 in install-nix-action
Daemon tests are broken in 2.30.1 Darwin sandbox and there's
no point release with the fix yet.
2025-07-25 02:22:07 +03:00
Sergei Zimmerman
58c71ed812 ci: Make it actually possible to disable dogfooding
Github composite actions are a real treat. Boolean inputs
are not actually booleans but rather strings [1].

[1]: https://www.github.com/actions/runner/issues/2238

(cherry picked from commit f0695e177f)
2025-07-24 23:18:36 +00:00
Sergei Zimmerman
c972f66475 Merge pull request #13537 from NixOS/mergify/bp/2.29-maintenance/pr-13473
ci: Dogfood Nix from master (backport #13473)
2025-07-25 02:17:29 +03:00
Sergei Zimmerman
bfc5678471 ci: Don't dogfood installer from master
CI on release branches should be stable, otherwise backporting
might become flaky and unreliable. Dogfooding only really makes
sense for CI on master branch, where failures are not as tedious
to work around.
2025-07-25 01:56:12 +03:00
Sergei Zimmerman
a5684b2c83 ci: Dogfood nix from master for vm_tests and flake_regressions
This should provide more coverage for the build from master that
is being dogfooded.

(cherry picked from commit 3b3c02160d)
2025-07-25 01:14:39 +03:00
Sergei Zimmerman
c17e66af6f ci: Dogfood Nix from master
(cherry picked from commit 04f6974d2c)

# Conflicts:
#	.github/workflows/ci.yml
2025-07-25 01:14:38 +03:00
mergify[bot]
661caad5bb Merge pull request #13517 from NixOS/mergify/bp/2.29-maintenance/pr-13514
treewide: Fix Meson CPU names for powerpc CPUs (backport #13514)
2025-07-21 23:33:35 +00:00
OPNA2608
281e3b0247 treewide: Fix Meson CPU names for powerpc CPUs
(cherry picked from commit 6db6190002)
2025-07-21 22:49:14 +00:00
Jörg Thalheim
af342d8b2b Merge pull request #13505 from NixOS/mergify/bp/2.29-maintenance/pr-13108
Rip off the bandaid: Format the codebase with clang-format (backport #13108)
2025-07-18 22:31:35 +02:00
Sergei Zimmerman
7c2b240ded Update .git-blame-ignore-revs to ignore the mass reformatting
Co-authored-by: Graham Christensen <graham@grahamc.com>
2025-07-18 22:50:11 +03:00
Sergei Zimmerman
0e35cd6f3e Apply clang-format universally.
* It is tough to contribute to a project that doesn't use a formatter,
* It is extra hard to contribute to a project which has configured the formatter, but ignores it for some files
* Code formatting makes it harder to hide obscure / weird bugs by accident or on purpose,

Let's rip the bandaid off?

Note that PRs currently in flight should be able to be merged relatively easily by applying `clang-format` to their tip prior to merge.

Co-authored-by: Graham Christensen <graham@grahamc.com>
2025-07-18 22:49:40 +03:00
Graham Christensen
a5cfab671b Update clang-format with fixing namespace coments, and separate definition blocks
(cherry picked from commit 41bf87ec70)
2025-07-18 22:47:54 +03:00
Graham Christensen
bd1ff9f254 Drop a ton of files that should just get formatted
(cherry picked from commit e7af2e6566)
2025-07-18 22:47:48 +03:00
Graham Christensen
036cd2a408 Add sed
(cherry picked from commit 6896761d79)
2025-07-18 19:42:21 +00:00
Graham Christensen
82bf098fbe format.sh: support looping until it is happy
(cherry picked from commit ee9b57cbf5)
2025-07-18 19:42:21 +00:00
Sergei Zimmerman
4b3bbf8511 Merge pull request #13452 from NixOS/mergify/bp/2.29-maintenance/pr-13450
libexpr: Fix invalid handling of errors for imported functions (backport #13450)
2025-07-12 00:12:25 +03:00
Sergei Zimmerman
8736cb537d libexpr: Fix invalid handling of errors for imported functions
c39cc00404 has added assertions for
all Value accesses and the following case has started failing with
an `unreachable`:

(/tmp/fun.nix):

```nix
{a}: a
```

```
$ nix eval --impure --expr 'import /tmp/fun.nix {a="a";b="b";}'
```

This would crash:

```
terminating due to unexpected unrecoverable internal error: Unexpected condition in getStorage at ../include/nix/expr/value.hh:844
```

This is not a regression, but rather surfaces an existing problem, which previously
was left undiagnosed. In the case of an import `fun` is the `import` primOp, so that read is invalid
and previously this resulted in an access into an inactive union member, which is UB.
The correct thing to use is `vCur`. Identical problem also affected the case of a missing argument.

Add previously failing test cases to the functional/lang test suite.

Fixes #13448.

(cherry picked from commit 6e78cc90d3)
2025-07-11 22:51:09 +03:00
Eelco Dolstra
d4d0853fee Merge pull request #13415 from NixOS/mergify/bp/2.29-maintenance/pr-13412
libutil: Use caching `directory_entry` API in `PosixSourceAccessor::r… (backport #13412)
2025-07-01 17:48:23 +02:00
Sergei Zimmerman
aaffbc2209 libutil: Use caching directory_entry API in PosixSourceAccessor::readDirectory
Previous use of symlink_status() always translated into a stat call, leading
to huge performance penalties for by-name-overlay in nixpkgs. The comment
below references the possible caching, but that seemed to be erroneous, since
the correct way to make use of the caching API is by calling a bunch of `is_*`
functions [1]. For example, here's how libstdc++ does that [2], [3].

This translates to great nixpkgs eval performance improvements:

```
Benchmark 1: GC_INITIAL_HEAP_SIZE=4G result/bin/nix-instantiate ../nixpkgs -A hello --readonly-mode
  Time (mean ± σ):     186.7 ms ±   6.7 ms    [User: 121.3 ms, System: 64.9 ms]
  Range (min … max):   179.4 ms … 201.6 ms    16 runs

Benchmark 2: GC_INITIAL_HEAP_SIZE=4G nix-instantiate ../nixpkgs -A hello --readonly-mode
  Time (mean ± σ):     230.6 ms ±   5.0 ms    [User: 126.9 ms, System: 103.1 ms]
  Range (min … max):   225.1 ms … 241.4 ms    13 runs
```

[1]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0317r1.html
[2]: 8ea555b7b4/libstdc%2B%2B-v3/include/bits/fs_dir.h (L341-L348)
[3]: 8ea555b7b4/libstdc%2B%2B-v3/include/bits/fs_dir.h (L161-L163)

(cherry picked from commit 8708e9a526)
2025-07-01 15:00:31 +00:00
mergify[bot]
8f6c5d088a Merge pull request #13404 from NixOS/mergify/bp/2.29-maintenance/pr-13170
Use correct parent `outPath` for relative path inputs (backport #13170)
2025-06-27 12:34:04 +00:00
Matt Sturgeon
d0290d342d Add release note for non-flake inputs having sourceInfo
(cherry picked from commit 2922e3082e)
2025-06-27 11:59:53 +00:00
Matt Sturgeon
7b050cec80 tests/functional/flakes/non-flake-inputs: Test non-flake inputs having sourceInfo
(cherry picked from commit 72232bc28a)
2025-06-27 11:59:53 +00:00
Robert Hensing
82dcbe0510 tests/function/flakes/relative-paths: Test #13164
(cherry picked from commit eaee0b4740)
2025-06-27 11:59:52 +00:00
Matt Sturgeon
31e19b0a28 Use correct parent outPath for relative path inputs
Ensure relative path inputs are relative to the parent node's _actual_
`outPath`, instead of the subtly different `sourceInfo.outPath`.

Additionally, non-flake inputs now also have a `sourceInfo` attribute.

This fixes the relationship between `self.outPath` and
`self.sourceInfo.outPath` in some edge cases.

Fixes #13164

(cherry picked from commit 46beb9af76)
2025-06-27 11:59:52 +00:00
Eelco Dolstra
7bb2001997 Bump version 2025-06-24 17:02:40 +02:00
Eelco Dolstra
5d78f74fe4 Merge remote-tracking branch 'cve/fod-cves-2.29' into 2.29-maintenance 2025-06-24 16:05:12 +02:00
mergify[bot]
b3b137ec4a Merge pull request #13392 from NixOS/mergify/bp/2.29-maintenance/pr-13348
Make the repl test more robust (backport #13348)
2025-06-22 19:41:08 +00:00
Eelco Dolstra
833406121c Make the repl test more robust
Seen in https://github.com/DeterminateSystems/nix-src/actions/runs/15590867877/job/43909540271:

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

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

(cherry picked from commit 9eb46e9cc0)
2025-06-22 19:09:38 +00:00
Eelco Dolstra
01619fbe2d Fixes for GHSA-g948-229j-48j3
Squashed commit of the following:

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

    Chown structured attr files safely

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

    Replace 'bool sync' with an enum for clarity

    And drop writeFileAndSync().

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

    Drop guessOrInventPathFromFD()

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

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

    Tweak comment

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    libutil: writeFile variant for file descriptors

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

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

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

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

    libstore: chown to builder variant for file descriptors

    We use it immediately for the build temporary directory.

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

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

    libstore: open build directory as a dirfd as well

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

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

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

    libutil: guess or invent a path from file descriptors

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

    Change-Id: I2d800740cb4f9912e64c923120d3f977c58ccb7e
    Signed-off-by: Raito Bezarius <raito@lix.systems>
2025-06-19 16:29:59 +02:00
mergify[bot]
075df0b446 Merge pull request #13380 from NixOS/mergify/bp/2.29-maintenance/pr-13376
Revert "Drop magic-nix-cache" (backport #13376)
2025-06-19 12:44:08 +00:00
Eelco Dolstra
2f6c758d3d Revert "Drop magic-nix-cache"
This reverts commit 9cc8be2674 since
magic-nix-cache works again (thanks @jchv).

(cherry picked from commit 9b57573bae)
2025-06-19 12:12:28 +00:00
mergify[bot]
4c7e5ce7a8 Merge pull request #13375 from NixOS/mergify/bp/2.29-maintenance/pr-13371
tests: fixup with jq-1.8.0 (backport #13371)
2025-06-18 15:51:12 +00:00
Vladimír Čunát
86fbaf3b14 tests: fixup with jq-1.8.0
(cherry picked from commit 77f6b6532f)
2025-06-18 15:18:06 +00:00
mergify[bot]
5c3aed3e88 Merge pull request #13330 from NixOS/mergify/bp/2.29-maintenance/pr-13284
lockFlake(): Allow registry lookups for overridden inputs (backport #13284)
2025-06-06 08:47:04 +00:00
Seth Flynn
fcdffffa37 lockFlake(): Allow registry lookups for overridden inputs
Fixes #13144

(cherry picked from commit d0a2323829)
2025-06-06 08:12:20 +00:00
mergify[bot]
aeb627bebf Merge pull request #13316 from NixOS/mergify/bp/2.29-maintenance/pr-13296
Clear `displayPrefix` in `makeEmptySourceAccessor` (backport #13296)
2025-06-03 18:08:59 +00:00
Sergei Zimmerman
a2567f6d7a Clear displayPrefix in makeEmptySourceAccessor
Judging by the comment for `makeEmptySourceAccessor` the prefix has
to be empty:

> Return a source accessor that contains only an empty root directory.

Fixes #13295.

(cherry picked from commit fba1bb0c13)
2025-06-03 19:27:15 +02:00
mergify[bot]
c1e272b47d Merge pull request #13319 from NixOS/mergify/bp/2.29-maintenance/pr-13274
Drop magic-nix-cache (backport #13274)
2025-06-03 14:52:47 +00:00
Eelco Dolstra
cfba4b3bf4 Drop magic-nix-cache
This no longer works, see https://determinate.systems/posts/magic-nix-cache-free-tier-eol/.

(cherry picked from commit 9cc8be2674)
2025-06-03 14:18:54 +00:00
mergify[bot]
d761dad79c Merge pull request #13259 from NixOS/mergify/bp/2.29-maintenance/pr-13256
Fix nlohmann error in fromStructuredAttrs() (backport #13256)
2025-05-25 06:35:47 +00:00
Eelco Dolstra
d068b82c2f Add test
(cherry picked from commit c66eb9cef7)
2025-05-25 05:55:28 +00:00
Eelco Dolstra
8ca4d2ef08 fromStructuredAttrs(): Don't crash if exportReferencesGraph is a string
Fixes

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

and other crashes.

Fixes #13254.

(cherry picked from commit d877b0c0cc)
2025-05-25 05:55:27 +00:00
Eelco Dolstra
acc3cd460d Don't use 'callback' object that we may have moved out of
(cherry picked from commit fa6e10ea6a)
2025-05-25 05:55:27 +00:00
Eelco Dolstra
c4813b8cbc Bump version 2025-05-22 14:48:51 +02:00
Eelco Dolstra
0cd1fce3c3 Merge pull request #13230 from NixOS/mergify/bp/2.29-maintenance/pr-13228
libutil-tests/json-utils: fix -Werror=sign-compare error (backport #13228)
2025-05-19 16:46:37 +02:00
Jörg Thalheim
90eb2f759c libutil-tests/json-utils: fix -Werror=sign-compare error
I am on a newer different nixpkgs branch, so I am getting this error

(cherry picked from commit 1290b7e53d)
2025-05-19 14:16:43 +00:00
Jörg Thalheim
d1e4be6fb4 Merge pull request #13227 from NixOS/mergify/bp/2.29-maintenance/pr-13142
libstore: Use `boost::regex` for GC root discovery (backport #13142)
2025-05-18 22:26:54 +02:00
Sergei Zimmerman
29d98da636 libstore: Depend on boost_regex explicitly
(cherry picked from commit 18a5589f9a)
2025-05-18 19:46:17 +00:00
Sergei Zimmerman
91dc6e7fa0 packaging/dependencies: Use boost without enableIcu
This reduces the closure size on master by 40MiB.

```
$ nix build github:nixos/nix/1e822bd4149a8bce1da81ee2ad9404986b07914c#nix-store --out-link closure-on-master
$ nix build .#nix-store -L --out-link closure-without-icu
$ nix path-info --closure-size -h ./closure-on-master
/nix/store/8gwr38m5h6p7245ji9jv28a2a11w1isx-nix-store-2.29.0pre  124.4 MiB
$ nix path-info --closure-size -h ./closure-without-icu
/nix/store/k0gwfykjqpnmaqbwh23nk55lhanc9g24-nix-store-2.29.0pre   86.6 MiB
```

(cherry picked from commit f3090ef703)
2025-05-18 19:46:17 +00:00
Sergei Zimmerman
b33fd1e4fb libstore: Use boost::regex for GC root discovery
As it turns out using `std::regex` is actually the bottleneck
for root discovery. Just substituting `std::` -> `boost::`
makes root discovery twice as fast (3x if counting only userspace time).

Some rather ad-hoc measurements to motivate the switch:

(On master)

```
nix build github:nixos/nix/1e822bd4149a8bce1da81ee2ad9404986b07914c#nix-cli --out-link result-1e822bd4149a8bce1da81ee2ad9404986b07914c
taskset -c 2,3 hyperfine "result-1e822bd4149a8bce1da81ee2ad9404986b07914c/bin/nix store gc --dry-run --max 0"
Benchmark 1: result-1e822bd4149a8bce1da81ee2ad9404986b07914c/bin/nix store gc --dry-run --max 0
  Time (mean ± σ):     481.6 ms ±   3.9 ms    [User: 336.2 ms, System: 142.0 ms]
  Range (min … max):   474.6 ms … 487.7 ms    10 runs
```

(After this patch)

```
taskset -c 2,3 hyperfine "result/bin/nix store gc --dry-run --max 0"
Benchmark 1: result/bin/nix store gc --dry-run --max 0
  Time (mean ± σ):     254.7 ms ±   9.7 ms    [User: 111.1 ms, System: 141.3 ms]
  Range (min … max):   246.5 ms … 281.3 ms    10 runs
```

`boost::regex` is a drop-in replacement for `std::regex`, but much faster.
Doing a simple before/after comparison doesn't surface any change in behavior:

```
result/bin/nix store gc --dry-run -vvvvv --max 0 |& grep "got additional" | wc -l
result-1e822bd4149a8bce1da81ee2ad9404986b07914c/bin/nix store gc --dry-run -vvvvv --max 0 |& grep "got additional" | wc -l
```

(cherry picked from commit 3a1301cd6d)
2025-05-18 19:46:16 +00:00
mergify[bot]
1c618a9d87 Merge pull request #13222 from NixOS/mergify/bp/2.29-maintenance/pr-13221
doc: Render verbatim `@docroot@` on contributing page (backport #13221)
2025-05-17 18:00:31 +00:00
Robert Hensing
ab2abebfc3 doc: Render verbatim @docroot@ on contributing page
In rendered form:

```diff
-Add references to the manual using ..
+Add references to the manual using [links like this](@docroot@/example.md)
```

(cherry picked from commit 147a34c573)
2025-05-17 17:19:51 +00:00
John Ericson
0f132fc129 Merge pull request #13218 from NixOS/mergify/bp/2.29-maintenance/pr-13212
docs: remove repeated "allowedReferences" and other lexical illusion (backport #13212)
2025-05-16 12:36:46 -04:00
Peder Bergebakken Sundt
6fc6db3496 docs: remove lexical illusions detected with write-good
I made this this non-markdown aware tool somewhat behave with some cursed fd+pandoc invocations

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

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

(cherry picked from commit 67535263a5)
2025-05-15 21:49:21 +00:00
Jörg Thalheim
fee8454dd0 Merge pull request #13205 from NixOS/mergify/bp/2.29-maintenance/pr-13202
Fix nix-copy-closure VM test (backport #13202)
2025-05-15 18:34:32 +02:00
Eelco Dolstra
dc238ba102 Fix nix-copy-closure VM test
https://hydra.nixos.org/build/297112538
(cherry picked from commit d626348f42)
2025-05-15 15:51:43 +00:00
mergify[bot]
fa7a5ab07a Merge pull request #13201 from NixOS/mergify/bp/2.29-maintenance/pr-13197
Update Nixpkgs to fix static builds (backport #13197)
2025-05-15 11:48:30 +00:00
Eelco Dolstra
27932ae6da Merge pull request #13199 from NixOS/mergify/bp/2.29-maintenance/pr-13196
rename StoreDirConfigItself to StoreDirConfigBase (backport #13196)
2025-05-15 12:44:09 +02:00
Eelco Dolstra
631d23788e Merge pull request #13198 from NixOS/mergify/bp/2.29-maintenance/pr-13195
Remove otherNixes.nix_2_18 (backport #13195)
2025-05-15 12:24:24 +02:00
Eelco Dolstra
4f03bfebd9 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/f02fddb8acef29a8b32f10a335d44828d7825b78?narHash=sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds%2Bhc%3D' (2025-05-01)
  → 'github:NixOS/nixpkgs/adaa24fbf46737f3f1b5497bf64bae750f82942e?narHash=sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY%3D' (2025-05-13)

(cherry picked from commit 3ba49d7ec2)
2025-05-15 10:21:25 +00:00
Jörg Thalheim
7f488dc7d3 rename StoreDirConfigItself to StoreDirConfigBase
context: https://github.com/NixOS/nix/pull/13154#discussion_r2081904653
(cherry picked from commit 2dd2142754)
2025-05-15 10:04:22 +00:00
Eelco Dolstra
1b2e88effd Remove otherNixes.nix_2_18
Nixpkgs no longer has Nix 2.18, so this fails to evaluate.

(cherry picked from commit bc85e20fb9)
2025-05-15 09:44:21 +00:00
John Ericson
4dcf21a2f6 Merge branch 'master' into 2.29-maintenance 2025-05-14 19:59:35 -04:00
John Ericson
ff24751bdd Mark official release 2025-05-14 19:29:50 -04:00
654 changed files with 26157 additions and 24444 deletions

View File

@@ -8,7 +8,7 @@ BraceWrapping:
AfterUnion: true
SplitEmptyRecord: false
PointerAlignment: Middle
FixNamespaceComments: false
FixNamespaceComments: true
SortIncludes: Never
#IndentPPDirectives: BeforeHash
SpaceAfterCStyleCast: true
@@ -32,3 +32,4 @@ IndentPPDirectives: AfterHash
PPIndentWidth: 2
BinPackArguments: false
BreakBeforeTernaryOperators: true
SeparateDefinitionBlocks: Always

4
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,4 @@
# bulk initial re-formatting with clang-format
0e35cd6f3e27760976ead16fb45008ece0185aad # !autorebase ./maintainers/format.sh --until-stable
# nixfmt 1.0.0
d6aebd884790ae82c21ef2b58a010026ce757eaf # !autorebase ./maintainers/format.sh --until-stable

View File

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

View File

@@ -13,8 +13,14 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: cachix/install-nix-action@v31
- run: nix --experimental-features 'nix-command flakes' flake show --all-systems --json
- uses: ./.github/actions/install-nix-action
with:
dogfood: false
extra_nix_config:
experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
use_cache: false
- run: nix flake show --all-systems --json
tests:
strategy:
@@ -34,13 +40,14 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: cachix/install-nix-action@v31
- uses: ./.github/actions/install-nix-action
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
dogfood: false
# The sandbox would otherwise be disabled by default on Darwin
extra_nix_config: |
sandbox = true
max-jobs = 1
- uses: DeterminateSystems/magic-nix-cache-action@main
# Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
# https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
- run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
@@ -92,91 +99,31 @@ jobs:
- run: exec bash -c "nix-channel --add https://releases.nixos.org/nixos/unstable/nixos-23.05pre466020.60c1d71f2ba nixpkgs"
- run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"
# Steps to test CI automation in your own fork.
# 1. Sign-up for https://hub.docker.com/
# 2. Store your dockerhub username as DOCKERHUB_USERNAME in "Repository secrets" of your fork repository settings (https://github.com/$githubuser/nix/settings/secrets/actions)
# 3. Create an access token in https://hub.docker.com/settings/security and store it as DOCKERHUB_TOKEN in "Repository secrets" of your fork
check_secrets:
permissions:
contents: none
name: Check Docker secrets present for installer tests
runs-on: ubuntu-24.04
outputs:
docker: ${{ steps.secret.outputs.docker }}
steps:
- name: Check for secrets
id: secret
env:
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
run: |
echo "::set-output name=docker::${{ env._DOCKER_SECRETS != '' }}"
docker_push_image:
needs: [tests, vm_tests, check_secrets]
name: Push docker image to DockerHub and GHCR
needs: [tests, vm_tests]
if: github.event_name == 'push' && github.ref_name == 'master'
uses: ./.github/workflows/docker-push.yml
with:
ref: ${{ github.sha }}
is_master: true
permissions:
contents: read
packages: write
if: >-
needs.check_secrets.outputs.docker == 'true' &&
github.event_name == 'push' &&
github.ref_name == 'master'
runs-on: ubuntu-24.04
steps:
- name: Check for secrets
id: secret
env:
_DOCKER_SECRETS: ${{ secrets.DOCKERHUB_USERNAME }}${{ secrets.DOCKERHUB_TOKEN }}
run: |
echo "::set-output name=docker::${{ env._DOCKER_SECRETS != '' }}"
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: cachix/install-nix-action@v31
with:
install_url: https://releases.nixos.org/nix/nix-2.20.3/install
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
- run: nix --experimental-features 'nix-command flakes' build .#dockerImage -L
- run: docker load -i ./result/image.tar.gz
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
# We'll deploy the newly built image to both Docker Hub and Github Container Registry.
#
# Push to Docker Hub first
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
- run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
# Push to GitHub Container Registry as well
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/nix
# Change all uppercase to lowercase
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
docker tag nix:$NIX_VERSION $IMAGE_ID:$NIX_VERSION
docker tag nix:$NIX_VERSION $IMAGE_ID:latest
docker push $IMAGE_ID:$NIX_VERSION
docker push $IMAGE_ID:latest
# deprecated 2024-02-24
docker tag nix:$NIX_VERSION $IMAGE_ID:master
docker push $IMAGE_ID:master
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
vm_tests:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: ./.github/actions/install-nix-action
with:
dogfood: false
extra_nix_config:
experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
- run: |
nix build -L \
.#hydraJobs.tests.functional_user \
@@ -201,6 +148,10 @@ jobs:
with:
repository: NixOS/flake-regressions-data
path: flake-regressions/tests
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: ./.github/actions/install-nix-action
with:
dogfood: false
extra_nix_config:
experimental-features = nix-command flakes
github_token: ${{ secrets.GITHUB_TOKEN }}
- run: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh

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

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

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

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

3
.gitignore vendored
View File

@@ -47,3 +47,6 @@ result-*
.DS_Store
flake-regressions
# direnv
.direnv/

View File

@@ -1 +1 @@
2.29.0
2.29.3

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
ninja,
lowdown-unsandboxed,
mdbook,
mdbook-linkcheck,
jq,
python3,
rsync,
@@ -46,24 +45,22 @@ mkMesonDerivation (finalAttrs: {
];
# Hack for sake of the dev shell
passthru.externalNativeBuildInputs =
[
meson
ninja
(lib.getBin lowdown-unsandboxed)
mdbook
mdbook-linkcheck
jq
python3
rsync
changelog-d
]
++ lib.optionals (!officialRelease) [
# When not an official release, we likely have changelog entries that have
# yet to be rendered.
# When released, these are rendered into a committed file to save a dependency.
changelog-d
];
passthru.externalNativeBuildInputs = [
meson
ninja
(lib.getBin lowdown-unsandboxed)
mdbook
jq
python3
rsync
changelog-d
]
++ lib.optionals (!officialRelease) [
# When not an official release, we likely have changelog entries that have
# yet to be rendered.
# When released, these are rendered into a committed file to save a dependency.
changelog-d
];
nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [
nix-cli

View File

@@ -0,0 +1,17 @@
---
synopsis: Non-flake inputs now contain a `sourceInfo` attribute
issues: 13164
prs: 13170
---
Flakes have always a `sourceInfo` attribute which describes the source of the flake.
The `sourceInfo.outPath` is often identical to the flake's `outPath`, however it can differ when the flake is located in a subdirectory of its source.
Non-flake inputs (i.e. inputs with `flake = false`) can also be located at some path _within_ a wider source.
This usually happens when defining a relative path input within the same source as the parent flake, e.g. `inputs.foo.url = ./some-file.nix`.
Such relative inputs will now inherit their parent's `sourceInfo`.
This also means it is now possible to use `?dir=subdir` on non-flake inputs.
This iterates on the work done in 2.26 to improve relative path support ([#10089](https://github.com/NixOS/nix/pull/10089)),
and resolves a regression introduced in 2.28 relating to nested relative path inputs ([#13164](https://github.com/NixOS/nix/issues/13164)).

View File

@@ -53,6 +53,11 @@ This command has the following operations:
Download the Nix expressions of subscribed channels and create a new generation.
Update all channels if none is specified, and only those included in *names* otherwise.
> **Note**
>
> Downloaded channel contents are cached.
> Use `--tarball-ttl` or the [`tarball-ttl` configuration option](@docroot@/command-ref/conf-file.md#conf-tarball-ttl) to change the validity period of cached downloads.
- `--list-generations`
Prints a list of all the current existing generations for the

View File

@@ -215,14 +215,18 @@ nix build .#nix-everything-x86_64-w64-mingw32
For historic reasons and backward-compatibility, some CPU and OS identifiers are translated as follows:
| `config.guess` | Nix |
|----------------------------|---------------------|
| `amd64` | `x86_64` |
| `i*86` | `i686` |
| `arm6` | `arm6l` |
| `arm7` | `arm7l` |
| `linux-gnu*` | `linux` |
| `linux-musl*` | `linux` |
| `host_machine.cpu_family()` | `host_machine.endian()` | Nix |
|-----------------------------|-------------------------|---------------------|
| `x86` | | `i686` |
| `arm` | | `host_machine.cpu()`|
| `ppc` | `little` | `powerpcle` |
| `ppc64` | `little` | `powerpc64le` |
| `ppc` | `big` | `powerpc` |
| `ppc64` | `big` | `powerpc64` |
| `mips` | `little` | `mipsel` |
| `mips64` | `little` | `mips64el` |
| `mips` | `big` | `mips` |
| `mips64` | `big` | `mips64` |
## Compilation environments

View File

@@ -20,8 +20,9 @@ prs: 1238
Here's one or more paragraphs that describe the change.
- It's markdown
- Add references to the manual using @docroot@
- Add references to the manual using [links like this](@_at_docroot@/example.md)
```
<!-- for the raw markdown readers: that means using @docroot@ -->
Significant changes should add the following header, which moves them to the top.

View File

@@ -25,7 +25,7 @@ This performs the default type of installation for your platform:
We recommend the multi-user installation if it supports your platform and you can authenticate with `sudo`.
The installer can configured with various command line arguments and environment variables.
The installer can be configured with various command line arguments and environment variables.
To show available command line flags:
```console

View File

@@ -73,7 +73,7 @@ Derivations can declare some infrequently used optional attributes.
> **Warning**
>
> If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites),
> If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites),
[`disallowedReferences`](#adv-attr-disallowedReferences) and [`disallowedRequisites`](#adv-attr-disallowedRequisites), maxSize, and maxClosureSize.
will have no effect.

View File

@@ -196,7 +196,7 @@ All comparison operators are implemented in terms of `<`, and the following equi
## Logical implication
Equivalent to `!`*b1* `||` *b2*.
Equivalent to `!`*b1* `||` *b2* (or `if` *b1* `then` *b2* `else true`)
[Logical implication]: #logical-implication

View File

@@ -162,7 +162,7 @@ There are two types of placeholder, corresponding to the two cases where this pr
> **Explanation**
>
> In general, we need to realise [realise] a [store object] in order to be sure to have a store object for it.
> In general, we need to [realise] a [store object] in order to be sure to have a store object for it.
> But for these two cases this is either impossible or impractical:
>
> - In the output case this is impossible:
@@ -189,7 +189,7 @@ This ensures that there is a canonical [store path] used to refer to the derivat
> **Note**
>
> Currently, the canonical encoding for every derivation is the "ATerm" format,
> but this is subject to change for types derivations which are not yet stable.
> but this is subject to change for the types of derivations which are not yet stable.
Regardless of the format used, when serializing a derivation to a store object, that store object will be content-addressed.
@@ -282,7 +282,7 @@ type DerivingPath = ConstantPath | OutputPath;
Under this extended model, `DerivingPath`s are thus inductively built up from a root `ConstantPath`, wrapped with zero or more outer `OutputPath`s.
### Encoding {#deriving-path-encoding}
### Encoding {#deriving-path-encoding-higher-order}
The encoding is adjusted in the natural way, encoding the `drv` field recursively using the same deriving path encoding.
The result of this is that it is possible to have a chain of `^<output-name>` at the end of the final string, as opposed to just a single one.

View File

@@ -23,7 +23,7 @@ The output spec for an output with a fixed content addresses additionally contai
> **Design note**
>
> In principle, the output spec could also specify the references the store object should have, since the references and file system objects are equally parts of a content-addressed store object proper that contribute to its content-addressed.
> However, at this time, the references are not not done because all fixed content-addressed outputs are required to have no references (including no self-reference).
> However, at this time, the references are not done because all fixed content-addressed outputs are required to have no references (including no self-reference).
>
> Also in principle, rather than specifying the references and file system object data with separate hashes, a single hash that constraints both could be used.
> This could be done with the final store path's digest, or better yet, the hash that will become the store path's digest before it is truncated.
@@ -116,7 +116,7 @@ Because the derivation output is not fixed (just like with [input addressing]),
> (The "environment", in this case, consists of attributes such as the Operating System Nix runs atop, along with the operating-system-specific privileges that Nix has been granted.
> Because of how conventional operating systems like macos, Linux, etc. work, granting builders *fewer* privileges may ironically require that Nix be run with *more* privileges.)
That said, derivations producing floating content-addressed outputs may declare their builders as impure (like the builders of derivations producing producing fixed outputs).
That said, derivations producing floating content-addressed outputs may declare their builders as impure (like the builders of derivations producing fixed outputs).
This is provisionally supported as part of the [`impure-derivations`][xp-feature-impure-derivations] experimental feature.
### Compatibility negotiation
@@ -144,7 +144,7 @@ A *deterministic* content-addressing derivation should produce outputs with the
The choice of provisional store path can be thought of as an impurity, since it is an arbitrary choice.
If provisional outputs paths are deterministically chosen, we are in the first branch of part (1).
The builder the data it produces based on it in arbitrary ways, but this gets us closer to to [input addressing].
The builder the data it produces based on it in arbitrary ways, but this gets us closer to [input addressing].
Deterministically choosing the provisional path may be considered "complete sandboxing" by removing an impurity, but this is unsatisfactory
<!--

View File

@@ -83,7 +83,7 @@ The rules for this are fairly concise:
- A content-addressing derivation may be pure or impure
- If it is impure, it may be be fixed (typical), or it may be floating if the additional [`impure-derivations`][xp-feature-impure-derivations] experimental feature is enabled.
- If it is impure, it may be fixed (typical), or it may be floating if the additional [`impure-derivations`][xp-feature-impure-derivations] experimental feature is enabled.
- If it is pure, it must be floating.

View File

@@ -18,14 +18,14 @@ In particular, the edge corresponding to a reference is from the store object th
References other than a self-reference must not form a cycle.
The graph of references excluding self-references thus forms a [directed acyclic graph].
[directed acyclic graph]: @docroot@/glossary.md#gloss-directed acyclic graph
[directed acyclic graph]: @docroot@/glossary.md#gloss-directed-acyclic-graph
We can take the [transitive closure] of the references graph, which any pair of store objects have an edge not if there is a single reference from the first to the second, but a path of one or more references from the first to the second.
The *requisites* of a store object are all store objects reachable by paths of references which start with given store object's references.
[transitive closure]: https://en.wikipedia.org/wiki/Transitive_closure
We can also take the [transpose graph] ofthe references graph, where we reverse the orientation of all edges.
We can also take the [transpose graph] of the references graph, where we reverse the orientation of all edges.
The *referrers* of a store object are the store objects that reference it.
[transpose graph]: https://en.wikipedia.org/wiki/Transpose_graph

View File

@@ -41,6 +41,10 @@ def recursive_replace(data: dict[str, t.Any], book_root: Path, search_path: Path
return data | dict(
sections = [recursive_replace(section, book_root, search_path) for section in sections],
)
case {'items': items}:
return data | dict(
items = [recursive_replace(item, book_root, search_path) for item in items],
)
case {'Chapter': chapter}:
path_to_chapter = Path(chapter['path'])
chapter_content = chapter['content']
@@ -57,6 +61,9 @@ def recursive_replace(data: dict[str, t.Any], book_root: Path, search_path: Path
).replace(
'@docroot@',
("../" * len(path_to_chapter.parent.parts) or "./")[:-1]
).replace(
'@_at_',
'@'
),
sub_items = [
recursive_replace(sub_item, book_root, search_path)

View File

@@ -38,60 +38,58 @@ let
]
++ extraPkgs;
users =
{
users = {
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!)";
};
}
// lib.optionalAttrs (uid != 0) {
"${uname}" = {
uid = uid;
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/home/${uname}";
gid = gid;
groups = [ "${gname}" ];
description = "Nix user";
};
}
// 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)
);
groups =
{
root.gid = 0;
nixbld.gid = 30000;
nobody.gid = 65534;
}
// lib.optionalAttrs (gid != 0) {
"${gname}".gid = gid;
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!)";
};
}
// lib.optionalAttrs (uid != 0) {
"${uname}" = {
uid = uid;
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/home/${uname}";
gid = gid;
groups = [ "${gname}" ];
description = "Nix user";
};
}
// 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)
);
groups = {
root.gid = 0;
nixbld.gid = 30000;
nobody.gid = 65534;
}
// lib.optionalAttrs (gid != 0) {
"${gname}".gid = gid;
};
userToPasswd = (
k:
{
@@ -155,7 +153,7 @@ let
nixConfContents =
(lib.concatStringsSep "\n" (
lib.mapAttrsFlatten (
lib.mapAttrsToList (
n: v:
let
vStr = if builtins.isList v then lib.concatStringsSep " " v else v;
@@ -173,7 +171,12 @@ let
channel = pkgs.runCommand "channel-nixos" { inherit bundleNixpkgs; } ''
mkdir $out
if [ "$bundleNixpkgs" ]; then
ln -s ${nixpkgs} $out/nixpkgs
ln -s ${
builtins.path {
path = nixpkgs;
name = "source";
}
} $out/nixpkgs
echo "[]" > $out/manifest.nix
fi
'';
@@ -275,7 +278,6 @@ let
ln -s ${profile} $out/nix/var/nix/profiles/default-1-link
ln -s /nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default
ln -s /nix/var/nix/profiles/default $out${userHome}/.nix-profile
ln -s ${channel} $out/nix/var/nix/profiles/per-user/${uname}/channels-1-link
ln -s /nix/var/nix/profiles/per-user/${uname}/channels-1-link $out/nix/var/nix/profiles/per-user/${uname}/channels
@@ -327,7 +329,7 @@ pkgs.dockerTools.buildLayeredImageWithNixDb {
'';
config = {
Cmd = [ "${userHome}/.nix-profile/bin/bash" ];
Cmd = [ (lib.getExe pkgs.bashInteractive) ];
User = "${toString uid}:${toString gid}";
Env = [
"USER=${uname}"

8
flake.lock generated
View File

@@ -63,16 +63,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1746141548,
"narHash": "sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds+hc=",
"lastModified": 1756178832,
"narHash": "sha256-O2CIn7HjZwEGqBrwu9EU76zlmA5dbmna7jL1XUmAId8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f02fddb8acef29a8b32f10a335d44828d7825b78",
"rev": "d98ce345cdab58477ca61855540999c86577d19d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"ref": "nixos-25.05-small",
"repo": "nixpkgs",
"type": "github"
}

View File

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

View File

@@ -77,467 +77,6 @@
# Don't format vendored code
''^doc/manual/redirects\.js$''
''^doc/manual/theme/highlight\.js$''
# We haven't applied formatting to these files yet
''^doc/manual/redirects\.js$''
''^doc/manual/theme/highlight\.js$''
''^precompiled-headers\.h$''
''^src/build-remote/build-remote\.cc$''
''^src/libcmd/built-path\.cc$''
''^src/libcmd/include/nix/cmd/built-path\.hh$''
''^src/libcmd/common-eval-args\.cc$''
''^src/libcmd/include/nix/cmd/common-eval-args\.hh$''
''^src/libcmd/editor-for\.cc$''
''^src/libcmd/installable-attr-path\.cc$''
''^src/libcmd/include/nix/cmd/installable-attr-path\.hh$''
''^src/libcmd/installable-derived-path\.cc$''
''^src/libcmd/include/nix/cmd/installable-derived-path\.hh$''
''^src/libcmd/installable-flake\.cc$''
''^src/libcmd/include/nix/cmd/installable-flake\.hh$''
''^src/libcmd/installable-value\.cc$''
''^src/libcmd/include/nix/cmd/installable-value\.hh$''
''^src/libcmd/installables\.cc$''
''^src/libcmd/include/nix/cmd/installables\.hh$''
''^src/libcmd/include/nix/cmd/legacy\.hh$''
''^src/libcmd/markdown\.cc$''
''^src/libcmd/misc-store-flags\.cc$''
''^src/libcmd/repl-interacter\.cc$''
''^src/libcmd/include/nix/cmd/repl-interacter\.hh$''
''^src/libcmd/repl\.cc$''
''^src/libcmd/include/nix/cmd/repl\.hh$''
''^src/libexpr-c/nix_api_expr\.cc$''
''^src/libexpr-c/nix_api_external\.cc$''
''^src/libexpr/attr-path\.cc$''
''^src/libexpr/include/nix/expr/attr-path\.hh$''
''^src/libexpr/attr-set\.cc$''
''^src/libexpr/include/nix/expr/attr-set\.hh$''
''^src/libexpr/eval-cache\.cc$''
''^src/libexpr/include/nix/expr/eval-cache\.hh$''
''^src/libexpr/eval-error\.cc$''
''^src/libexpr/include/nix/expr/eval-inline\.hh$''
''^src/libexpr/eval-settings\.cc$''
''^src/libexpr/include/nix/expr/eval-settings\.hh$''
''^src/libexpr/eval\.cc$''
''^src/libexpr/include/nix/expr/eval\.hh$''
''^src/libexpr/function-trace\.cc$''
''^src/libexpr/include/nix/expr/gc-small-vector\.hh$''
''^src/libexpr/get-drvs\.cc$''
''^src/libexpr/include/nix/expr/get-drvs\.hh$''
''^src/libexpr/json-to-value\.cc$''
''^src/libexpr/nixexpr\.cc$''
''^src/libexpr/include/nix/expr/nixexpr\.hh$''
''^src/libexpr/include/nix/expr/parser-state\.hh$''
''^src/libexpr/primops\.cc$''
''^src/libexpr/include/nix/expr/primops\.hh$''
''^src/libexpr/primops/context\.cc$''
''^src/libexpr/primops/fetchClosure\.cc$''
''^src/libexpr/primops/fetchMercurial\.cc$''
''^src/libexpr/primops/fetchTree\.cc$''
''^src/libexpr/primops/fromTOML\.cc$''
''^src/libexpr/print-ambiguous\.cc$''
''^src/libexpr/include/nix/expr/print-ambiguous\.hh$''
''^src/libexpr/include/nix/expr/print-options\.hh$''
''^src/libexpr/print\.cc$''
''^src/libexpr/include/nix/expr/print\.hh$''
''^src/libexpr/search-path\.cc$''
''^src/libexpr/include/nix/expr/symbol-table\.hh$''
''^src/libexpr/value-to-json\.cc$''
''^src/libexpr/include/nix/expr/value-to-json\.hh$''
''^src/libexpr/value-to-xml\.cc$''
''^src/libexpr/include/nix/expr/value-to-xml\.hh$''
''^src/libexpr/include/nix/expr/value\.hh$''
''^src/libexpr/value/context\.cc$''
''^src/libexpr/include/nix/expr/value/context\.hh$''
''^src/libfetchers/attrs\.cc$''
''^src/libfetchers/cache\.cc$''
''^src/libfetchers/include/nix/fetchers/cache\.hh$''
''^src/libfetchers/fetch-settings\.cc$''
''^src/libfetchers/include/nix/fetchers/fetch-settings\.hh$''
''^src/libfetchers/fetch-to-store\.cc$''
''^src/libfetchers/fetchers\.cc$''
''^src/libfetchers/include/nix/fetchers/fetchers\.hh$''
''^src/libfetchers/filtering-source-accessor\.cc$''
''^src/libfetchers/include/nix/fetchers/filtering-source-accessor\.hh$''
''^src/libfetchers/fs-source-accessor\.cc$''
''^src/libfetchers/include/nix/fs-source-accessor\.hh$''
''^src/libfetchers/git-utils\.cc$''
''^src/libfetchers/include/nix/fetchers/git-utils\.hh$''
''^src/libfetchers/github\.cc$''
''^src/libfetchers/indirect\.cc$''
''^src/libfetchers/memory-source-accessor\.cc$''
''^src/libfetchers/path\.cc$''
''^src/libfetchers/registry\.cc$''
''^src/libfetchers/include/nix/fetchers/registry\.hh$''
''^src/libfetchers/tarball\.cc$''
''^src/libfetchers/include/nix/fetchers/tarball\.hh$''
''^src/libfetchers/git\.cc$''
''^src/libfetchers/mercurial\.cc$''
''^src/libflake/config\.cc$''
''^src/libflake/flake\.cc$''
''^src/libflake/include/nix/flake/flake\.hh$''
''^src/libflake/flakeref\.cc$''
''^src/libflake/include/nix/flake/flakeref\.hh$''
''^src/libflake/lockfile\.cc$''
''^src/libflake/include/nix/flake/lockfile\.hh$''
''^src/libflake/url-name\.cc$''
''^src/libmain/common-args\.cc$''
''^src/libmain/include/nix/main/common-args\.hh$''
''^src/libmain/loggers\.cc$''
''^src/libmain/include/nix/main/loggers\.hh$''
''^src/libmain/progress-bar\.cc$''
''^src/libmain/shared\.cc$''
''^src/libmain/include/nix/main/shared\.hh$''
''^src/libmain/unix/stack\.cc$''
''^src/libstore/binary-cache-store\.cc$''
''^src/libstore/include/nix/store/binary-cache-store\.hh$''
''^src/libstore/include/nix/store/build-result\.hh$''
''^src/libstore/include/nix/store/builtins\.hh$''
''^src/libstore/builtins/buildenv\.cc$''
''^src/libstore/include/nix/store/builtins/buildenv\.hh$''
''^src/libstore/include/nix/store/common-protocol-impl\.hh$''
''^src/libstore/common-protocol\.cc$''
''^src/libstore/include/nix/store/common-protocol\.hh$''
''^src/libstore/include/nix/store/common-ssh-store-config\.hh$''
''^src/libstore/content-address\.cc$''
''^src/libstore/include/nix/store/content-address\.hh$''
''^src/libstore/daemon\.cc$''
''^src/libstore/include/nix/store/daemon\.hh$''
''^src/libstore/derivations\.cc$''
''^src/libstore/include/nix/store/derivations\.hh$''
''^src/libstore/derived-path-map\.cc$''
''^src/libstore/include/nix/store/derived-path-map\.hh$''
''^src/libstore/derived-path\.cc$''
''^src/libstore/include/nix/store/derived-path\.hh$''
''^src/libstore/downstream-placeholder\.cc$''
''^src/libstore/include/nix/store/downstream-placeholder\.hh$''
''^src/libstore/dummy-store\.cc$''
''^src/libstore/export-import\.cc$''
''^src/libstore/filetransfer\.cc$''
''^src/libstore/include/nix/store/filetransfer\.hh$''
''^src/libstore/include/nix/store/gc-store\.hh$''
''^src/libstore/globals\.cc$''
''^src/libstore/include/nix/store/globals\.hh$''
''^src/libstore/http-binary-cache-store\.cc$''
''^src/libstore/legacy-ssh-store\.cc$''
''^src/libstore/include/nix/store/legacy-ssh-store\.hh$''
''^src/libstore/include/nix/store/length-prefixed-protocol-helper\.hh$''
''^src/libstore/linux/personality\.cc$''
''^src/libstore/linux/include/nix/store/personality\.hh$''
''^src/libstore/local-binary-cache-store\.cc$''
''^src/libstore/local-fs-store\.cc$''
''^src/libstore/include/nix/store/local-fs-store\.hh$''
''^src/libstore/log-store\.cc$''
''^src/libstore/include/nix/store/log-store\.hh$''
''^src/libstore/machines\.cc$''
''^src/libstore/include/nix/store/machines\.hh$''
''^src/libstore/make-content-addressed\.cc$''
''^src/libstore/include/nix/store/make-content-addressed\.hh$''
''^src/libstore/misc\.cc$''
''^src/libstore/names\.cc$''
''^src/libstore/include/nix/store/names\.hh$''
''^src/libstore/nar-accessor\.cc$''
''^src/libstore/include/nix/store/nar-accessor\.hh$''
''^src/libstore/nar-info-disk-cache\.cc$''
''^src/libstore/include/nix/store/nar-info-disk-cache\.hh$''
''^src/libstore/nar-info\.cc$''
''^src/libstore/include/nix/store/nar-info\.hh$''
''^src/libstore/outputs-spec\.cc$''
''^src/libstore/include/nix/store/outputs-spec\.hh$''
''^src/libstore/parsed-derivations\.cc$''
''^src/libstore/path-info\.cc$''
''^src/libstore/include/nix/store/path-info\.hh$''
''^src/libstore/path-references\.cc$''
''^src/libstore/include/nix/store/path-regex\.hh$''
''^src/libstore/path-with-outputs\.cc$''
''^src/libstore/path\.cc$''
''^src/libstore/include/nix/store/path\.hh$''
''^src/libstore/pathlocks\.cc$''
''^src/libstore/include/nix/store/pathlocks\.hh$''
''^src/libstore/profiles\.cc$''
''^src/libstore/include/nix/store/profiles\.hh$''
''^src/libstore/realisation\.cc$''
''^src/libstore/include/nix/store/realisation\.hh$''
''^src/libstore/remote-fs-accessor\.cc$''
''^src/libstore/include/nix/store/remote-fs-accessor\.hh$''
''^src/libstore/include/nix/store/remote-store-connection\.hh$''
''^src/libstore/remote-store\.cc$''
''^src/libstore/include/nix/store/remote-store\.hh$''
''^src/libstore/s3-binary-cache-store\.cc$''
''^src/libstore/include/nix/store/s3\.hh$''
''^src/libstore/serve-protocol-impl\.cc$''
''^src/libstore/include/nix/store/serve-protocol-impl\.hh$''
''^src/libstore/serve-protocol\.cc$''
''^src/libstore/include/nix/store/serve-protocol\.hh$''
''^src/libstore/sqlite\.cc$''
''^src/libstore/include/nix/store/sqlite\.hh$''
''^src/libstore/ssh-store\.cc$''
''^src/libstore/ssh\.cc$''
''^src/libstore/include/nix/store/ssh\.hh$''
''^src/libstore/store-api\.cc$''
''^src/libstore/include/nix/store/store-api\.hh$''
''^src/libstore/include/nix/store/store-dir-config\.hh$''
''^src/libstore/build/derivation-goal\.cc$''
''^src/libstore/include/nix/store/build/derivation-goal\.hh$''
''^src/libstore/build/drv-output-substitution-goal\.cc$''
''^src/libstore/include/nix/store/build/drv-output-substitution-goal\.hh$''
''^src/libstore/build/entry-points\.cc$''
''^src/libstore/build/goal\.cc$''
''^src/libstore/include/nix/store/build/goal\.hh$''
''^src/libstore/unix/build/hook-instance\.cc$''
''^src/libstore/unix/build/derivation-builder\.cc$''
''^src/libstore/unix/include/nix/store/build/derivation-builder\.hh$''
''^src/libstore/build/substitution-goal\.cc$''
''^src/libstore/include/nix/store/build/substitution-goal\.hh$''
''^src/libstore/build/worker\.cc$''
''^src/libstore/include/nix/store/build/worker\.hh$''
''^src/libstore/builtins/fetchurl\.cc$''
''^src/libstore/builtins/unpack-channel\.cc$''
''^src/libstore/gc\.cc$''
''^src/libstore/local-overlay-store\.cc$''
''^src/libstore/include/nix/store/local-overlay-store\.hh$''
''^src/libstore/local-store\.cc$''
''^src/libstore/include/nix/store/local-store\.hh$''
''^src/libstore/unix/user-lock\.cc$''
''^src/libstore/unix/include/nix/store/user-lock\.hh$''
''^src/libstore/optimise-store\.cc$''
''^src/libstore/unix/pathlocks\.cc$''
''^src/libstore/posix-fs-canonicalise\.cc$''
''^src/libstore/include/nix/store/posix-fs-canonicalise\.hh$''
''^src/libstore/uds-remote-store\.cc$''
''^src/libstore/include/nix/store/uds-remote-store\.hh$''
''^src/libstore/windows/build\.cc$''
''^src/libstore/include/nix/store/worker-protocol-impl\.hh$''
''^src/libstore/worker-protocol\.cc$''
''^src/libstore/include/nix/store/worker-protocol\.hh$''
''^src/libutil-c/nix_api_util_internal\.h$''
''^src/libutil/archive\.cc$''
''^src/libutil/include/nix/util/archive\.hh$''
''^src/libutil/args\.cc$''
''^src/libutil/include/nix/util/args\.hh$''
''^src/libutil/include/nix/util/args/root\.hh$''
''^src/libutil/include/nix/util/callback\.hh$''
''^src/libutil/canon-path\.cc$''
''^src/libutil/include/nix/util/canon-path\.hh$''
''^src/libutil/include/nix/util/chunked-vector\.hh$''
''^src/libutil/include/nix/util/closure\.hh$''
''^src/libutil/include/nix/util/comparator\.hh$''
''^src/libutil/compute-levels\.cc$''
''^src/libutil/include/nix/util/config-impl\.hh$''
''^src/libutil/configuration\.cc$''
''^src/libutil/include/nix/util/configuration\.hh$''
''^src/libutil/current-process\.cc$''
''^src/libutil/include/nix/util/current-process\.hh$''
''^src/libutil/english\.cc$''
''^src/libutil/include/nix/util/english\.hh$''
''^src/libutil/error\.cc$''
''^src/libutil/include/nix/util/error\.hh$''
''^src/libutil/include/nix/util/exit\.hh$''
''^src/libutil/experimental-features\.cc$''
''^src/libutil/include/nix/util/experimental-features\.hh$''
''^src/libutil/file-content-address\.cc$''
''^src/libutil/include/nix/util/file-content-address\.hh$''
''^src/libutil/file-descriptor\.cc$''
''^src/libutil/include/nix/util/file-descriptor\.hh$''
''^src/libutil/include/nix/util/file-path-impl\.hh$''
''^src/libutil/include/nix/util/file-path\.hh$''
''^src/libutil/file-system\.cc$''
''^src/libutil/include/nix/util/file-system\.hh$''
''^src/libutil/include/nix/util/finally\.hh$''
''^src/libutil/include/nix/util/fmt\.hh$''
''^src/libutil/fs-sink\.cc$''
''^src/libutil/include/nix/util/fs-sink\.hh$''
''^src/libutil/git\.cc$''
''^src/libutil/include/nix/util/git\.hh$''
''^src/libutil/hash\.cc$''
''^src/libutil/include/nix/util/hash\.hh$''
''^src/libutil/hilite\.cc$''
''^src/libutil/include/nix/util/hilite\.hh$''
''^src/libutil/source-accessor\.hh$''
''^src/libutil/include/nix/util/json-impls\.hh$''
''^src/libutil/json-utils\.cc$''
''^src/libutil/include/nix/util/json-utils\.hh$''
''^src/libutil/linux/cgroup\.cc$''
''^src/libutil/linux/namespaces\.cc$''
''^src/libutil/logging\.cc$''
''^src/libutil/include/nix/util/logging\.hh$''
''^src/libutil/memory-source-accessor\.cc$''
''^src/libutil/include/nix/util/memory-source-accessor\.hh$''
''^src/libutil/include/nix/util/pool\.hh$''
''^src/libutil/position\.cc$''
''^src/libutil/include/nix/util/position\.hh$''
''^src/libutil/posix-source-accessor\.cc$''
''^src/libutil/include/nix/util/posix-source-accessor\.hh$''
''^src/libutil/include/nix/util/processes\.hh$''
''^src/libutil/include/nix/util/ref\.hh$''
''^src/libutil/references\.cc$''
''^src/libutil/include/nix/util/references\.hh$''
''^src/libutil/regex-combinators\.hh$''
''^src/libutil/serialise\.cc$''
''^src/libutil/include/nix/util/serialise\.hh$''
''^src/libutil/include/nix/util/signals\.hh$''
''^src/libutil/signature/local-keys\.cc$''
''^src/libutil/include/nix/util/signature/local-keys\.hh$''
''^src/libutil/signature/signer\.cc$''
''^src/libutil/include/nix/util/signature/signer\.hh$''
''^src/libutil/source-accessor\.cc$''
''^src/libutil/include/nix/util/source-accessor\.hh$''
''^src/libutil/source-path\.cc$''
''^src/libutil/include/nix/util/source-path\.hh$''
''^src/libutil/include/nix/util/split\.hh$''
''^src/libutil/suggestions\.cc$''
''^src/libutil/include/nix/util/suggestions\.hh$''
''^src/libutil/include/nix/util/sync\.hh$''
''^src/libutil/terminal\.cc$''
''^src/libutil/include/nix/util/terminal\.hh$''
''^src/libutil/thread-pool\.cc$''
''^src/libutil/include/nix/util/thread-pool\.hh$''
''^src/libutil/include/nix/util/topo-sort\.hh$''
''^src/libutil/include/nix/util/types\.hh$''
''^src/libutil/unix/file-descriptor\.cc$''
''^src/libutil/unix/file-path\.cc$''
''^src/libutil/unix/processes\.cc$''
''^src/libutil/unix/include/nix/util/signals-impl\.hh$''
''^src/libutil/unix/signals\.cc$''
''^src/libutil/unix-domain-socket\.cc$''
''^src/libutil/unix/users\.cc$''
''^src/libutil/include/nix/util/url-parts\.hh$''
''^src/libutil/url\.cc$''
''^src/libutil/include/nix/util/url\.hh$''
''^src/libutil/users\.cc$''
''^src/libutil/include/nix/util/users\.hh$''
''^src/libutil/util\.cc$''
''^src/libutil/include/nix/util/util\.hh$''
''^src/libutil/include/nix/util/variant-wrapper\.hh$''
''^src/libutil/widecharwidth/widechar_width\.h$'' # vendored source
''^src/libutil/windows/file-descriptor\.cc$''
''^src/libutil/windows/file-path\.cc$''
''^src/libutil/windows/processes\.cc$''
''^src/libutil/windows/users\.cc$''
''^src/libutil/windows/windows-error\.cc$''
''^src/libutil/windows/include/nix/util/windows-error\.hh$''
''^src/libutil/xml-writer\.cc$''
''^src/libutil/include/nix/util/xml-writer\.hh$''
''^src/nix-build/nix-build\.cc$''
''^src/nix-channel/nix-channel\.cc$''
''^src/nix-collect-garbage/nix-collect-garbage\.cc$''
''^src/nix-env/buildenv.nix$''
''^src/nix-env/nix-env\.cc$''
''^src/nix-env/user-env\.cc$''
''^src/nix-env/user-env\.hh$''
''^src/nix-instantiate/nix-instantiate\.cc$''
''^src/nix-store/dotgraph\.cc$''
''^src/nix-store/graphml\.cc$''
''^src/nix-store/nix-store\.cc$''
''^src/nix/add-to-store\.cc$''
''^src/nix/app\.cc$''
''^src/nix/build\.cc$''
''^src/nix/bundle\.cc$''
''^src/nix/cat\.cc$''
''^src/nix/config-check\.cc$''
''^src/nix/config\.cc$''
''^src/nix/copy\.cc$''
''^src/nix/derivation-add\.cc$''
''^src/nix/derivation-show\.cc$''
''^src/nix/derivation\.cc$''
''^src/nix/develop\.cc$''
''^src/nix/diff-closures\.cc$''
''^src/nix/dump-path\.cc$''
''^src/nix/edit\.cc$''
''^src/nix/eval\.cc$''
''^src/nix/flake\.cc$''
''^src/nix/fmt\.cc$''
''^src/nix/hash\.cc$''
''^src/nix/log\.cc$''
''^src/nix/ls\.cc$''
''^src/nix/main\.cc$''
''^src/nix/make-content-addressed\.cc$''
''^src/nix/nar\.cc$''
''^src/nix/optimise-store\.cc$''
''^src/nix/path-from-hash-part\.cc$''
''^src/nix/path-info\.cc$''
''^src/nix/prefetch\.cc$''
''^src/nix/profile\.cc$''
''^src/nix/realisation\.cc$''
''^src/nix/registry\.cc$''
''^src/nix/repl\.cc$''
''^src/nix/run\.cc$''
''^src/nix/run\.hh$''
''^src/nix/search\.cc$''
''^src/nix/sigs\.cc$''
''^src/nix/store-copy-log\.cc$''
''^src/nix/store-delete\.cc$''
''^src/nix/store-gc\.cc$''
''^src/nix/store-info\.cc$''
''^src/nix/store-repair\.cc$''
''^src/nix/store\.cc$''
''^src/nix/unix/daemon\.cc$''
''^src/nix/upgrade-nix\.cc$''
''^src/nix/verify\.cc$''
''^src/nix/why-depends\.cc$''
''^tests/functional/plugins/plugintest\.cc''
''^tests/functional/test-libstoreconsumer/main\.cc''
''^tests/nixos/ca-fd-leak/sender\.c''
''^tests/nixos/ca-fd-leak/smuggler\.c''
''^tests/nixos/user-sandboxing/attacker\.c''
''^src/libexpr-test-support/include/nix/expr/tests/libexpr\.hh''
''^src/libexpr-test-support/tests/value/context\.cc''
''^src/libexpr-test-support/include/nix/expr/tests/value/context\.hh''
''^src/libexpr-tests/derived-path\.cc''
''^src/libexpr-tests/error_traces\.cc''
''^src/libexpr-tests/eval\.cc''
''^src/libexpr-tests/json\.cc''
''^src/libexpr-tests/main\.cc''
''^src/libexpr-tests/primops\.cc''
''^src/libexpr-tests/search-path\.cc''
''^src/libexpr-tests/trivial\.cc''
''^src/libexpr-tests/value/context\.cc''
''^src/libexpr-tests/value/print\.cc''
''^src/libfetchers-tests/public-key\.cc''
''^src/libflake-tests/flakeref\.cc''
''^src/libflake-tests/url-name\.cc''
''^src/libstore-test-support/tests/derived-path\.cc''
''^src/libstore-test-support/include/nix/store/tests/derived-path\.hh''
''^src/libstore-test-support/include/nix/store/tests/nix_api_store\.hh''
''^src/libstore-test-support/tests/outputs-spec\.cc''
''^src/libstore-test-support/include/nix/store/tests/outputs-spec\.hh''
''^src/libstore-test-support/path\.cc''
''^src/libstore-test-support/include/nix/store/tests/path\.hh''
''^src/libstore-test-support/include/nix/store/tests/protocol\.hh''
''^src/libstore-tests/common-protocol\.cc''
''^src/libstore-tests/content-address\.cc''
''^src/libstore-tests/derivation\.cc''
''^src/libstore-tests/derived-path\.cc''
''^src/libstore-tests/downstream-placeholder\.cc''
''^src/libstore-tests/machines\.cc''
''^src/libstore-tests/nar-info-disk-cache\.cc''
''^src/libstore-tests/nar-info\.cc''
''^src/libstore-tests/outputs-spec\.cc''
''^src/libstore-tests/path-info\.cc''
''^src/libstore-tests/path\.cc''
''^src/libstore-tests/serve-protocol\.cc''
''^src/libstore-tests/worker-protocol\.cc''
''^src/libutil-test-support/include/nix/util/tests/characterization\.hh''
''^src/libutil-test-support/hash\.cc''
''^src/libutil-test-support/include/nix/util/tests/hash\.hh''
''^src/libutil-tests/args\.cc''
''^src/libutil-tests/canon-path\.cc''
''^src/libutil-tests/chunked-vector\.cc''
''^src/libutil-tests/closure\.cc''
''^src/libutil-tests/compression\.cc''
''^src/libutil-tests/config\.cc''
''^src/libutil-tests/file-content-address\.cc''
''^src/libutil-tests/git\.cc''
''^src/libutil-tests/hash\.cc''
''^src/libutil-tests/hilite\.cc''
''^src/libutil-tests/json-utils\.cc''
''^src/libutil-tests/logging\.cc''
''^src/libutil-tests/lru-cache\.cc''
''^src/libutil-tests/pool\.cc''
''^src/libutil-tests/references\.cc''
''^src/libutil-tests/suggestions\.cc''
''^src/libutil-tests/url\.cc''
''^src/libutil-tests/xml-writer\.cc''
];
};
shellcheck = {

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env bash
if ! type -p pre-commit &>/dev/null; then
echo "format.sh: pre-commit not found. Please use \`nix develop\`.";
echo "format.sh: pre-commit not found. Please use \`nix develop -c ./maintainers/format.sh\`.";
exit 1;
fi;
if test -z "$_NIX_PRE_COMMIT_HOOKS_CONFIG"; then
echo "format.sh: _NIX_PRE_COMMIT_HOOKS_CONFIG not set. Please use \`nix develop\`.";
echo "format.sh: _NIX_PRE_COMMIT_HOOKS_CONFIG not set. Please use \`nix develop -c ./maintainers/format.sh\`.";
exit 1;
fi;
pre-commit run --config "$_NIX_PRE_COMMIT_HOOKS_CONFIG" --all-files
while ! pre-commit run --config "$_NIX_PRE_COMMIT_HOOKS_CONFIG" --all-files; do
if [ "${1:-}" != "--until-stable" ]; then
exit 1
fi
done

View File

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

View File

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

View File

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

View File

@@ -5,11 +5,11 @@
The release process is intended to create the following for each
release:
* A Git tag
* A signed Git tag (public keys in `maintainers/keys/`)
* Binary tarballs in https://releases.nixos.org/?prefix=nix/
* Docker images
* Docker images (arm64 and amd64 variants, uploaded to DockerHub and GHCR)
* Closures in https://cache.nixos.org
@@ -101,21 +101,17 @@ release:
evaluation ID (e.g. `1780832` in
`https://hydra.nixos.org/eval/1780832`).
* Tag the release and upload the release artifacts to
[`releases.nixos.org`](https://releases.nixos.org/) and [Docker Hub](https://hub.docker.com/):
* Tag the release:
```console
$ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID>
$ IS_LATEST=1 ./maintainers/upload-release.pl --skip-docker --skip-s3 --project-root $PWD <EVAL-ID>
```
Note: `IS_LATEST=1` causes the `latest-release` branch to be
force-updated. This is used by the `nixos.org` website to get the
[latest Nix manual](https://nixos.org/manual/nixpkgs/unstable/).
TODO: This script requires the right AWS credentials. Document.
TODO: This script currently requires a
`/home/eelco/Dev/nix-pristine`.
* Trigger the [`upload-release.yml` workflow](https://github.com/NixOS/nix/actions/workflows/upload-release.yml) via `workflow_dispatch` trigger. At the top click `Run workflow` -> select the current release branch from `Use workflow from` -> fill in `Hydra evaluation ID` with `<EVAL-ID>` value from previous steps -> click `Run workflow`. Wait for the run to be approved by `NixOS/nix-team` (or bypass checks if warranted). Wait for the workflow to succeed.
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
@@ -180,16 +176,18 @@ release:
* Wait for the desired evaluation of the maintenance jobset to finish
building.
* Run
* Tag the release
```console
$ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID>
$ IS_LATEST=1 ./maintainers/upload-release.pl --skip-docker --skip-s3 --project-root $PWD <EVAL-ID>
```
Omit `IS_LATEST=1` when creating a point release that is not on the
most recent stable branch. This prevents `nixos.org` to going back
to an older release.
* Trigger the [`upload-release.yml` workflow](https://github.com/NixOS/nix/actions/workflows/upload-release.yml) via `workflow_dispatch` trigger. At the top click `Run workflow` -> select the current release branch from `Use workflow from` -> fill in `Hydra evaluation ID` with `<EVAL-ID>` value from previous steps -> click `Run workflow`. Wait for the run to be approved by `NixOS/nix-team` (or bypass checks if warranted). Wait for the workflow to succeed.
* Bump the version number of the release branch as above (e.g. to
`2.12.2`).

View File

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

View File

@@ -0,0 +1,19 @@
# This attempts to translate meson cpu_family and cpu_name specified via
# --cross-file [1] into a nix *system double*. Nixpkgs mostly respects ([2]) the
# conventions outlined in [1].
#
# [1]: https://mesonbuild.com/Reference-tables.html#cpu-families
# [2]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/lib/meson.nix
nix_system_cpu = {'ppc64' : 'powerpc64', 'ppc' : 'powerpc', 'x86' : 'i686'}.get(
host_machine.cpu_family(),
host_machine.cpu_family(),
)
if (host_machine.cpu_family() in [ 'ppc64', 'ppc' ]) and host_machine.endian() == 'little'
nix_system_cpu += 'le'
elif host_machine.cpu_family() in [ 'mips64', 'mips' ] and host_machine.endian() == 'little'
nix_system_cpu += 'el'
elif host_machine.cpu_family() == 'arm'
nix_system_cpu = host_machine.cpu()
endif

View File

@@ -11,12 +11,18 @@ endforeach
requires_public += deps_public
extra_pkg_config_variables = get_variable('extra_pkg_config_variables', {})
extra_cflags = []
if not meson.project_name().endswith('-c')
extra_cflags += ['-std=c++2a']
endif
import('pkgconfig').generate(
this_library,
filebase : meson.project_name(),
name : 'Nix',
description : 'Nix Package Manager',
extra_cflags : ['-std=c++2a'],
extra_cflags : extra_cflags,
requires : requires_public,
requires_private : requires_private,
libraries_private : libraries_private,

View File

@@ -54,12 +54,12 @@ let
preConfigure =
prevAttrs.preConfigure or ""
+
# Update the repo-global .version file.
# Symlink ./.version points there, but by default only workDir is writable.
''
chmod u+w ./.version
echo ${finalAttrs.version} > ./.version
'';
# Update the repo-global .version file.
# Symlink ./.version points there, but by default only workDir is writable.
''
chmod u+w ./.version
echo ${finalAttrs.version} > ./.version
'';
};
localSourceLayer =
@@ -148,7 +148,8 @@ let
nativeBuildInputs = [
meson
ninja
] ++ prevAttrs.nativeBuildInputs or [ ];
]
++ prevAttrs.nativeBuildInputs or [ ];
mesonCheckFlags = prevAttrs.mesonCheckFlags or [ ] ++ [
"--print-errorlogs"
];
@@ -166,6 +167,17 @@ let
outputs = prevAttrs.outputs or [ "out" ] ++ [ "dev" ];
};
fixupStaticLayer = finalAttrs: prevAttrs: {
postFixup =
prevAttrs.postFixup or ""
+ lib.optionalString (stdenv.hostPlatform.isStatic) ''
# HACK: Otherwise the result will have the entire buildInputs closure
# injected by the pkgsStatic stdenv
# <https://github.com/NixOS/nixpkgs/issues/83667>
rm -f $out/nix-support/propagated-build-inputs
'';
};
# Work around weird `--as-needed` linker behavior with BSD, see
# https://github.com/mesonbuild/meson/issues/3593
bsdNoLinkAsNeeded =
@@ -301,6 +313,7 @@ in
scope.sourceLayer
setVersionLayer
mesonLayer
fixupStaticLayer
scope.mesonComponentOverrides
];
mkMesonExecutable = mkPackageBuilder [
@@ -310,6 +323,7 @@ in
setVersionLayer
mesonLayer
mesonBuildLayer
fixupStaticLayer
scope.mesonComponentOverrides
];
mkMesonLibrary = mkPackageBuilder [
@@ -320,6 +334,7 @@ in
setVersionLayer
mesonBuildLayer
mesonLibraryLayer
fixupStaticLayer
scope.mesonComponentOverrides
];

View File

@@ -63,6 +63,7 @@ scope: {
"--with-coroutine"
"--with-iostreams"
];
enableIcu = false;
}).overrideAttrs
(old: {
# Need to remove `--with-*` to use `--with-libraries=...`

View File

@@ -71,17 +71,16 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
# We use this shell with the local checkout, not unpackPhase.
src = null;
env =
{
# For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
modular.pre-commit.settings.rawConfig
}";
}
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
CC_LD = "mold";
CXX_LD = "mold";
};
env = {
# For `make format`, to work without installing pre-commit
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
modular.pre-commit.settings.rawConfig
}";
}
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
CC_LD = "mold";
CXX_LD = "mold";
};
mesonFlags =
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
@@ -113,15 +112,13 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
) pkgs.buildPackages.mesonEmulatorHook
++ [
pkgs.buildPackages.cmake
pkgs.buildPackages.gnused
pkgs.buildPackages.shellcheck
pkgs.buildPackages.changelog-d
modular.pre-commit.settings.package
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
pkgs.buildPackages.nixfmt-rfc-style
]
# TODO: Remove the darwin check once
# https://github.com/NixOS/nixpkgs/pull/291814 is available
++ lib.optional (stdenv.cc.isClang && !stdenv.buildPlatform.isDarwin) pkgs.buildPackages.bear
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
lib.hiPrio pkgs.buildPackages.clang-tools
)

View File

@@ -47,25 +47,25 @@
}:
let
libs =
{
inherit
nix-util
nix-util-c
nix-store
nix-store-c
nix-fetchers
nix-fetchers-c
nix-expr
nix-expr-c
nix-flake
nix-flake-c
nix-main
nix-main-c
nix-cmd
;
}
// lib.optionalAttrs
libs = {
inherit
nix-util
nix-util-c
nix-store
nix-store-c
nix-fetchers
nix-fetchers-c
nix-expr
nix-expr-c
nix-flake
nix-flake-c
nix-main
nix-main-c
nix-cmd
;
}
//
lib.optionalAttrs
(!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
{
# Currently fails in static build
@@ -127,20 +127,19 @@ stdenv.mkDerivation (finalAttrs: {
*/
dontFixup = true;
checkInputs =
[
# Make sure the unit tests have passed
nix-util-tests.tests.run
nix-store-tests.tests.run
nix-expr-tests.tests.run
nix-fetchers-tests.tests.run
nix-flake-tests.tests.run
checkInputs = [
# Make sure the unit tests have passed
nix-util-tests.tests.run
nix-store-tests.tests.run
nix-expr-tests.tests.run
nix-fetchers-tests.tests.run
nix-flake-tests.tests.run
# Make sure the functional tests have passed
nix-functional-tests
]
++ lib.optionals
(!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
# Make sure the functional tests have passed
nix-functional-tests
]
++
lib.optionals (!stdenv.hostPlatform.isStatic && stdenv.buildPlatform.canExecute stdenv.hostPlatform)
[
# Perl currently fails in static build
# TODO: Split out tests into a separate derivation?

View File

@@ -49,15 +49,15 @@
#include <unistd.h>
#ifndef _WIN32
# include <grp.h>
# include <netdb.h>
# include <pwd.h>
# include <sys/resource.h>
# include <sys/select.h>
# include <sys/socket.h>
# include <sys/utsname.h>
# include <sys/wait.h>
# include <termios.h>
# include <grp.h>
# include <netdb.h>
# include <pwd.h>
# include <sys/resource.h>
# include <sys/select.h>
# include <sys/socket.h>
# include <sys/utsname.h>
# include <sys/wait.h>
# include <termios.h>
#endif
#include <nlohmann/json.hpp>

View File

@@ -1,17 +1,16 @@
# Only execute this file once per shell.
if test -z "$HOME" || \
test -n "$__ETC_PROFILE_NIX_SOURCED"
if test -z "$HOME" || test -n "$__ETC_PROFILE_NIX_SOURCED"
exit
end
set --global __ETC_PROFILE_NIX_SOURCED 1
set --global --export __ETC_PROFILE_NIX_SOURCED 1
# Local helpers
function add_path --argument-names new_path
if type -q fish_add_path
# fish 3.2.0 or newer
fish_add_path --prepend --global $new_path
fish_add_path --prepend --global $new_path
else
# older versions of fish
if not contains $new_path $fish_user_paths
@@ -24,7 +23,33 @@ end
# Set up the per-user profile.
set --local NIX_LINK $HOME/.nix-profile
set --local NIX_LINK "$HOME/.nix-profile"
set --local NIX_LINK_NEW
if test -n "$XDG_STATE_HOME"
set NIX_LINK_NEW "$XDG_STATE_HOME/nix/profile"
else
set NIX_LINK_NEW "$HOME/.local/state/nix/profile"
end
if test -e "$NIX_LINK_NEW"
if test -t 2; and test -e "$NIX_LINK"
set --local warning "\033[1;35mwarning:\033[0m "
printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
if test (realpath "$NIX_LINK") = (realpath "$NIX_LINK_NEW")
printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
else
# This should be an exceptionally rare occasion: the only way to get it would be to
# 1. Update to newer Nix;
# 2. Remove .nix-profile;
# 3. Set the $NIX_LINK_NEW to something other than the default user profile;
# 4. Roll back to older Nix.
# If someone did all that, they can probably figure out how to migrate the profile.
printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
end
end
set NIX_LINK "$NIX_LINK_NEW"
end
# Set up environment.
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix

View File

@@ -1,17 +1,16 @@
# Only execute this file once per shell.
if test -z "$HOME" || \
test -n "$__ETC_PROFILE_NIX_SOURCED"
if test -z "$HOME" || test -n "$__ETC_PROFILE_NIX_SOURCED"
exit
end
set --global __ETC_PROFILE_NIX_SOURCED 1
set --global --export __ETC_PROFILE_NIX_SOURCED 1
# Local helpers
function add_path --argument-names new_path
if type -q fish_add_path
# fish 3.2.0 or newer
fish_add_path --prepend --global $new_path
fish_add_path --prepend --global $new_path
else
# older versions of fish
if not contains $new_path $fish_user_paths
@@ -24,7 +23,38 @@ end
# Set up the per-user profile.
set --local NIX_LINK $HOME/.nix-profile
set --local NIX_LINK
if test -n "$NIX_STATE_HOME"
set NIX_LINK "$NIX_STATE_HOME/.nix-profile"
else
set NIX_LINK "$HOME/.nix-profile"
set --local NIX_LINK_NEW
if test -n "$XDG_STATE_HOME"
set NIX_LINK_NEW "$XDG_STATE_HOME/nix/profile"
else
set NIX_LINK_NEW "$HOME/.local/state/nix/profile"
end
if test -e "$NIX_LINK_NEW"
if test -t 2; and test -e "$NIX_LINK"
set --local warning "\033[1;35mwarning:\033[0m "
printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
if test (realpath "$NIX_LINK") = (realpath "$NIX_LINK_NEW")
printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
else
# This should be an exceptionally rare occasion: the only way to get it would be to
# 1. Update to newer Nix;
# 2. Remove .nix-profile;
# 3. Set the $NIX_LINK_NEW to something other than the default user profile;
# 4. Roll back to older Nix.
# If someone did all that, they can probably figure out how to migrate the profile.
printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
end
end
set NIX_LINK "$NIX_LINK_NEW"
end
end
# Set up environment.
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix

View File

@@ -6,7 +6,7 @@
#include <tuple>
#include <iomanip>
#ifdef __APPLE__
#include <sys/time.h>
# include <sys/time.h>
#endif
#include "nix/store/machines.hh"
@@ -26,8 +26,7 @@
using namespace nix;
using std::cin;
static void handleAlarm(int sig) {
}
static void handleAlarm(int sig) {}
std::string escapeUri(std::string uri)
{
@@ -42,13 +41,15 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri.render()), slot), true);
}
static bool allSupportedLocally(Store & store, const StringSet& requiredFeatures) {
static bool allSupportedLocally(Store & store, const StringSet & requiredFeatures)
{
for (auto & feature : requiredFeatures)
if (!store.config.systemFeatures.get().count(feature)) return false;
if (!store.config.systemFeatures.get().count(feature))
return false;
return true;
}
static int main_build_remote(int argc, char * * argv)
static int main_build_remote(int argc, char ** argv)
{
{
logger = makeJSONLogger(getStandardError());
@@ -85,7 +86,7 @@ static int main_build_remote(int argc, char * * argv)
that gets cleared on reboot, but it wouldn't work on macOS. */
auto currentLoadName = "/current-load";
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
currentLoad = std::string { localStore->config.stateDir } + currentLoadName;
currentLoad = std::string{localStore->config.stateDir} + currentLoadName;
else
currentLoad = settings.nixStateDir + currentLoadName;
@@ -107,8 +108,11 @@ static int main_build_remote(int argc, char * * argv)
try {
auto s = readString(source);
if (s != "try") return 0;
} catch (EndOfFile &) { return 0; }
if (s != "try")
return 0;
} catch (EndOfFile &) {
return 0;
}
auto amWilling = readInt(source);
auto neededSystem = readString(source);
@@ -117,10 +121,10 @@ static int main_build_remote(int argc, char * * argv)
/* 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);
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;
@@ -139,11 +143,8 @@ static int main_build_remote(int argc, char * * argv)
for (auto & m : machines) {
debug("considering building on remote machine '%s'", m.storeUri.render());
if (m.enabled &&
m.systemSupported(neededSystem) &&
m.allSupported(requiredFeatures) &&
m.mandatoryMet(requiredFeatures))
{
if (m.enabled && m.systemSupported(neededSystem) && m.allSupported(requiredFeatures)
&& m.mandatoryMet(requiredFeatures)) {
rightType = true;
AutoCloseFD free;
uint64_t load = 0;
@@ -185,8 +186,7 @@ static int main_build_remote(int argc, char * * argv)
if (!bestSlotLock) {
if (rightType && !canBuildLocally)
std::cerr << "# postpone\n";
else
{
else {
// build the hint template.
std::string errorText =
"Failed to find a machine for remote build!\n"
@@ -205,16 +205,11 @@ static int main_build_remote(int argc, char * * argv)
drvstr = "<unknown>";
auto error = HintFmt::fromFormatString(errorText);
error
% drvstr
% neededSystem
% concatStringsSep<StringSet>(", ", requiredFeatures)
error % drvstr % neededSystem % concatStringsSep<StringSet>(", ", requiredFeatures)
% machines.size();
for (auto & m : machines)
error
% concatStringsSep<StringSet>(", ", m.systemTypes)
% m.maxJobs
error % concatStringsSep<StringSet>(", ", m.systemTypes) % m.maxJobs
% concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
@@ -242,9 +237,7 @@ static int main_build_remote(int argc, char * * argv)
sshStore->connect();
} catch (std::exception & e) {
auto msg = chomp(drainFD(5, false));
printError("cannot build on '%s': %s%s",
storeUri, e.what(),
msg.empty() ? "" : ": " + msg);
printError("cannot build on '%s': %s%s", storeUri, e.what(), msg.empty() ? "" : ": " + msg);
bestMachine->enabled = false;
continue;
}
@@ -253,7 +246,7 @@ static int main_build_remote(int argc, char * * argv)
}
}
connected:
connected:
close(5);
assert(sshStore);
@@ -265,13 +258,14 @@ connected:
AutoCloseFD uploadLock;
{
auto setUpdateLock = [&](auto && fileName){
auto setUpdateLock = [&](auto && fileName) {
uploadLock = openLockFile(currentLoad + "/" + escapeUri(fileName) + ".upload-lock", true);
};
try {
setUpdateLock(storeUri);
} catch (SysError & e) {
if (e.errNo != ENAMETOOLONG) throw;
if (e.errNo != ENAMETOOLONG)
throw;
// Try again hashing the store URL so we have a shorter path
auto h = hashString(HashAlgorithm::MD5, storeUri);
setUpdateLock(h.to_string(HashFormat::Base64, false));
@@ -315,7 +309,7 @@ connected:
//
// This condition mirrors that: that code enforces the "rules" outlined there;
// we do the best we can given those "rules".
if (trustedOrLegacy || drv.type().isCA()) {
if (trustedOrLegacy || drv.type().isCA()) {
// Hijack the inputs paths of the derivation to include all
// the paths that come from the `inputDrvs` set. We dont do
// that for the derivations whose `inputDrvs` is empty
@@ -330,28 +324,26 @@ connected:
optResult = sshStore->buildDerivation(*drvPath, (const BasicDerivation &) drv);
auto & result = *optResult;
if (!result.success())
throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
throw Error(
"build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
} else {
copyClosure(*store, *sshStore, StorePathSet {*drvPath}, NoRepair, NoCheckSigs, substitute);
auto res = sshStore->buildPathsWithResults({
DerivedPath::Built {
.drvPath = makeConstantStorePathRef(*drvPath),
.outputs = OutputsSpec::All {},
}
});
copyClosure(*store, *sshStore, StorePathSet{*drvPath}, NoRepair, NoCheckSigs, substitute);
auto res = sshStore->buildPathsWithResults({DerivedPath::Built{
.drvPath = makeConstantStorePathRef(*drvPath),
.outputs = OutputsSpec::All{},
}});
// One path to build should produce exactly one build result
assert(res.size() == 1);
optResult = std::move(res[0]);
}
auto outputHashes = staticOutputHashes(*store, drv);
std::set<Realisation> missingRealisations;
StorePathSet missingPaths;
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) {
for (auto & outputName : wantedOutputs) {
auto thisOutputHash = outputHashes.at(outputName);
auto thisOutputId = DrvOutput{ thisOutputHash, outputName };
auto thisOutputId = DrvOutput{thisOutputHash, outputName};
if (!store->queryRealisation(thisOutputId)) {
debug("missing output %s", outputName);
assert(optResult);

View File

@@ -10,23 +10,13 @@
namespace nix {
// Custom implementation to avoid `ref` ptr equality
GENERATE_CMP_EXT(
,
std::strong_ordering,
SingleBuiltPathBuilt,
*me->drvPath,
me->output);
GENERATE_CMP_EXT(, std::strong_ordering, SingleBuiltPathBuilt, *me->drvPath, me->output);
// Custom implementation to avoid `ref` ptr equality
// TODO no `GENERATE_CMP_EXT` because no `std::set::operator<=>` on
// Darwin, per header.
GENERATE_EQUAL(
,
BuiltPathBuilt ::,
BuiltPathBuilt,
*me->drvPath,
me->outputs);
GENERATE_EQUAL(, BuiltPathBuilt ::, BuiltPathBuilt, *me->drvPath, me->outputs);
StorePath SingleBuiltPath::outPath() const
{
@@ -34,8 +24,8 @@ StorePath SingleBuiltPath::outPath() const
overloaded{
[](const SingleBuiltPath::Opaque & p) { return p.path; },
[](const SingleBuiltPath::Built & b) { return b.output.second; },
}, raw()
);
},
raw());
}
StorePathSet BuiltPath::outPaths() const
@@ -49,13 +39,13 @@ StorePathSet BuiltPath::outPaths() const
res.insert(path);
return res;
},
}, raw()
);
},
raw());
}
SingleDerivedPath::Built SingleBuiltPath::Built::discardOutputPath() const
{
return SingleDerivedPath::Built {
return SingleDerivedPath::Built{
.drvPath = make_ref<SingleDerivedPath>(drvPath->discardOutputPath()),
.output = output.first,
};
@@ -65,14 +55,10 @@ SingleDerivedPath SingleBuiltPath::discardOutputPath() const
{
return std::visit(
overloaded{
[](const SingleBuiltPath::Opaque & p) -> SingleDerivedPath {
return p;
},
[](const SingleBuiltPath::Built & b) -> SingleDerivedPath {
return b.discardOutputPath();
},
}, raw()
);
[](const SingleBuiltPath::Opaque & p) -> SingleDerivedPath { return p; },
[](const SingleBuiltPath::Built & b) -> SingleDerivedPath { return b.discardOutputPath(); },
},
raw());
}
nlohmann::json BuiltPath::Built::toJSON(const StoreDirConfig & store) const
@@ -97,16 +83,12 @@ nlohmann::json SingleBuiltPath::Built::toJSON(const StoreDirConfig & store) cons
nlohmann::json SingleBuiltPath::toJSON(const StoreDirConfig & store) const
{
return std::visit([&](const auto & buildable) {
return buildable.toJSON(store);
}, raw());
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
}
nlohmann::json BuiltPath::toJSON(const StoreDirConfig & store) const
{
return std::visit([&](const auto & buildable) {
return buildable.toJSON(store);
}, raw());
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
}
RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
@@ -116,20 +98,18 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
overloaded{
[&](const BuiltPath::Opaque & p) { res.insert(p.path); },
[&](const BuiltPath::Built & p) {
auto drvHashes =
staticOutputHashes(store, store.readDerivation(p.drvPath->outPath()));
for (auto& [outputName, outputPath] : p.outputs) {
if (experimentalFeatureSettings.isEnabled(
Xp::CaDerivations)) {
auto drvHashes = staticOutputHashes(store, store.readDerivation(p.drvPath->outPath()));
for (auto & [outputName, outputPath] : p.outputs) {
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
auto drvOutput = get(drvHashes, outputName);
if (!drvOutput)
throw Error(
"the derivation '%s' has unrealised output '%s' (derived-path.cc/toRealisedPaths)",
store.printStorePath(p.drvPath->outPath()), outputName);
auto thisRealisation = store.queryRealisation(
DrvOutput{*drvOutput, outputName});
assert(thisRealisation); // Weve built it, so we must
// have the realisation
store.printStorePath(p.drvPath->outPath()),
outputName);
auto thisRealisation = store.queryRealisation(DrvOutput{*drvOutput, outputName});
assert(thisRealisation); // Weve built it, so we must
// have the realisation
res.insert(*thisRealisation);
} else {
res.insert(outputPath);
@@ -141,4 +121,4 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
return res;
}
}
} // namespace nix

View File

@@ -8,4 +8,4 @@ void InstallableValueCommand::run(ref<Store> store, ref<Installable> installable
run(store, installableValue);
}
}
} // namespace nix

View File

@@ -402,4 +402,4 @@ void MixOutLinkBase::createOutLinksMaybe(const std::vector<BuiltPathWithResult>
createOutLinks(outLink, toBuiltPaths(buildables), *store2);
}
}
} // namespace nix

View File

@@ -18,12 +18,11 @@
namespace nix {
fetchers::Settings fetchSettings;
static GlobalConfig::Register rFetchSettings(&fetchSettings);
EvalSettings evalSettings {
EvalSettings evalSettings{
settings.readOnlyMode,
{
{
@@ -31,10 +30,11 @@ EvalSettings evalSettings {
[](EvalState & state, std::string_view rest) {
experimentalFeatureSettings.require(Xp::Flakes);
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(fetchSettings, std::string { rest }, {}, true, false);
auto flakeRef = parseFlakeRef(fetchSettings, std::string{rest}, {}, true, false);
debug("fetching flake search path element '%s''", rest);
auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store);
auto storePath = nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName());
auto storePath =
nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName());
state.allowPath(storePath);
return state.storePath(storePath);
},
@@ -44,17 +44,14 @@ EvalSettings evalSettings {
static GlobalConfig::Register rEvalSettings(&evalSettings);
flake::Settings flakeSettings;
static GlobalConfig::Register rFlakeSettings(&flakeSettings);
CompatibilitySettings compatibilitySettings {};
CompatibilitySettings compatibilitySettings{};
static GlobalConfig::Register rCompatibilitySettings(&compatibilitySettings);
MixEvalArgs::MixEvalArgs()
{
addFlag({
@@ -62,7 +59,9 @@ MixEvalArgs::MixEvalArgs()
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
.category = category,
.labels = {"name", "expr"},
.handler = {[&](std::string name, std::string expr) { autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}}); }},
.handler = {[&](std::string name, std::string expr) {
autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}});
}},
});
addFlag({
@@ -70,7 +69,9 @@ MixEvalArgs::MixEvalArgs()
.description = "Pass the string *string* as the argument *name* to Nix functions.",
.category = category,
.labels = {"name", "string"},
.handler = {[&](std::string name, std::string s) { autoArgs.insert_or_assign(name, AutoArg{AutoArgString{s}}); }},
.handler = {[&](std::string name, std::string s) {
autoArgs.insert_or_assign(name, AutoArg{AutoArgString{s}});
}},
});
addFlag({
@@ -78,7 +79,9 @@ MixEvalArgs::MixEvalArgs()
.description = "Pass the contents of file *path* as the argument *name* to Nix functions.",
.category = category,
.labels = {"name", "path"},
.handler = {[&](std::string name, std::string path) { autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}}); }},
.handler = {[&](std::string name, std::string path) {
autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}});
}},
.completer = completePath,
});
@@ -102,18 +105,14 @@ MixEvalArgs::MixEvalArgs()
)",
.category = category,
.labels = {"path"},
.handler = {[&](std::string s) {
lookupPath.elements.emplace_back(LookupPath::Elem::parse(s));
}},
.handler = {[&](std::string s) { lookupPath.elements.emplace_back(LookupPath::Elem::parse(s)); }},
});
addFlag({
.longName = "impure",
.description = "Allow access to mutable paths and repositories.",
.category = category,
.handler = {[&]() {
evalSettings.pureEval = false;
}},
.handler = {[&]() { evalSettings.pureEval = false; }},
});
addFlag({
@@ -125,7 +124,8 @@ MixEvalArgs::MixEvalArgs()
auto from = parseFlakeRef(fetchSettings, _from, std::filesystem::current_path().string());
auto to = parseFlakeRef(fetchSettings, _to, std::filesystem::current_path().string());
fetchers::Attrs extraAttrs;
if (to.subdir != "") extraAttrs["dir"] = to.subdir;
if (to.subdir != "")
extraAttrs["dir"] = to.subdir;
fetchers::overrideRegistry(from.input, to.input, extraAttrs);
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
@@ -136,7 +136,7 @@ MixEvalArgs::MixEvalArgs()
addFlag({
.longName = "eval-store",
.description =
R"(
R"(
The [URL of the Nix store](@docroot@/store/types/index.md#store-url-format)
to use for evaluation, i.e. to store derivations (`.drv` files) and inputs referenced by them.
)",
@@ -151,20 +151,21 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
auto res = state.buildBindings(autoArgs.size());
for (auto & [name, arg] : autoArgs) {
auto v = state.allocValue();
std::visit(overloaded {
[&](const AutoArgExpr & arg) {
state.mkThunk_(*v, state.parseExprFromString(arg.expr, compatibilitySettings.nixShellShebangArgumentsRelativeToScript ? state.rootPath(absPath(getCommandBaseDir())) : state.rootPath(".")));
},
[&](const AutoArgString & arg) {
v->mkString(arg.s);
},
[&](const AutoArgFile & arg) {
v->mkString(readFile(arg.path.string()));
},
[&](const AutoArgStdin & arg) {
v->mkString(readFile(STDIN_FILENO));
}
}, arg);
std::visit(
overloaded{
[&](const AutoArgExpr & arg) {
state.mkThunk_(
*v,
state.parseExprFromString(
arg.expr,
compatibilitySettings.nixShellShebangArgumentsRelativeToScript
? state.rootPath(absPath(getCommandBaseDir()))
: state.rootPath(".")));
},
[&](const AutoArgString & arg) { v->mkString(arg.s); },
[&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string())); },
[&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO)); }},
arg);
res.insert(state.symbols.create(name), v);
}
return res.finish();
@@ -173,10 +174,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * baseDir)
{
if (EvalSettings::isPseudoUrl(s)) {
auto accessor = fetchers::downloadTarball(
state.store,
state.fetchSettings,
EvalSettings::resolvePseudoUrl(s));
auto accessor = fetchers::downloadTarball(state.store, state.fetchSettings, EvalSettings::resolvePseudoUrl(s));
auto storePath = fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy);
return state.storePath(storePath);
}
@@ -185,7 +183,8 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas
experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(fetchSettings, std::string(s.substr(6)), {}, true, false);
auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store);
auto storePath = nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName());
auto storePath =
nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName());
state.allowPath(storePath);
return state.storePath(storePath);
}
@@ -199,4 +198,4 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas
return state.rootPath(baseDir ? absPath(s, *baseDir) : absPath(s));
}
}
} // namespace nix

View File

@@ -11,14 +11,12 @@ Strings editorFor(const SourcePath & file, uint32_t line)
throw Error("cannot open '%s' in an editor because it has no physical path", file);
auto editor = getEnv("EDITOR").value_or("cat");
auto args = tokenizeString<Strings>(editor);
if (line > 0 && (
editor.find("emacs") != std::string::npos ||
editor.find("nano") != std::string::npos ||
editor.find("vim") != std::string::npos ||
editor.find("kak") != std::string::npos))
if (line > 0
&& (editor.find("emacs") != std::string::npos || editor.find("nano") != std::string::npos
|| editor.find("vim") != std::string::npos || editor.find("kak") != std::string::npos))
args.push_back(fmt("+%d", line));
args.push_back(path->string());
return args;
}
}
} // namespace nix

View File

@@ -8,7 +8,8 @@ namespace nix {
struct SingleBuiltPath;
struct SingleBuiltPathBuilt {
struct SingleBuiltPathBuilt
{
ref<SingleBuiltPath> drvPath;
std::pair<std::string, StorePath> output;
@@ -18,26 +19,25 @@ struct SingleBuiltPathBuilt {
static SingleBuiltPathBuilt parse(const StoreDirConfig & store, std::string_view, std::string_view);
nlohmann::json toJSON(const StoreDirConfig & store) const;
bool operator ==(const SingleBuiltPathBuilt &) const noexcept;
std::strong_ordering operator <=>(const SingleBuiltPathBuilt &) const noexcept;
bool operator==(const SingleBuiltPathBuilt &) const noexcept;
std::strong_ordering operator<=>(const SingleBuiltPathBuilt &) const noexcept;
};
using _SingleBuiltPathRaw = std::variant<
DerivedPathOpaque,
SingleBuiltPathBuilt
>;
using _SingleBuiltPathRaw = std::variant<DerivedPathOpaque, SingleBuiltPathBuilt>;
struct SingleBuiltPath : _SingleBuiltPathRaw {
struct SingleBuiltPath : _SingleBuiltPathRaw
{
using Raw = _SingleBuiltPathRaw;
using Raw::Raw;
using Opaque = DerivedPathOpaque;
using Built = SingleBuiltPathBuilt;
bool operator == (const SingleBuiltPath &) const = default;
auto operator <=> (const SingleBuiltPath &) const = default;
bool operator==(const SingleBuiltPath &) const = default;
auto operator<=>(const SingleBuiltPath &) const = default;
inline const Raw & raw() const {
inline const Raw & raw() const
{
return static_cast<const Raw &>(*this);
}
@@ -51,7 +51,7 @@ struct SingleBuiltPath : _SingleBuiltPathRaw {
static inline ref<SingleBuiltPath> staticDrv(StorePath drvPath)
{
return make_ref<SingleBuiltPath>(SingleBuiltPath::Opaque { drvPath });
return make_ref<SingleBuiltPath>(SingleBuiltPath::Opaque{drvPath});
}
/**
@@ -59,40 +59,41 @@ static inline ref<SingleBuiltPath> staticDrv(StorePath drvPath)
*
* See 'BuiltPath' for more an explanation.
*/
struct BuiltPathBuilt {
struct BuiltPathBuilt
{
ref<SingleBuiltPath> drvPath;
std::map<std::string, StorePath> outputs;
bool operator == (const BuiltPathBuilt &) const noexcept;
bool operator==(const BuiltPathBuilt &) const noexcept;
// TODO libc++ 16 (used by darwin) missing `std::map::operator <=>`, can't do yet.
//std::strong_ordering operator <=> (const BuiltPathBuilt &) const noexcept;
// std::strong_ordering operator <=> (const BuiltPathBuilt &) const noexcept;
std::string to_string(const StoreDirConfig & store) const;
static BuiltPathBuilt parse(const StoreDirConfig & store, std::string_view, std::string_view);
nlohmann::json toJSON(const StoreDirConfig & store) const;
};
using _BuiltPathRaw = std::variant<
DerivedPath::Opaque,
BuiltPathBuilt
>;
using _BuiltPathRaw = std::variant<DerivedPath::Opaque, BuiltPathBuilt>;
/**
* A built path. Similar to a DerivedPath, but enriched with the corresponding
* output path(s).
*/
struct BuiltPath : _BuiltPathRaw {
struct BuiltPath : _BuiltPathRaw
{
using Raw = _BuiltPathRaw;
using Raw::Raw;
using Opaque = DerivedPathOpaque;
using Built = BuiltPathBuilt;
bool operator == (const BuiltPath &) const = default;
// TODO libc++ 16 (used by darwin) missing `std::map::operator <=>`, can't do yet.
//auto operator <=> (const BuiltPath &) const = default;
bool operator==(const BuiltPath &) const = default;
inline const Raw & raw() const {
// TODO libc++ 16 (used by darwin) missing `std::map::operator <=>`, can't do yet.
// auto operator <=> (const BuiltPath &) const = default;
inline const Raw & raw() const
{
return static_cast<const Raw &>(*this);
}
@@ -104,4 +105,4 @@ struct BuiltPath : _BuiltPathRaw {
typedef std::vector<BuiltPath> BuiltPaths;
}
} // namespace nix

View File

@@ -20,4 +20,4 @@ struct InstallableValueCommand : InstallableCommand
void run(ref<Store> store, ref<Installable> installable) override;
};
}
} // namespace nix

View File

@@ -12,7 +12,9 @@ namespace nix {
class Store;
namespace fetchers { struct Settings; }
namespace fetchers {
struct Settings;
}
class EvalState;
struct EvalSettings;
@@ -20,7 +22,9 @@ struct CompatibilitySettings;
class Bindings;
struct SourcePath;
namespace flake { struct Settings; }
namespace flake {
struct Settings;
}
/**
* @todo Get rid of global setttings variables
@@ -55,10 +59,23 @@ struct MixEvalArgs : virtual Args, virtual MixRepair
std::optional<std::string> evalStoreUrl;
private:
struct AutoArgExpr { std::string expr; };
struct AutoArgString { std::string s; };
struct AutoArgFile { std::filesystem::path path; };
struct AutoArgStdin { };
struct AutoArgExpr
{
std::string expr;
};
struct AutoArgString
{
std::string s;
};
struct AutoArgFile
{
std::filesystem::path path;
};
struct AutoArgStdin
{};
using AutoArg = std::variant<AutoArgExpr, AutoArgString, AutoArgFile, AutoArgStdin>;
@@ -70,4 +87,4 @@ private:
*/
SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * baseDir = nullptr);
}
} // namespace nix

View File

@@ -33,4 +33,4 @@ struct CompatibilitySettings : public Config
)"};
};
};
}; // namespace nix

View File

@@ -12,4 +12,4 @@ namespace nix {
*/
Strings editorFor(const SourcePath & file, uint32_t line);
}
} // namespace nix

View File

@@ -39,7 +39,10 @@ class InstallableAttrPath : public InstallableValue
const std::string & attrPath,
ExtendedOutputsSpec extendedOutputsSpec);
std::string what() const override { return attrPath; };
std::string what() const override
{
return attrPath;
};
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
@@ -55,4 +58,4 @@ public:
ExtendedOutputsSpec extendedOutputsSpec);
};
}
} // namespace nix

View File

@@ -11,8 +11,10 @@ struct InstallableDerivedPath : Installable
DerivedPath derivedPath;
InstallableDerivedPath(ref<Store> store, DerivedPath && derivedPath)
: store(store), derivedPath(std::move(derivedPath))
{ }
: store(store)
, derivedPath(std::move(derivedPath))
{
}
std::string what() const override;
@@ -20,10 +22,8 @@ struct InstallableDerivedPath : Installable
std::optional<StorePath> getStorePath() override;
static InstallableDerivedPath parse(
ref<Store> store,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec);
static InstallableDerivedPath
parse(ref<Store> store, std::string_view prefix, ExtendedOutputsSpec extendedOutputsSpec);
};
}
} // namespace nix

View File

@@ -18,7 +18,8 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue
/**
* Extra struct to get around C++ designated initializer limitations
*/
struct Flake {
struct Flake
{
FlakeRef originalRef;
FlakeRef lockedRef;
};
@@ -26,8 +27,10 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue
Flake flake;
ExtraPathInfoFlake(Value && v, Flake && f)
: ExtraPathInfoValue(std::move(v)), flake(std::move(f))
{ }
: ExtraPathInfoValue(std::move(v))
, flake(std::move(f))
{
}
};
struct InstallableFlake : InstallableValue
@@ -49,7 +52,10 @@ struct InstallableFlake : InstallableValue
Strings prefixes,
const flake::LockFlags & lockFlags);
std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
std::string what() const override
{
return flakeRef.to_string() + "#" + *attrPaths.begin();
}
std::vector<std::string> getActualAttrPaths();
@@ -61,8 +67,7 @@ struct InstallableFlake : InstallableValue
* Get a cursor to every attrpath in getActualAttrPaths() that
* exists. However if none exists, throw an exception.
*/
std::vector<ref<eval_cache::AttrCursor>>
getCursors(EvalState & state) override;
std::vector<ref<eval_cache::AttrCursor>> getCursors(EvalState & state) override;
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
@@ -79,11 +84,9 @@ struct InstallableFlake : InstallableValue
*/
static inline FlakeRef defaultNixpkgsFlakeRef()
{
return FlakeRef::fromAttrs(fetchSettings, {{"type","indirect"}, {"id", "nixpkgs"}});
return FlakeRef::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", "nixpkgs"}});
}
ref<eval_cache::EvalCache> openEvalCache(
EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake);
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, std::shared_ptr<flake::LockedFlake> lockedFlake);
}
} // namespace nix

View File

@@ -9,7 +9,10 @@ namespace nix {
struct PackageInfo;
struct SourceExprCommand;
namespace eval_cache { class EvalCache; class AttrCursor; }
namespace eval_cache {
class EvalCache;
class AttrCursor;
} // namespace eval_cache
struct App
{
@@ -37,7 +40,8 @@ struct ExtraPathInfoValue : ExtraPathInfo
/**
* Extra struct to get around C++ designated initializer limitations
*/
struct Value {
struct Value
{
/**
* An optional priority for use with "build envs". See Package
*/
@@ -61,7 +65,8 @@ struct ExtraPathInfoValue : ExtraPathInfo
ExtraPathInfoValue(Value && v)
: value(std::move(v))
{ }
{
}
virtual ~ExtraPathInfoValue() = default;
};
@@ -74,9 +79,12 @@ struct InstallableValue : Installable
{
ref<EvalState> state;
InstallableValue(ref<EvalState> state) : state(state) {}
InstallableValue(ref<EvalState> state)
: state(state)
{
}
virtual ~InstallableValue() { }
virtual ~InstallableValue() {}
virtual std::pair<Value *, PosIdx> toValue(EvalState & state) = 0;
@@ -85,15 +93,13 @@ struct InstallableValue : Installable
* However if none exists, throw exception instead of returning
* empty vector.
*/
virtual std::vector<ref<eval_cache::AttrCursor>>
getCursors(EvalState & state);
virtual std::vector<ref<eval_cache::AttrCursor>> getCursors(EvalState & state);
/**
* Get the first and most preferred cursor this Installable could
* refer to, or throw an exception if none exists.
*/
virtual ref<eval_cache::AttrCursor>
getCursor(EvalState & state);
virtual ref<eval_cache::AttrCursor> getCursor(EvalState & state);
UnresolvedApp toApp(EvalState & state);
@@ -116,7 +122,8 @@ protected:
* @result A derived path (with empty info, for now) if the value
* matched the above criteria.
*/
std::optional<DerivedPathWithInfo> trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx);
std::optional<DerivedPathWithInfo>
trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx);
};
}
} // namespace nix

View File

@@ -112,7 +112,7 @@ typedef std::vector<ref<Installable>> Installables;
*/
struct Installable
{
virtual ~Installable() { }
virtual ~Installable() {}
/**
* What Installable is this?
@@ -168,37 +168,19 @@ struct Installable
BuildMode bMode = bmNormal);
static std::set<StorePath> toStorePathSet(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const Installables & installables);
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables);
static std::vector<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const Installables & installables);
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables);
static StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
ref<Installable> installable);
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, ref<Installable> installable);
static std::set<StorePath> toDerivations(
ref<Store> store,
const Installables & installables,
bool useDeriver = false);
static std::set<StorePath>
toDerivations(ref<Store> store, const Installables & installables, bool useDeriver = false);
static BuiltPaths toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const Installables & installables);
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables);
};
}
} // namespace nix

View File

@@ -7,13 +7,14 @@
namespace nix {
typedef std::function<void(int, char * *)> MainFunction;
typedef std::function<void(int, char **)> MainFunction;
struct RegisterLegacyCommand
{
typedef std::map<std::string, MainFunction> Commands;
static Commands & commands() {
static Commands & commands()
{
static Commands commands;
return commands;
}
@@ -24,4 +25,4 @@ struct RegisterLegacyCommand
}
};
}
} // namespace nix

View File

@@ -14,4 +14,4 @@ namespace nix {
*/
std::string renderMarkdownToTerminal(std::string_view markdown);
}
} // namespace nix

View File

@@ -4,18 +4,22 @@
namespace nix::flag {
Args::Flag hashAlgo(std::string && longName, HashAlgorithm * ha);
static inline Args::Flag hashAlgo(HashAlgorithm * ha)
{
return hashAlgo("hash-algo", ha);
}
Args::Flag hashAlgoOpt(std::string && longName, std::optional<HashAlgorithm> * oha);
Args::Flag hashFormatWithDefault(std::string && longName, HashFormat * hf);
Args::Flag hashFormatOpt(std::string && longName, std::optional<HashFormat> * ohf);
static inline Args::Flag hashAlgoOpt(std::optional<HashAlgorithm> * oha)
{
return hashAlgoOpt("hash-algo", oha);
}
Args::Flag fileIngestionMethod(FileIngestionMethod * method);
Args::Flag contentAddressMethod(ContentAddressMethod * method);
}
} // namespace nix::flag

View File

@@ -19,4 +19,4 @@ extern const StringSet networkProxyVariables;
*/
bool haveNetworkProxyConnection();
}
} // namespace nix

View File

@@ -11,10 +11,11 @@ namespace nix {
namespace detail {
/** Provides the completion hooks for the repl, without exposing its complete
* internals. */
struct ReplCompleterMixin {
struct ReplCompleterMixin
{
virtual StringSet completePrefix(const std::string & prefix) = 0;
};
};
}; // namespace detail
enum class ReplPromptType {
ReplPrompt,
@@ -29,7 +30,7 @@ public:
virtual Guard init(detail::ReplCompleterMixin * repl) = 0;
/** Returns a boolean of whether the interacter got EOF */
virtual bool getLine(std::string & input, ReplPromptType promptType) = 0;
virtual ~ReplInteracter(){};
virtual ~ReplInteracter() {};
};
class ReadlineLikeInteracter : public virtual ReplInteracter
@@ -40,9 +41,10 @@ public:
: historyFile(historyFile)
{
}
virtual Guard init(detail::ReplCompleterMixin * repl) override;
virtual bool getLine(std::string & input, ReplPromptType promptType) override;
virtual ~ReadlineLikeInteracter() override;
};
};
}; // namespace nix

View File

@@ -12,12 +12,12 @@ struct AbstractNixRepl
AbstractNixRepl(ref<EvalState> state)
: state(state)
{ }
{
}
virtual ~AbstractNixRepl()
{ }
virtual ~AbstractNixRepl() {}
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
typedef std::vector<std::pair<Value *, std::string>> AnnotatedValues;
using RunNix = void(Path program, const Strings & args, const std::optional<std::string> & input);
@@ -33,13 +33,11 @@ struct AbstractNixRepl
std::function<AnnotatedValues()> getValues,
RunNix * runNix = nullptr);
static ReplExitStatus runSimple(
ref<EvalState> evalState,
const ValMap & extraEnv);
static ReplExitStatus runSimple(ref<EvalState> evalState, const ValMap & extraEnv);
virtual void initEnv() = 0;
virtual ReplExitStatus mainLoop() = 0;
};
}
} // namespace nix

View File

@@ -35,7 +35,8 @@ InstallableAttrPath::InstallableAttrPath(
, v(allocRootValue(v))
, attrPath(attrPath)
, extendedOutputsSpec(std::move(extendedOutputsSpec))
{ }
{
}
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
{
@@ -48,12 +49,9 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
{
auto [v, pos] = toValue(*state);
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
*v,
pos,
fmt("while evaluating the attribute '%s'", attrPath)))
{
return { *derivedPathWithInfo };
if (std::optional derivedPathWithInfo =
trySinglePathToDerivedPaths(*v, pos, fmt("while evaluating the attribute '%s'", attrPath))) {
return {*derivedPathWithInfo};
}
Bindings & autoArgs = *cmd.getAutoArgs(*state);
@@ -70,19 +68,19 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
if (!drvPath)
throw Error("'%s' is not a derivation", what());
auto newOutputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
StringSet outputsToInstall;
for (auto & output : packageInfo.queryOutputs(false, true))
outputsToInstall.insert(output.first);
if (outputsToInstall.empty())
outputsToInstall.insert("out");
return OutputsSpec::Names { std::move(outputsToInstall) };
auto newOutputs = std::visit(
overloaded{
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
StringSet outputsToInstall;
for (auto & output : packageInfo.queryOutputs(false, true))
outputsToInstall.insert(output.first);
if (outputsToInstall.empty())
outputsToInstall.insert("out");
return OutputsSpec::Names{std::move(outputsToInstall)};
},
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec { return e; },
},
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
return e;
},
}, extendedOutputsSpec.raw);
extendedOutputsSpec.raw);
auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
@@ -93,11 +91,12 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
DerivedPathsWithInfo res;
for (auto & [drvPath, outputs] : byDrvPath)
res.push_back({
.path = DerivedPath::Built {
.drvPath = makeConstantStorePathRef(drvPath),
.outputs = outputs,
},
.info = make_ref<ExtraPathInfoValue>(ExtraPathInfoValue::Value {
.path =
DerivedPath::Built{
.drvPath = makeConstantStorePathRef(drvPath),
.outputs = outputs,
},
.info = make_ref<ExtraPathInfoValue>(ExtraPathInfoValue::Value{
.extendedOutputsSpec = outputs,
/* FIXME: reconsider backwards compatibility above
so we can fill in this info. */
@@ -115,10 +114,12 @@ InstallableAttrPath InstallableAttrPath::parse(
ExtendedOutputsSpec extendedOutputsSpec)
{
return {
state, cmd, v,
prefix == "." ? "" : std::string { prefix },
state,
cmd,
v,
prefix == "." ? "" : std::string{prefix},
std::move(extendedOutputsSpec),
};
}
}
} // namespace nix

View File

@@ -21,35 +21,35 @@ std::optional<StorePath> InstallableDerivedPath::getStorePath()
return derivedPath.getBaseStorePath();
}
InstallableDerivedPath InstallableDerivedPath::parse(
ref<Store> store,
std::string_view prefix,
ExtendedOutputsSpec extendedOutputsSpec)
InstallableDerivedPath
InstallableDerivedPath::parse(ref<Store> store, 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);
return DerivedPath::Opaque {
.path = std::move(storePath),
};
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);
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 = make_ref<SingleDerivedPath>(SingleDerivedPath::parse(*store, prefix));
drvRequireExperiment(*drv);
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 = make_ref<SingleDerivedPath>(SingleDerivedPath::parse(*store, prefix));
drvRequireExperiment(*drv);
return DerivedPath::Built {
.drvPath = std::move(drv),
.outputs = outputSpec,
};
},
}, extendedOutputsSpec.raw);
return InstallableDerivedPath {
extendedOutputsSpec.raw);
return InstallableDerivedPath{
store,
std::move(derivedPath),
};
}
}
} // namespace nix

View File

@@ -28,8 +28,8 @@ namespace nix {
std::vector<std::string> InstallableFlake::getActualAttrPaths()
{
std::vector<std::string> res;
if (attrPaths.size() == 1 && attrPaths.front().starts_with(".")){
attrPaths.front().erase(0,1);
if (attrPaths.size() == 1 && attrPaths.front().starts_with(".")) {
attrPaths.front().erase(0, 1);
res.push_back(attrPaths.front());
return res;
}
@@ -47,8 +47,11 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
{
std::string s;
for (const auto & [n, i] : enumerate(paths)) {
if (n > 0) s += n + 1 == paths.size() ? " or " : ", ";
s += '\''; s += i; s += '\'';
if (n > 0)
s += n + 1 == paths.size() ? " or " : ", ";
s += '\'';
s += i;
s += '\'';
}
return s;
}
@@ -62,12 +65,12 @@ InstallableFlake::InstallableFlake(
Strings attrPaths,
Strings prefixes,
const flake::LockFlags & lockFlags)
: InstallableValue(state),
flakeRef(flakeRef),
attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
prefixes(fragment == "" ? Strings{} : prefixes),
extendedOutputsSpec(std::move(extendedOutputsSpec)),
lockFlags(lockFlags)
: InstallableValue(state)
, flakeRef(flakeRef)
, attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment})
, prefixes(fragment == "" ? Strings{} : prefixes)
, extendedOutputsSpec(std::move(extendedOutputsSpec))
, lockFlags(lockFlags)
{
if (cmd && cmd->getAutoArgs(*state)->size())
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
@@ -87,18 +90,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
auto v = attr->forceValue();
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
v,
noPos,
fmt("while evaluating the flake output attribute '%s'", attrPath)))
{
return { *derivedPathWithInfo };
v, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath))) {
return {*derivedPathWithInfo};
} else {
throw Error(
"expected flake output attribute '%s' to be a derivation or path but found %s: %s",
attrPath,
showType(v),
ValuePrinter(*this->state, v, errorPrintOptions)
);
ValuePrinter(*this->state, v, errorPrintOptions));
}
}
@@ -113,39 +112,40 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
}
return {{
.path = DerivedPath::Built {
.drvPath = makeConstantStorePathRef(std::move(drvPath)),
.outputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
StringSet outputsToInstall;
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
if (aOutputSpecified->getBool()) {
if (auto aOutputName = attr->maybeGetAttr("outputName"))
outputsToInstall = { aOutputName->getString() };
}
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
for (auto & s : aOutputsToInstall->getListOfStrings())
outputsToInstall.insert(s);
}
.path =
DerivedPath::Built{
.drvPath = makeConstantStorePathRef(std::move(drvPath)),
.outputs = std::visit(
overloaded{
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
StringSet outputsToInstall;
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
if (aOutputSpecified->getBool()) {
if (auto aOutputName = attr->maybeGetAttr("outputName"))
outputsToInstall = {aOutputName->getString()};
}
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
for (auto & s : aOutputsToInstall->getListOfStrings())
outputsToInstall.insert(s);
}
if (outputsToInstall.empty())
outputsToInstall.insert("out");
if (outputsToInstall.empty())
outputsToInstall.insert("out");
return OutputsSpec::Names { std::move(outputsToInstall) };
},
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
return e;
},
}, extendedOutputsSpec.raw),
},
return OutputsSpec::Names{std::move(outputsToInstall)};
},
[&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec { return e; },
},
extendedOutputsSpec.raw),
},
.info = make_ref<ExtraPathInfoFlake>(
ExtraPathInfoValue::Value {
ExtraPathInfoValue::Value{
.priority = priority,
.attrPath = attrPath,
.extendedOutputsSpec = extendedOutputsSpec,
},
ExtraPathInfoFlake::Flake {
ExtraPathInfoFlake::Flake{
.originalRef = flakeRef,
.lockedRef = getLockedFlake()->flake.lockedRef,
}),
@@ -157,8 +157,7 @@ std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
return {&getCursor(state)->forceValue(), noPos};
}
std::vector<ref<eval_cache::AttrCursor>>
InstallableFlake::getCursors(EvalState & state)
std::vector<ref<eval_cache::AttrCursor>> InstallableFlake::getCursors(EvalState & state)
{
auto evalCache = openEvalCache(state, getLockedFlake());
@@ -181,11 +180,7 @@ InstallableFlake::getCursors(EvalState & state)
}
if (res.size() == 0)
throw Error(
suggestions,
"flake '%s' does not provide attribute %s",
flakeRef,
showAttrPaths(attrPaths));
throw Error(suggestions, "flake '%s' does not provide attribute %s", flakeRef, showAttrPaths(attrPaths));
return res;
}
@@ -196,8 +191,8 @@ std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
flake::LockFlags lockFlagsApplyConfig = lockFlags;
// FIXME why this side effect?
lockFlagsApplyConfig.applyNixConfig = true;
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(
flakeSettings, *state, flakeRef, lockFlagsApplyConfig));
_lockedFlake =
std::make_shared<flake::LockedFlake>(lockFlake(flakeSettings, *state, flakeRef, lockFlagsApplyConfig));
}
return _lockedFlake;
}
@@ -216,4 +211,4 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const
return defaultNixpkgsFlakeRef();
}
}
} // namespace nix

View File

@@ -4,17 +4,14 @@
namespace nix {
std::vector<ref<eval_cache::AttrCursor>>
InstallableValue::getCursors(EvalState & state)
std::vector<ref<eval_cache::AttrCursor>> InstallableValue::getCursors(EvalState & state)
{
auto evalCache =
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
[&]() { return toValue(state).first; });
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state, [&]() { return toValue(state).first; });
return {evalCache->getRoot()};
}
ref<eval_cache::AttrCursor>
InstallableValue::getCursor(EvalState & state)
ref<eval_cache::AttrCursor> InstallableValue::getCursor(EvalState & state)
{
/* Although getCursors should return at least one element, in case it doesn't,
bound check to avoid an undefined behavior for vector[0] */
@@ -39,30 +36,32 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
auto castedInstallable = installable.dynamic_pointer_cast<InstallableValue>();
if (!castedInstallable)
throw nonValueInstallable(*installable);
return ref { castedInstallable };
return ref{castedInstallable};
}
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
std::optional<DerivedPathWithInfo>
InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
{
if (v.type() == nPath) {
auto storePath = fetchToStore(*state->store, v.path(), FetchMode::Copy);
return {{
.path = DerivedPath::Opaque {
.path = std::move(storePath),
},
.path =
DerivedPath::Opaque{
.path = std::move(storePath),
},
.info = make_ref<ExtraPathInfo>(),
}};
}
else if (v.type() == nString) {
return {{
.path = DerivedPath::fromSingle(
state->coerceToSingleDerivedPath(pos, v, errorCtx)),
.path = DerivedPath::fromSingle(state->coerceToSingleDerivedPath(pos, v, errorCtx)),
.info = make_ref<ExtraPathInfo>(),
}};
}
else return std::nullopt;
else
return std::nullopt;
}
}
} // namespace nix

View File

@@ -61,7 +61,8 @@ MixFlakeOptions::MixFlakeOptions()
.category = category,
.handler = {[&]() {
lockFlags.recreateLockFile = true;
warn("'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead.");
warn(
"'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead.");
}},
});
@@ -158,9 +159,7 @@ MixFlakeOptions::MixFlakeOptions()
.description = "Write the given lock file instead of `flake.lock` within the top-level flake.",
.category = category,
.labels = {"flake-lock-path"},
.handler = {[&](std::string lockFilePath) {
lockFlags.outputLockFilePath = lockFilePath;
}},
.handler = {[&](std::string lockFilePath) { lockFlags.outputLockFilePath = lockFilePath; }},
.completer = completePath,
});
@@ -175,12 +174,12 @@ MixFlakeOptions::MixFlakeOptions()
flakeSettings,
*evalState,
parseFlakeRef(fetchSettings, flakeRef, absPath(getCommandBaseDir())),
{ .writeLockFile = false });
{.writeLockFile = false});
for (auto & [inputName, input] : flake.lockFile.root->inputs) {
auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes
if (auto input3 = std::dynamic_pointer_cast<const flake::LockedNode>(input2)) {
overrideRegistry(
fetchers::Input::fromAttrs(fetchSettings, {{"type","indirect"}, {"id", inputName}}),
fetchers::Input::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", inputName}}),
input3->lockedRef.input,
{});
}
@@ -209,7 +208,8 @@ SourceExprCommand::SourceExprCommand()
addFlag({
.longName = "expr",
.description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.",
.description =
"Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.",
.category = installablesCategory,
.labels = {"expr"},
.handler = {&expr},
@@ -220,32 +220,26 @@ MixReadOnlyOption::MixReadOnlyOption()
{
addFlag({
.longName = "read-only",
.description =
"Do not instantiate each evaluated derivation. "
"This improves performance, but can cause errors when accessing "
"store paths of derivations during evaluation.",
.description = "Do not instantiate each evaluated derivation. "
"This improves performance, but can cause errors when accessing "
"store paths of derivations during evaluation.",
.handler = {&settings.readOnlyMode, true},
});
}
Strings SourceExprCommand::getDefaultFlakeAttrPaths()
{
return {
"packages." + settings.thisSystem.get() + ".default",
"defaultPackage." + settings.thisSystem.get()
};
return {"packages." + settings.thisSystem.get() + ".default", "defaultPackage." + settings.thisSystem.get()};
}
Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
{
return {
// As a convenience, look for the attribute in
// 'outputs.packages'.
"packages." + settings.thisSystem.get() + ".",
// As a temporary hack until Nixpkgs is properly converted
// to provide a clean 'packages' set, look in 'legacyPackages'.
"legacyPackages." + settings.thisSystem.get() + "."
};
return {// As a convenience, look for the attribute in
// 'outputs.packages'.
"packages." + settings.thisSystem.get() + ".",
// As a temporary hack until Nixpkgs is properly converted
// to provide a clean 'packages' set, look in 'legacyPackages'.
"legacyPackages." + settings.thisSystem.get() + "."};
}
Args::CompleterClosure SourceExprCommand::getCompleteInstallable()
@@ -263,10 +257,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
evalSettings.pureEval = false;
auto state = getEvalState();
auto e =
state->parseExprFromFile(
resolveExprPath(
lookupFileArg(*state, *file)));
auto e = state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, *file)));
Value root;
state->eval(e, root);
@@ -285,7 +276,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
}
auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root);
Value &v1(*v);
Value & v1(*v);
state->forceValue(v1, pos);
Value v2;
state->autoCallFunction(*autoArgs, v1, v2);
@@ -310,7 +301,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
getDefaultFlakeAttrPaths(),
prefix);
}
} catch (EvalError&) {
} catch (EvalError &) {
// Don't want eval errors to mess-up with the completion engine, so let's just swallow them
}
}
@@ -334,22 +325,23 @@ void completeFlakeRefWithFragment(
auto fragment = prefix.substr(hash + 1);
std::string prefixRoot = "";
if (fragment.starts_with(".")){
if (fragment.starts_with(".")) {
fragment = fragment.substr(1);
prefixRoot = ".";
}
auto flakeRefS = std::string(prefix.substr(0, hash));
// TODO: ideally this would use the command base directory instead of assuming ".".
auto flakeRef = parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string());
auto flakeRef =
parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string());
auto evalCache = openEvalCache(*evalState,
std::make_shared<flake::LockedFlake>(lockFlake(
flakeSettings, *evalState, flakeRef, lockFlags)));
auto evalCache = openEvalCache(
*evalState,
std::make_shared<flake::LockedFlake>(lockFlake(flakeSettings, *evalState, flakeRef, lockFlags)));
auto root = evalCache->getRoot();
if (prefixRoot == "."){
if (prefixRoot == ".") {
attrPathPrefixes.clear();
}
/* Complete 'fragment' relative to all the
@@ -369,7 +361,8 @@ void completeFlakeRefWithFragment(
}
auto attr = root->findAlongAttrPath(attrPath);
if (!attr) continue;
if (!attr)
continue;
for (auto & attr2 : (*attr)->getAttrs()) {
if (hasPrefix(evalState->symbols[attr2], lastAttr)) {
@@ -377,7 +370,9 @@ void completeFlakeRefWithFragment(
/* Strip the attrpath prefix. */
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
// FIXME: handle names with dots
completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", evalState->symbols.resolve(attrPath2)));
completions.add(
flakeRefS + "#" + prefixRoot
+ concatStringsSep(".", evalState->symbols.resolve(attrPath2)));
}
}
}
@@ -387,7 +382,8 @@ void completeFlakeRefWithFragment(
if (fragment.empty()) {
for (auto & attrPath : defaultFlakeAttrPaths) {
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
if (!attr) continue;
if (!attr)
continue;
completions.add(flakeRefS + "#" + prefixRoot);
}
}
@@ -427,14 +423,12 @@ DerivedPathWithInfo Installable::toDerivedPath()
{
auto buildables = toDerivedPaths();
if (buildables.size() != 1)
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
throw Error(
"installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
return std::move(buildables[0]);
}
static StorePath getDeriver(
ref<Store> store,
const Installable & i,
const StorePath & drvPath)
static StorePath getDeriver(ref<Store> store, const Installable & i, const StorePath & drvPath)
{
auto derivers = store->queryValidDerivers(drvPath);
if (derivers.empty())
@@ -443,35 +437,35 @@ static StorePath getDeriver(
return *derivers.begin();
}
ref<eval_cache::EvalCache> openEvalCache(
EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake)
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, std::shared_ptr<flake::LockedFlake> lockedFlake)
{
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
? lockedFlake->getFingerprint(state.store, state.fetchSettings)
: std::nullopt;
auto rootLoader = [&state, lockedFlake]()
{
/* For testing whether the evaluation cache is
complete. */
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
throw Error("not everything is cached, but evaluation is not allowed");
? lockedFlake->getFingerprint(state.store, state.fetchSettings)
: std::nullopt;
auto rootLoader = [&state, lockedFlake]() {
/* For testing whether the evaluation cache is
complete. */
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
throw Error("not everything is cached, but evaluation is not allowed");
auto vFlake = state.allocValue();
flake::callFlake(state, *lockedFlake, *vFlake);
auto vFlake = state.allocValue();
flake::callFlake(state, *lockedFlake, *vFlake);
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
auto aOutputs = vFlake->attrs()->get(state.symbols.create("outputs"));
assert(aOutputs);
auto aOutputs = vFlake->attrs()->get(state.symbols.create("outputs"));
assert(aOutputs);
return aOutputs->value;
};
return aOutputs->value;
};
if (fingerprint) {
auto search = state.evalCaches.find(fingerprint.value());
if (search == state.evalCaches.end()) {
search = state.evalCaches.emplace(fingerprint.value(), make_ref<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader)).first;
search =
state.evalCaches
.emplace(fingerprint.value(), make_ref<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader))
.first;
}
return search->second;
} else {
@@ -479,8 +473,7 @@ ref<eval_cache::EvalCache> openEvalCache(
}
}
Installables SourceExprCommand::parseInstallables(
ref<Store> store, std::vector<std::string> ss)
Installables SourceExprCommand::parseInstallables(ref<Store> store, std::vector<std::string> ss)
{
Installables result;
@@ -501,12 +494,10 @@ Installables SourceExprCommand::parseInstallables(
if (file == "-") {
auto e = state->parseStdin();
state->eval(e, *vFile);
}
else if (file) {
} else if (file) {
auto dir = absPath(getCommandBaseDir());
state->evalFile(lookupFileArg(*state, *file, &dir), *vFile);
}
else {
} else {
Path dir = absPath(getCommandBaseDir());
auto e = state->parseExprFromString(*expr, state->rootPath(dir));
state->eval(e, *vFile);
@@ -515,9 +506,8 @@ Installables SourceExprCommand::parseInstallables(
for (auto & s : ss) {
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
result.push_back(
make_ref<InstallableAttrPath>(
InstallableAttrPath::parse(
state, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
make_ref<InstallableAttrPath>(InstallableAttrPath::parse(
state, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
}
} else {
@@ -532,8 +522,9 @@ Installables SourceExprCommand::parseInstallables(
if (prefix.find('/') != std::string::npos) {
try {
result.push_back(make_ref<InstallableDerivedPath>(
InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec.raw)));
result.push_back(
make_ref<InstallableDerivedPath>(
InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec.raw)));
continue;
} catch (BadStorePath &) {
} catch (...) {
@@ -543,9 +534,10 @@ Installables SourceExprCommand::parseInstallables(
}
try {
auto [flakeRef, fragment] = parseFlakeRefWithFragment(
fetchSettings, std::string { prefix }, absPath(getCommandBaseDir()));
result.push_back(make_ref<InstallableFlake>(
auto [flakeRef, fragment] =
parseFlakeRefWithFragment(fetchSettings, std::string{prefix}, absPath(getCommandBaseDir()));
result.push_back(
make_ref<InstallableFlake>(
this,
getEvalState(),
std::move(flakeRef),
@@ -566,8 +558,7 @@ Installables SourceExprCommand::parseInstallables(
return result;
}
ref<Installable> SourceExprCommand::parseInstallable(
ref<Store> store, const std::string & installable)
ref<Installable> SourceExprCommand::parseInstallable(ref<Store> store, const std::string & installable)
{
auto installables = parseInstallables(store, {installable});
assert(installables.size() == 1);
@@ -578,20 +569,18 @@ static SingleBuiltPath getBuiltPath(ref<Store> evalStore, ref<Store> store, cons
{
return std::visit(
overloaded{
[&](const SingleDerivedPath::Opaque & bo) -> SingleBuiltPath {
return SingleBuiltPath::Opaque { bo.path };
},
[&](const SingleDerivedPath::Opaque & bo) -> SingleBuiltPath { return SingleBuiltPath::Opaque{bo.path}; },
[&](const SingleDerivedPath::Built & bfd) -> SingleBuiltPath {
auto drvPath = getBuiltPath(evalStore, store, *bfd.drvPath);
// Resolving this instead of `bfd` will yield the same result, but avoid duplicative work.
SingleDerivedPath::Built truncatedBfd {
SingleDerivedPath::Built truncatedBfd{
.drvPath = makeConstantStorePathRef(drvPath.outPath()),
.output = bfd.output,
};
auto outputPath = resolveDerivedPath(*store, truncatedBfd, &*evalStore);
return SingleBuiltPath::Built {
return SingleBuiltPath::Built{
.drvPath = make_ref<SingleBuiltPath>(std::move(drvPath)),
.output = { bfd.output, outputPath },
.output = {bfd.output, outputPath},
};
},
},
@@ -599,11 +588,7 @@ static SingleBuiltPath getBuiltPath(ref<Store> evalStore, ref<Store> store, cons
}
std::vector<BuiltPathWithResult> Installable::build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
const Installables & installables,
BuildMode bMode)
ref<Store> evalStore, ref<Store> store, Realise mode, const Installables & installables, BuildMode bMode)
{
std::vector<BuiltPathWithResult> res;
for (auto & [_, builtPathWithResult] : build2(evalStore, store, mode, installables, bMode))
@@ -611,9 +596,7 @@ std::vector<BuiltPathWithResult> Installable::build(
return res;
}
static void throwBuildErrors(
std::vector<KeyedBuildResult> & buildResults,
const Store & store)
static void throwBuildErrors(std::vector<KeyedBuildResult> & buildResults, const Store & store)
{
std::vector<KeyedBuildResult> failed;
for (auto & buildResult : buildResults) {
@@ -630,10 +613,11 @@ static void throwBuildErrors(
StringSet failedPaths;
for (; failedResult != failed.end(); failedResult++) {
if (!failedResult->errorMsg.empty()) {
logError(ErrorInfo{
.level = lvlError,
.msg = failedResult->errorMsg,
});
logError(
ErrorInfo{
.level = lvlError,
.msg = failedResult->errorMsg,
});
}
failedPaths.insert(failedResult->path.to_string(store));
}
@@ -643,11 +627,7 @@ static void throwBuildErrors(
}
std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
const Installables & installables,
BuildMode bMode)
ref<Store> evalStore, ref<Store> store, Realise mode, const Installables & installables, BuildMode bMode)
{
if (mode == Realise::Nothing)
settings.readOnlyMode = true;
@@ -678,22 +658,25 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
for (auto & path : pathsToBuild) {
for (auto & aux : backmap[path]) {
std::visit(overloaded {
[&](const DerivedPath::Built & bfd) {
auto outputs = resolveDerivedPath(*store, bfd, &*evalStore);
res.push_back({aux.installable, {
.path = BuiltPath::Built {
.drvPath = make_ref<SingleBuiltPath>(getBuiltPath(evalStore, store, *bfd.drvPath)),
.outputs = outputs,
},
.info = aux.info}});
std::visit(
overloaded{
[&](const DerivedPath::Built & bfd) {
auto outputs = resolveDerivedPath(*store, bfd, &*evalStore);
res.push_back(
{aux.installable,
{.path =
BuiltPath::Built{
.drvPath =
make_ref<SingleBuiltPath>(getBuiltPath(evalStore, store, *bfd.drvPath)),
.outputs = outputs,
},
.info = aux.info}});
},
[&](const DerivedPath::Opaque & bo) {
res.push_back({aux.installable, {.path = BuiltPath::Opaque{bo.path}, .info = aux.info}});
},
},
[&](const DerivedPath::Opaque & bo) {
res.push_back({aux.installable, {
.path = BuiltPath::Opaque { bo.path },
.info = aux.info}});
},
}, path.raw());
path.raw());
}
}
@@ -707,26 +690,30 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
throwBuildErrors(buildResults, *store);
for (auto & buildResult : buildResults) {
for (auto & aux : backmap[buildResult.path]) {
std::visit(overloaded {
[&](const DerivedPath::Built & bfd) {
std::map<std::string, StorePath> outputs;
for (auto & [outputName, realisation] : buildResult.builtOutputs)
outputs.emplace(outputName, realisation.outPath);
res.push_back({aux.installable, {
.path = BuiltPath::Built {
.drvPath = make_ref<SingleBuiltPath>(getBuiltPath(evalStore, store, *bfd.drvPath)),
.outputs = outputs,
},
.info = aux.info,
.result = buildResult}});
std::visit(
overloaded{
[&](const DerivedPath::Built & bfd) {
std::map<std::string, StorePath> outputs;
for (auto & [outputName, realisation] : buildResult.builtOutputs)
outputs.emplace(outputName, realisation.outPath);
res.push_back(
{aux.installable,
{.path =
BuiltPath::Built{
.drvPath =
make_ref<SingleBuiltPath>(getBuiltPath(evalStore, store, *bfd.drvPath)),
.outputs = outputs,
},
.info = aux.info,
.result = buildResult}});
},
[&](const DerivedPath::Opaque & bo) {
res.push_back(
{aux.installable,
{.path = BuiltPath::Opaque{bo.path}, .info = aux.info, .result = buildResult}});
},
},
[&](const DerivedPath::Opaque & bo) {
res.push_back({aux.installable, {
.path = BuiltPath::Opaque { bo.path },
.info = aux.info,
.result = buildResult}});
},
}, buildResult.path.raw());
buildResult.path.raw());
}
}
@@ -741,11 +728,7 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
}
BuiltPaths Installable::toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const Installables & installables)
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables)
{
if (operateOn == OperateOn::Output) {
BuiltPaths res;
@@ -764,10 +747,7 @@ BuiltPaths Installable::toBuiltPaths(
}
StorePathSet Installable::toStorePathSet(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
const Installables & installables)
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables)
{
StorePathSet outPaths;
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
@@ -778,10 +758,7 @@ StorePathSet Installable::toStorePathSet(
}
StorePaths Installable::toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
const Installables & installables)
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, const Installables & installables)
{
StorePaths outPaths;
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
@@ -792,10 +769,7 @@ StorePaths Installable::toStorePaths(
}
StorePath Installable::toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
ref<Installable> installable)
ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, ref<Installable> installable)
{
auto paths = toStorePathSet(evalStore, store, mode, operateOn, {installable});
@@ -805,28 +779,23 @@ StorePath Installable::toStorePath(
return *paths.begin();
}
StorePathSet Installable::toDerivations(
ref<Store> store,
const Installables & installables,
bool useDeriver)
StorePathSet Installable::toDerivations(ref<Store> store, const Installables & installables, bool useDeriver)
{
StorePathSet drvPaths;
for (const auto & i : installables)
for (const auto & b : i->toDerivedPaths())
std::visit(overloaded {
[&](const DerivedPath::Opaque & bo) {
drvPaths.insert(
bo.path.isDerivation()
? bo.path
: useDeriver
? getDeriver(store, *i, bo.path)
: throw Error("argument '%s' did not evaluate to a derivation", i->what()));
std::visit(
overloaded{
[&](const DerivedPath::Opaque & bo) {
drvPaths.insert(
bo.path.isDerivation() ? bo.path
: useDeriver ? getDeriver(store, *i, bo.path)
: throw Error("argument '%s' did not evaluate to a derivation", i->what()));
},
[&](const DerivedPath::Built & bfd) { drvPaths.insert(resolveDerivedPath(*store, *bfd.drvPath)); },
},
[&](const DerivedPath::Built & bfd) {
drvPaths.insert(resolveDerivedPath(*store, *bfd.drvPath));
},
}, b.path.raw());
b.path.raw());
return drvPaths;
}
@@ -861,10 +830,7 @@ std::vector<FlakeRef> RawInstallablesCommand::getFlakeRefsForCompletion()
std::vector<FlakeRef> res;
res.reserve(rawInstallables.size());
for (const auto & i : rawInstallables)
res.push_back(parseFlakeRefWithFragment(
fetchSettings,
expandTilde(i),
absPath(getCommandBaseDir())).first);
res.push_back(parseFlakeRefWithFragment(fetchSettings, expandTilde(i), absPath(getCommandBaseDir())).first);
return res;
}
@@ -883,12 +849,7 @@ void RawInstallablesCommand::run(ref<Store> store)
std::vector<FlakeRef> InstallableCommand::getFlakeRefsForCompletion()
{
return {
parseFlakeRefWithFragment(
fetchSettings,
expandTilde(_installable),
absPath(getCommandBaseDir())).first
};
return {parseFlakeRefWithFragment(fetchSettings, expandTilde(_installable), absPath(getCommandBaseDir())).first};
}
void InstallablesCommand::run(ref<Store> store, std::vector<std::string> && rawInstallables)
@@ -928,4 +889,4 @@ BuiltPaths toBuiltPaths(const std::vector<BuiltPathWithResult> & builtPathsWithR
return res;
}
}
} // namespace nix

View File

@@ -18,25 +18,24 @@ static std::string doRenderMarkdownToTerminal(std::string_view markdown)
{
int windowWidth = getWindowSize().second;
#if HAVE_LOWDOWN_1_4
struct lowdown_opts_term opts_term {
# if HAVE_LOWDOWN_1_4
struct lowdown_opts_term opts_term{
.cols = (size_t) std::max(windowWidth - 5, 60),
.hmargin = 0,
.vmargin = 0,
};
#endif
struct lowdown_opts opts
{
# endif
struct lowdown_opts opts{
.type = LOWDOWN_TERM,
#if HAVE_LOWDOWN_1_4
# if HAVE_LOWDOWN_1_4
.term = opts_term,
#endif
# endif
.maxdepth = 20,
#if !HAVE_LOWDOWN_1_4
# if !HAVE_LOWDOWN_1_4
.cols = (size_t) std::max(windowWidth - 5, 60),
.hmargin = 0,
.vmargin = 0,
#endif
# endif
.feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES,
.oflags = LOWDOWN_TERM_NOLINK,
};

View File

@@ -1,7 +1,6 @@
#include "nix/cmd/misc-store-flags.hh"
namespace nix::flag
{
namespace nix::flag {
static void hashFormatCompleter(AddCompletions & completions, size_t index, std::string_view prefix)
{
@@ -15,27 +14,23 @@ static void hashFormatCompleter(AddCompletions & completions, size_t index, std:
Args::Flag hashFormatWithDefault(std::string && longName, HashFormat * hf)
{
assert(*hf == nix::HashFormat::SRI);
return Args::Flag {
.longName = std::move(longName),
.description = "Hash format (`base16`, `nix32`, `base64`, `sri`). Default: `sri`.",
.labels = {"hash-format"},
.handler = {[hf](std::string s) {
*hf = parseHashFormat(s);
}},
.completer = hashFormatCompleter,
return Args::Flag{
.longName = std::move(longName),
.description = "Hash format (`base16`, `nix32`, `base64`, `sri`). Default: `sri`.",
.labels = {"hash-format"},
.handler = {[hf](std::string s) { *hf = parseHashFormat(s); }},
.completer = hashFormatCompleter,
};
}
Args::Flag hashFormatOpt(std::string && longName, std::optional<HashFormat> * ohf)
{
return Args::Flag {
.longName = std::move(longName),
.description = "Hash format (`base16`, `nix32`, `base64`, `sri`).",
.labels = {"hash-format"},
.handler = {[ohf](std::string s) {
*ohf = std::optional<HashFormat>{parseHashFormat(s)};
}},
.completer = hashFormatCompleter,
return Args::Flag{
.longName = std::move(longName),
.description = "Hash format (`base16`, `nix32`, `base64`, `sri`).",
.labels = {"hash-format"},
.handler = {[ohf](std::string s) { *ohf = std::optional<HashFormat>{parseHashFormat(s)}; }},
.completer = hashFormatCompleter,
};
}
@@ -48,34 +43,31 @@ static void hashAlgoCompleter(AddCompletions & completions, size_t index, std::s
Args::Flag hashAlgo(std::string && longName, HashAlgorithm * ha)
{
return Args::Flag {
.longName = std::move(longName),
.description = "Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`).",
.labels = {"hash-algo"},
.handler = {[ha](std::string s) {
*ha = parseHashAlgo(s);
}},
.completer = hashAlgoCompleter,
return Args::Flag{
.longName = std::move(longName),
.description = "Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`).",
.labels = {"hash-algo"},
.handler = {[ha](std::string s) { *ha = parseHashAlgo(s); }},
.completer = hashAlgoCompleter,
};
}
Args::Flag hashAlgoOpt(std::string && longName, std::optional<HashAlgorithm> * oha)
{
return Args::Flag {
.longName = std::move(longName),
.description = "Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`). Can be omitted for SRI hashes.",
.labels = {"hash-algo"},
.handler = {[oha](std::string s) {
*oha = std::optional<HashAlgorithm>{parseHashAlgo(s)};
}},
.completer = hashAlgoCompleter,
return Args::Flag{
.longName = std::move(longName),
.description =
"Hash algorithm (`blake3`, `md5`, `sha1`, `sha256`, or `sha512`). Can be omitted for SRI hashes.",
.labels = {"hash-algo"},
.handler = {[oha](std::string s) { *oha = std::optional<HashAlgorithm>{parseHashAlgo(s)}; }},
.completer = hashAlgoCompleter,
};
}
Args::Flag fileIngestionMethod(FileIngestionMethod * method)
{
return Args::Flag {
.longName = "mode",
return Args::Flag{
.longName = "mode",
// FIXME indentation carefully made for context, this is messed up.
.description = R"(
How to compute the hash of the input.
@@ -92,16 +84,14 @@ Args::Flag fileIngestionMethod(FileIngestionMethod * method)
it to the hash function.
)",
.labels = {"file-ingestion-method"},
.handler = {[method](std::string s) {
*method = parseFileIngestionMethod(s);
}},
.handler = {[method](std::string s) { *method = parseFileIngestionMethod(s); }},
};
}
Args::Flag contentAddressMethod(ContentAddressMethod * method)
{
return Args::Flag {
.longName = "mode",
return Args::Flag{
.longName = "mode",
// FIXME indentation carefully made for context, this is messed up.
.description = R"(
How to compute the content-address of the store object.
@@ -126,10 +116,8 @@ Args::Flag contentAddressMethod(ContentAddressMethod * method)
for regular usage prefer `nar` and `flat`.
)",
.labels = {"content-address-method"},
.handler = {[method](std::string s) {
*method = ContentAddressMethod::parse(s);
}},
.handler = {[method](std::string s) { *method = ContentAddressMethod::parse(s); }},
};
}
}
} // namespace nix::flag

View File

@@ -47,4 +47,4 @@ bool haveNetworkProxyConnection()
return false;
}
}
} // namespace nix

View File

@@ -53,7 +53,8 @@ mkMesonLibrary (finalAttrs: {
buildInputs = [
({ inherit editline readline; }.${readlineFlavor})
] ++ lib.optional enableMarkdown lowdown;
]
++ lib.optional enableMarkdown lowdown;
propagatedBuildInputs = [
nix-util

View File

@@ -3,8 +3,8 @@
#include <cstdio>
#if USE_READLINE
#include <readline/history.h>
#include <readline/readline.h>
# include <readline/history.h>
# include <readline/readline.h>
#else
// editline < 1.15.2 don't wrap their API for C++ usage
// (added in https://github.com/troglobit/editline/commit/91398ceb3427b730995357e9d120539fb9bb7461).
@@ -12,7 +12,7 @@
// For compatibility with these versions, we wrap the API here
// (wrapping multiple times on newer versions is no problem).
extern "C" {
#include <editline.h>
# include <editline.h>
}
#endif
@@ -33,7 +33,7 @@ void sigintHandler(int signo)
{
g_signal_received = signo;
}
};
}; // namespace
static detail::ReplCompleterMixin * curRepl; // ugly
@@ -183,8 +183,7 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT
// editline doesn't echo the input to the output when non-interactive, unlike readline
// this results in a different behavior when running tests. The echoing is
// quite useful for reading the test output, so we add it here.
if (auto e = getEnv("_NIX_TEST_REPL_ECHO"); s && e && *e == "1")
{
if (auto e = getEnv("_NIX_TEST_REPL_ECHO"); s && e && *e == "1") {
#if !USE_READLINE
// This is probably not right for multi-line input, but we don't use that
// in the characterisation tests, so it's fine.
@@ -205,4 +204,4 @@ ReadlineLikeInteracter::~ReadlineLikeInteracter()
write_history(historyFile.c_str());
}
};
}; // namespace nix

View File

@@ -54,10 +54,7 @@ enum class ProcessLineResult {
PromptAgain,
};
struct NixRepl
: AbstractNixRepl
, detail::ReplCompleterMixin
, gc
struct NixRepl : AbstractNixRepl, detail::ReplCompleterMixin, gc
{
size_t debugTraceIndex;
@@ -79,8 +76,12 @@ struct NixRepl
std::unique_ptr<ReplInteracter> interacter;
NixRepl(const LookupPath & lookupPath, nix::ref<Store> store,ref<EvalState> state,
std::function<AnnotatedValues()> getValues, RunNix * runNix);
NixRepl(
const LookupPath & lookupPath,
nix::ref<Store> store,
ref<EvalState> state,
std::function<AnnotatedValues()> getValues,
RunNix * runNix);
virtual ~NixRepl() = default;
ReplExitStatus mainLoop() override;
@@ -101,20 +102,22 @@ struct NixRepl
void evalString(std::string s, Value & v);
void loadDebugTraceEnv(DebugTrace & dt);
void printValue(std::ostream & str,
Value & v,
unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
void printValue(std::ostream & str, Value & v, unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
{
// Hide the progress bar during printing because it might interfere
auto suspension = logger->suspend();
::nix::printValue(*state, str, v, PrintOptions {
.ansiColors = true,
.force = true,
.derivationPaths = true,
.maxDepth = maxDepth,
.prettyIndent = 2,
.errors = ErrorPrintBehavior::ThrowTopLevel,
});
::nix::printValue(
*state,
str,
v,
PrintOptions{
.ansiColors = true,
.force = true,
.derivationPaths = true,
.maxDepth = maxDepth,
.prettyIndent = 2,
.errors = ErrorPrintBehavior::ThrowTopLevel,
});
}
};
@@ -122,13 +125,17 @@ std::string removeWhitespace(std::string s)
{
s = chomp(s);
size_t n = s.find_first_not_of(" \n\r\t");
if (n != std::string::npos) s = std::string(s, n);
if (n != std::string::npos)
s = std::string(s, n);
return s;
}
NixRepl::NixRepl(const LookupPath & lookupPath, nix::ref<Store> store, ref<EvalState> state,
std::function<NixRepl::AnnotatedValues()> getValues, RunNix * runNix)
NixRepl::NixRepl(
const LookupPath & lookupPath,
nix::ref<Store> store,
ref<EvalState> state,
std::function<NixRepl::AnnotatedValues()> getValues,
RunNix * runNix)
: AbstractNixRepl(state)
, debugTraceIndex(0)
, getValues(getValues)
@@ -184,7 +191,8 @@ ReplExitStatus NixRepl::mainLoop()
auto suspension = logger->suspend();
// When continuing input from previous lines, don't print a prompt, just align to the same
// number of chars as the prompt.
if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
if (!interacter->getLine(
input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
// Ctrl-D should exit the debugger.
state->debugStop = false;
logger->cout("");
@@ -196,14 +204,14 @@ ReplExitStatus NixRepl::mainLoop()
}
try {
switch (processLine(input)) {
case ProcessLineResult::Quit:
return ReplExitStatus::QuitAll;
case ProcessLineResult::Continue:
return ReplExitStatus::Continue;
case ProcessLineResult::PromptAgain:
break;
default:
unreachable();
case ProcessLineResult::Quit:
return ReplExitStatus::QuitAll;
case ProcessLineResult::Continue:
return ReplExitStatus::Continue;
case ProcessLineResult::PromptAgain:
break;
default:
unreachable();
}
} catch (ParseError & e) {
if (e.msg().find("unexpected end of file") != std::string::npos) {
@@ -211,7 +219,7 @@ ReplExitStatus NixRepl::mainLoop()
// input without clearing the input so far.
continue;
} else {
printMsg(lvlError, e.msg());
printMsg(lvlError, e.msg());
}
} catch (EvalError & e) {
printMsg(lvlError, e.msg());
@@ -260,7 +268,8 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
/* This is a variable name; look it up in the current scope. */
StringSet::iterator i = varNames.lower_bound(cur);
while (i != varNames.end()) {
if (i->substr(0, cur.size()) != cur) break;
if (i->substr(0, cur.size()) != cur)
break;
completions.insert(prev + *i);
i++;
}
@@ -279,11 +288,15 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
Expr * e = parseString(expr);
Value v;
e->eval(*state, *env, v);
state->forceAttrs(v, noPos, "while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
state->forceAttrs(
v,
noPos,
"while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
for (auto & i : *v.attrs()) {
std::string_view name = state->symbols[i.name];
if (name.substr(0, cur2.size()) != cur2) continue;
if (name.substr(0, cur2.size()) != cur2)
continue;
completions.insert(concatStrings(prev, expr, ".", name));
}
@@ -301,24 +314,23 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
return completions;
}
// FIXME: DRY and match or use the parser
static bool isVarName(std::string_view s)
{
if (s.size() == 0) return false;
if (s.size() == 0)
return false;
char c = s[0];
if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false;
if ((c >= '0' && c <= '9') || c == '-' || c == '\'')
return false;
for (auto & i : s)
if (!((i >= 'a' && i <= 'z') ||
(i >= 'A' && i <= 'Z') ||
(i >= '0' && i <= '9') ||
i == '_' || i == '-' || i == '\''))
if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_' || i == '-'
|| i == '\''))
return false;
return true;
}
StorePath NixRepl::getDerivationPath(Value & v) {
StorePath NixRepl::getDerivationPath(Value & v)
{
auto packageInfo = getDerivation(*state, v, false);
if (!packageInfo)
throw Error("expression does not evaluate to a derivation, so I can't build it");
@@ -357,52 +369,49 @@ ProcessLineResult NixRepl::processLine(std::string line)
if (line[0] == ':') {
size_t p = line.find_first_of(" \n\r\t");
command = line.substr(0, p);
if (p != std::string::npos) arg = removeWhitespace(line.substr(p));
if (p != std::string::npos)
arg = removeWhitespace(line.substr(p));
} else {
arg = line;
}
if (command == ":?" || command == ":help") {
// FIXME: convert to Markdown, include in the 'nix repl' manpage.
std::cout
<< "The following commands are available:\n"
<< "\n"
<< " <expr> Evaluate and print expression\n"
<< " <x> = <expr> Bind expression to variable\n"
<< " :a, :add <expr> Add attributes from resulting set to scope\n"
<< " :b <expr> Build a derivation\n"
<< " :bl <expr> Build a derivation, creating GC roots in the\n"
<< " working directory\n"
<< " :e, :edit <expr> Open package or function in $EDITOR\n"
<< " :i <expr> Build derivation, then install result into\n"
<< " current profile\n"
<< " :l, :load <path> Load Nix expression and add it to scope\n"
<< " :lf, :load-flake <ref> Load Nix flake and add it to scope\n"
<< " :p, :print <expr> Evaluate and print expression recursively\n"
<< " Strings are printed directly, without escaping.\n"
<< " :q, :quit Exit nix-repl\n"
<< " :r, :reload Reload all files\n"
<< " :sh <expr> Build dependencies of derivation, then start\n"
<< " nix-shell\n"
<< " :t <expr> Describe result of evaluation\n"
<< " :u <expr> Build derivation, then start nix-shell\n"
<< " :doc <expr> Show documentation of a builtin function\n"
<< " :log <expr> Show logs for a derivation\n"
<< " :te, :trace-enable [bool] Enable, disable or toggle showing traces for\n"
<< " errors\n"
<< " :?, :help Brings up this help menu\n"
;
std::cout << "The following commands are available:\n"
<< "\n"
<< " <expr> Evaluate and print expression\n"
<< " <x> = <expr> Bind expression to variable\n"
<< " :a, :add <expr> Add attributes from resulting set to scope\n"
<< " :b <expr> Build a derivation\n"
<< " :bl <expr> Build a derivation, creating GC roots in the\n"
<< " working directory\n"
<< " :e, :edit <expr> Open package or function in $EDITOR\n"
<< " :i <expr> Build derivation, then install result into\n"
<< " current profile\n"
<< " :l, :load <path> Load Nix expression and add it to scope\n"
<< " :lf, :load-flake <ref> Load Nix flake and add it to scope\n"
<< " :p, :print <expr> Evaluate and print expression recursively\n"
<< " Strings are printed directly, without escaping.\n"
<< " :q, :quit Exit nix-repl\n"
<< " :r, :reload Reload all files\n"
<< " :sh <expr> Build dependencies of derivation, then start\n"
<< " nix-shell\n"
<< " :t <expr> Describe result of evaluation\n"
<< " :u <expr> Build derivation, then start nix-shell\n"
<< " :doc <expr> Show documentation of a builtin function\n"
<< " :log <expr> Show logs for a derivation\n"
<< " :te, :trace-enable [bool] Enable, disable or toggle showing traces for\n"
<< " errors\n"
<< " :?, :help Brings up this help menu\n";
if (state->debugRepl) {
std::cout
<< "\n"
<< " Debug mode commands\n"
<< " :env Show env stack\n"
<< " :bt, :backtrace Show trace stack\n"
<< " :st Show current trace\n"
<< " :st <idx> Change to another trace in the stack\n"
<< " :c, :continue Go until end of program, exception, or builtins.break\n"
<< " :s, :step Go one step\n"
;
std::cout << "\n"
<< " Debug mode commands\n"
<< " :env Show env stack\n"
<< " :bt, :backtrace Show trace stack\n"
<< " :st Show current trace\n"
<< " :st <idx> Change to another trace in the stack\n"
<< " :c, :continue Go until end of program, exception, or builtins.break\n"
<< " :s, :step Go one step\n";
}
}
@@ -427,17 +436,18 @@ ProcessLineResult NixRepl::processLine(std::string line)
try {
// change the DebugTrace index.
debugTraceIndex = stoi(arg);
} catch (...) { }
} catch (...) {
}
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
if (idx == debugTraceIndex) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state->positions, i);
std::cout << std::endl;
printEnvBindings(*state, i.expr, i.env);
loadDebugTraceEnv(i);
break;
}
if (idx == debugTraceIndex) {
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
showDebugTrace(std::cout, state->positions, i);
std::cout << std::endl;
printEnvBindings(*state, i.expr, i.env);
loadDebugTraceEnv(i);
break;
}
}
}
@@ -477,7 +487,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
Value v;
evalString(arg, v);
const auto [path, line] = [&] () -> std::pair<SourcePath, uint32_t> {
const auto [path, line] = [&]() -> std::pair<SourcePath, uint32_t> {
if (v.type() == nPath || v.type() == nString) {
NixStringContext context;
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
@@ -501,7 +511,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
// runProgram redirects stdout to a StringSink,
// using runProgram2 to allow editors to display their UI
runProgram2(RunOptions { .program = editor, .lookupPath = true, .args = args , .isInteractive = true });
runProgram2(RunOptions{.program = editor, .lookupPath = true, .args = args, .isInteractive = true});
// Reload right after exiting the editor
state->resetFileCache();
@@ -532,9 +542,9 @@ ProcessLineResult NixRepl::processLine(std::string line)
if (command == ":b" || command == ":bl") {
state->store->buildPaths({
DerivedPath::Built {
DerivedPath::Built{
.drvPath = makeConstantStorePathRef(drvPath),
.outputs = OutputsSpec::All { },
.outputs = OutputsSpec::All{},
},
});
auto drv = state->store->readDerivation(drvPath);
@@ -553,9 +563,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
runNix("nix-env", {"-i", drvPathRaw});
} else if (command == ":log") {
settings.readOnlyMode = true;
Finally roModeReset([&]() {
settings.readOnlyMode = false;
});
Finally roModeReset([&]() { settings.readOnlyMode = false; });
auto subs = getDefaultSubstituters();
subs.push_front(state->store);
@@ -578,7 +586,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
break;
}
}
if (!foundLog) throw Error("build log of '%s' is not available", drvPathRaw);
if (!foundLog)
throw Error("build log of '%s' is not available", drvPathRaw);
} else {
runNix("nix-shell", {drvPathRaw});
}
@@ -641,9 +650,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
for (auto & arg : args)
arg = "*" + arg + "*";
markdown +=
"**Synopsis:** `builtins." + (std::string) (*doc->name) + "` "
+ concatStringsSep(" ", args) + "\n\n";
markdown += "**Synopsis:** `builtins." + (std::string) (*doc->name) + "` " + concatStringsSep(" ", args)
+ "\n\n";
}
markdown += stripIndentation(doc->doc);
@@ -684,11 +692,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
else {
size_t p = line.find('=');
std::string name;
if (p != std::string::npos &&
p < line.size() &&
line[p + 1] != '=' &&
isVarName(name = removeWhitespace(line.substr(0, p))))
{
if (p != std::string::npos && p < line.size() && line[p + 1] != '='
&& isVarName(name = removeWhitespace(line.substr(0, p)))) {
Expr * e = parseString(line.substr(p + 1));
Value & v(*state->allocValue());
v.mkThunk(env, e);
@@ -736,9 +741,13 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
Value v;
flake::callFlake(*state,
flake::lockFlake(flakeSettings, *state, flakeRef,
flake::LockFlags {
flake::callFlake(
*state,
flake::lockFlake(
flakeSettings,
*state,
flakeRef,
flake::LockFlags{
.updateLockFile = false,
.useRegistries = !evalSettings.pureEval,
.allowUnlocked = !evalSettings.pureEval,
@@ -747,7 +756,6 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
addAttrsToScope(v);
}
void NixRepl::initEnv()
{
env = &state->allocEnv(envSize);
@@ -760,7 +768,6 @@ void NixRepl::initEnv()
varNames.emplace(state->symbols[i.first]);
}
void NixRepl::reloadFilesAndFlakes()
{
initEnv();
@@ -769,7 +776,6 @@ void NixRepl::reloadFilesAndFlakes()
loadFlakes();
}
void NixRepl::loadFiles()
{
Strings old = loadedFiles;
@@ -786,7 +792,6 @@ void NixRepl::loadFiles()
}
}
void NixRepl::loadFlakes()
{
Strings old = loadedFlakes;
@@ -798,10 +803,12 @@ void NixRepl::loadFlakes()
}
}
void NixRepl::addAttrsToScope(Value & attrs)
{
state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }, "while evaluating an attribute set to be merged in the global scope");
state->forceAttrs(
attrs,
[&]() { return attrs.determinePos(noPos); },
"while evaluating an attribute set to be merged in the global scope");
if (displ + attrs.attrs()->size() >= envSize)
throw Error("environment full; cannot add more variables");
@@ -815,7 +822,6 @@ void NixRepl::addAttrsToScope(Value & attrs)
notice("Added %1% variables.", attrs.attrs()->size());
}
void NixRepl::addVarToScope(const Symbol name, Value & v)
{
if (displ >= envSize)
@@ -828,13 +834,11 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
varNames.emplace(state->symbols[name]);
}
Expr * NixRepl::parseString(std::string s)
{
return state->parseExprFromString(std::move(s), state->rootPath("."), staticEnv);
}
void NixRepl::evalString(std::string s, Value & v)
{
Expr * e = parseString(s);
@@ -842,46 +846,39 @@ void NixRepl::evalString(std::string s, Value & v)
state->forceValue(v, v.determinePos(noPos));
}
void NixRepl::runNix(Path program, const Strings & args, const std::optional<std::string> & input)
{
if (runNixPtr)
(*runNixPtr)(program, args, input);
else
throw Error("Cannot run '%s' because no method of calling the Nix CLI was provided. This is a configuration problem pertaining to how this program was built. See Nix 2.25 release notes", program);
throw Error(
"Cannot run '%s' because no method of calling the Nix CLI was provided. This is a configuration problem pertaining to how this program was built. See Nix 2.25 release notes",
program);
}
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
const LookupPath & lookupPath, nix::ref<Store> store, ref<EvalState> state,
std::function<AnnotatedValues()> getValues, RunNix * runNix)
const LookupPath & lookupPath,
nix::ref<Store> store,
ref<EvalState> state,
std::function<AnnotatedValues()> getValues,
RunNix * runNix)
{
return std::make_unique<NixRepl>(
lookupPath,
std::move(store),
state,
getValues,
runNix
);
return std::make_unique<NixRepl>(lookupPath, std::move(store), state, getValues, runNix);
}
ReplExitStatus AbstractNixRepl::runSimple(
ref<EvalState> evalState,
const ValMap & extraEnv)
ReplExitStatus AbstractNixRepl::runSimple(ref<EvalState> evalState, const ValMap & extraEnv)
{
auto getValues = [&]()->NixRepl::AnnotatedValues{
auto getValues = [&]() -> NixRepl::AnnotatedValues {
NixRepl::AnnotatedValues values;
return values;
};
LookupPath lookupPath = {};
auto repl = std::make_unique<NixRepl>(
lookupPath,
openStore(),
evalState,
getValues,
/*runNix=*/nullptr
);
lookupPath,
openStore(),
evalState,
getValues,
/*runNix=*/nullptr);
repl->initEnv();
@@ -892,4 +889,4 @@ ReplExitStatus AbstractNixRepl::runSimple(
return repl->mainLoop();
}
}
} // namespace nix

View File

@@ -31,13 +31,11 @@
* @param init Function that takes a T* and returns the initializer for T
* @return Pointer to allocated and initialized object
*/
template <typename T, typename F>
template<typename T, typename F>
static T * unsafe_new_with_self(F && init)
{
// Allocate
void * p = ::operator new(
sizeof(T),
static_cast<std::align_val_t>(alignof(T)));
void * p = ::operator new(sizeof(T), static_cast<std::align_val_t>(alignof(T)));
// Initialize with placement new
return new (p) T(init(static_cast<T *>(p)));
}
@@ -86,12 +84,13 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n
NIXC_CATCH_ERRS
}
nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value)
nix_err nix_value_call_multi(
nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value)
{
if (context)
context->last_err_code = NIX_OK;
try {
state->state.callFunction(fn->value, {(nix::Value * *) args, nargs}, value->value, nix::noPos);
state->state.callFunction(fn->value, {(nix::Value **) args, nargs}, value->value, nix::noPos);
state->state.forceValue(value->value, nix::noPos);
}
NIXC_CATCH_ERRS
@@ -152,7 +151,8 @@ nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_buil
NIXC_CATCH_ERRS
}
nix_err nix_eval_state_builder_set_lookup_path(nix_c_context * context, nix_eval_state_builder * builder, const char ** lookupPath_c)
nix_err nix_eval_state_builder_set_lookup_path(
nix_c_context * context, nix_eval_state_builder * builder, const char ** lookupPath_c)
{
if (context)
context->last_err_code = NIX_OK;
@@ -175,11 +175,7 @@ EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder
return EvalState{
.fetchSettings = std::move(builder->fetchSettings),
.settings = std::move(builder->settings),
.state = nix::EvalState(
builder->lookupPath,
builder->store,
self->fetchSettings,
self->settings),
.state = nix::EvalState(builder->lookupPath, builder->store, self->fetchSettings, self->settings),
};
});
}
@@ -195,11 +191,10 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
if (nix_eval_state_builder_load(context, builder) != NIX_OK)
return nullptr;
if (nix_eval_state_builder_set_lookup_path(context, builder, lookupPath_c)
!= NIX_OK)
if (nix_eval_state_builder_set_lookup_path(context, builder, lookupPath_c) != NIX_OK)
return nullptr;
auto *state = nix_eval_state_build(context, builder);
auto * state = nix_eval_state_build(context, builder);
nix_eval_state_builder_free(builder);
return state;
}
@@ -265,20 +260,23 @@ nix_err nix_gc_incref(nix_c_context * context, const void *)
context->last_err_code = NIX_OK;
return NIX_OK;
}
nix_err nix_gc_decref(nix_c_context * context, const void *)
{
if (context)
context->last_err_code = NIX_OK;
return NIX_OK;
}
void nix_gc_now() {}
#endif
nix_err nix_value_incref(nix_c_context * context, nix_value *x)
nix_err nix_value_incref(nix_c_context * context, nix_value * x)
{
return nix_gc_incref(context, (const void *) x);
}
nix_err nix_value_decref(nix_c_context * context, nix_value *x)
nix_err nix_value_decref(nix_c_context * context, nix_value * x)
{
return nix_gc_decref(context, (const void *) x);
}

View File

@@ -48,11 +48,13 @@ class NixCExternalValue : public nix::ExternalValueBase
public:
NixCExternalValue(NixCExternalValueDesc & desc, void * v)
: desc(desc)
, v(v){};
, v(v) {};
void * get_ptr()
{
return v;
}
/**
* Print out the value
*/
@@ -155,11 +157,17 @@ public:
}
nix_string_context ctx{context};
desc.printValueAsXML(
v, (EvalState *) &state, strict, location, &doc, &ctx, &drvsSeen,
v,
(EvalState *) &state,
strict,
location,
&doc,
&ctx,
&drvsSeen,
*reinterpret_cast<const uint32_t *>(&pos));
}
virtual ~NixCExternalValue() override{};
virtual ~NixCExternalValue() override {};
};
ExternalValue * nix_create_external_value(nix_c_context * context, NixCExternalValueDesc * desc, void * v)

View File

@@ -16,141 +16,159 @@
#include "nix/store/tests/libstore.hh"
namespace nix {
class LibExprTest : public LibStoreTest {
public:
static void SetUpTestSuite() {
LibStoreTest::SetUpTestSuite();
initGC();
}
protected:
LibExprTest()
: LibStoreTest()
, state({}, store, fetchSettings, evalSettings, nullptr)
{
evalSettings.nixPath = {};
}
Value eval(std::string input, bool forceValue = true) {
Value v;
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
assert(e);
state.eval(e, v);
if (forceValue)
state.forceValue(v, noPos);
return v;
}
Value * maybeThunk(std::string input, bool forceValue = true) {
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
assert(e);
return e->maybeThunk(state, state.baseEnv);
}
Symbol createSymbol(const char * value) {
return state.symbols.create(value);
}
bool readOnlyMode = true;
fetchers::Settings fetchSettings{};
EvalSettings evalSettings{readOnlyMode};
EvalState state;
};
MATCHER(IsListType, "") {
return arg != nList;
class LibExprTest : public LibStoreTest
{
public:
static void SetUpTestSuite()
{
LibStoreTest::SetUpTestSuite();
initGC();
}
MATCHER(IsList, "") {
return arg.type() == nList;
protected:
LibExprTest()
: LibStoreTest()
, state({}, store, fetchSettings, evalSettings, nullptr)
{
evalSettings.nixPath = {};
}
MATCHER(IsString, "") {
return arg.type() == nString;
Value eval(std::string input, bool forceValue = true)
{
Value v;
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
assert(e);
state.eval(e, v);
if (forceValue)
state.forceValue(v, noPos);
return v;
}
MATCHER(IsNull, "") {
return arg.type() == nNull;
Value * maybeThunk(std::string input, bool forceValue = true)
{
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
assert(e);
return e->maybeThunk(state, state.baseEnv);
}
MATCHER(IsThunk, "") {
return arg.type() == nThunk;
Symbol createSymbol(const char * value)
{
return state.symbols.create(value);
}
MATCHER(IsAttrs, "") {
return arg.type() == nAttrs;
}
bool readOnlyMode = true;
fetchers::Settings fetchSettings{};
EvalSettings evalSettings{readOnlyMode};
EvalState state;
};
MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s)) {
if (arg.type() != nString) {
MATCHER(IsListType, "")
{
return arg != nList;
}
MATCHER(IsList, "")
{
return arg.type() == nList;
}
MATCHER(IsString, "")
{
return arg.type() == nString;
}
MATCHER(IsNull, "")
{
return arg.type() == nNull;
}
MATCHER(IsThunk, "")
{
return arg.type() == nThunk;
}
MATCHER(IsAttrs, "")
{
return arg.type() == nAttrs;
}
MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s))
{
if (arg.type() != nString) {
return false;
}
return std::string_view(arg.c_str()) == s;
}
MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v))
{
if (arg.type() != nInt) {
return false;
}
return arg.integer().value == v;
}
MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v))
{
if (arg.type() != nFloat) {
return false;
}
return arg.fpoint() == v;
}
MATCHER(IsTrue, "")
{
if (arg.type() != nBool) {
return false;
}
return arg.boolean() == true;
}
MATCHER(IsFalse, "")
{
if (arg.type() != nBool) {
return false;
}
return arg.boolean() == false;
}
MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p))
{
if (arg.type() != nPath) {
*result_listener << "Expected a path got " << arg.type();
return false;
} else {
auto path = arg.path();
if (path.path != CanonPath(p)) {
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << path.path;
return false;
}
return std::string_view(arg.c_str()) == s;
}
return true;
}
MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v)) {
if (arg.type() != nInt) {
return false;
}
return arg.integer().value == v;
MATCHER_P(IsListOfSize, n, fmt("Is a list of size [%1%]", n))
{
if (arg.type() != nList) {
*result_listener << "Expected list got " << arg.type();
return false;
} else if (arg.listSize() != (size_t) n) {
*result_listener << "Expected as list of size " << n << " got " << arg.listSize();
return false;
}
return true;
}
MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) {
if (arg.type() != nFloat) {
return false;
}
return arg.fpoint() == v;
MATCHER_P(IsAttrsOfSize, n, fmt("Is a set of size [%1%]", n))
{
if (arg.type() != nAttrs) {
*result_listener << "Expected set got " << arg.type();
return false;
} else if (arg.attrs()->size() != (size_t) n) {
*result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs()->size();
return false;
}
MATCHER(IsTrue, "") {
if (arg.type() != nBool) {
return false;
}
return arg.boolean() == true;
}
MATCHER(IsFalse, "") {
if (arg.type() != nBool) {
return false;
}
return arg.boolean() == false;
}
MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) {
if (arg.type() != nPath) {
*result_listener << "Expected a path got " << arg.type();
return false;
} else {
auto path = arg.path();
if (path.path != CanonPath(p)) {
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << path.path;
return false;
}
}
return true;
}
MATCHER_P(IsListOfSize, n, fmt("Is a list of size [%1%]", n)) {
if (arg.type() != nList) {
*result_listener << "Expected list got " << arg.type();
return false;
} else if (arg.listSize() != (size_t)n) {
*result_listener << "Expected as list of size " << n << " got " << arg.listSize();
return false;
}
return true;
}
MATCHER_P(IsAttrsOfSize, n, fmt("Is a set of size [%1%]", n)) {
if (arg.type() != nAttrs) {
*result_listener << "Expected set got " << arg.type();
return false;
} else if (arg.attrs()->size() != (size_t) n) {
*result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs()->size();
return false;
}
return true;
}
return true;
}
} /* namespace nix */

View File

@@ -18,6 +18,7 @@ protected:
state = nix_state_create(nullptr, nullptr, store);
value = nix_alloc_value(nullptr, state);
}
~nix_api_expr_test()
{
nix_gc_decref(nullptr, value);
@@ -28,4 +29,4 @@ protected:
nix_value * value;
};
}
} // namespace nixC

View File

@@ -9,23 +9,27 @@ namespace rc {
using namespace nix;
template<>
struct Arbitrary<NixStringContextElem::Opaque> {
struct Arbitrary<NixStringContextElem::Opaque>
{
static Gen<NixStringContextElem::Opaque> arbitrary();
};
template<>
struct Arbitrary<NixStringContextElem::Built> {
struct Arbitrary<NixStringContextElem::Built>
{
static Gen<NixStringContextElem::Built> arbitrary();
};
template<>
struct Arbitrary<NixStringContextElem::DrvDeep> {
struct Arbitrary<NixStringContextElem::DrvDeep>
{
static Gen<NixStringContextElem::DrvDeep> arbitrary();
};
template<>
struct Arbitrary<NixStringContextElem> {
struct Arbitrary<NixStringContextElem>
{
static Gen<NixStringContextElem> arbitrary();
};
}
} // namespace rc

View File

@@ -36,4 +36,4 @@ Gen<NixStringContextElem> Arbitrary<NixStringContextElem>::arbitrary()
});
}
}
} // namespace rc

View File

@@ -8,36 +8,30 @@
namespace nix {
// Testing of trivial expressions
class DerivedPathExpressionTest : public LibExprTest {};
class DerivedPathExpressionTest : public LibExprTest
{};
// FIXME: `RC_GTEST_FIXTURE_PROP` isn't calling `SetUpTestSuite` because it is
// no a real fixture.
//
// See https://github.com/emil-e/rapidcheck/blob/master/doc/gtest.md#rc_gtest_fixture_propfixture-name-args
TEST_F(DerivedPathExpressionTest, force_init)
{
}
TEST_F(DerivedPathExpressionTest, force_init) {}
#ifndef COVERAGE
RC_GTEST_FIXTURE_PROP(
DerivedPathExpressionTest,
prop_opaque_path_round_trip,
(const SingleDerivedPath::Opaque & o))
RC_GTEST_FIXTURE_PROP(DerivedPathExpressionTest, prop_opaque_path_round_trip, (const SingleDerivedPath::Opaque & o))
{
auto * v = state.allocValue();
state.mkStorePathString(o.path, *v);
auto d = state.coerceToSingleDerivedPath(noPos, *v, "");
RC_ASSERT(SingleDerivedPath { o } == d);
RC_ASSERT(SingleDerivedPath{o} == d);
}
// TODO use DerivedPath::Built for parameter once it supports a single output
// path only.
RC_GTEST_FIXTURE_PROP(
DerivedPathExpressionTest,
prop_derived_path_built_placeholder_round_trip,
(const SingleDerivedPath::Built & b))
DerivedPathExpressionTest, prop_derived_path_built_placeholder_round_trip, (const SingleDerivedPath::Built & b))
{
/**
* We set these in tests rather than the regular globals so we don't have
@@ -49,7 +43,7 @@ RC_GTEST_FIXTURE_PROP(
auto * v = state.allocValue();
state.mkOutputString(*v, b, std::nullopt, mockXpSettings);
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, "", mockXpSettings);
RC_ASSERT(SingleDerivedPath { b } == d);
RC_ASSERT(SingleDerivedPath{b} == d);
}
RC_GTEST_FIXTURE_PROP(
@@ -63,7 +57,7 @@ RC_GTEST_FIXTURE_PROP(
auto * v = state.allocValue();
state.mkOutputString(*v, b, outPath, mockXpSettings);
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, "", mockXpSettings);
RC_ASSERT(SingleDerivedPath { b } == d);
RC_ASSERT(SingleDerivedPath{b} == d);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,8 @@
namespace nix {
TEST(nix_isAllowedURI, http_example_com) {
TEST(nix_isAllowedURI, http_example_com)
{
Strings allowed;
allowed.push_back("http://example.com");
@@ -20,7 +21,8 @@ TEST(nix_isAllowedURI, http_example_com) {
ASSERT_FALSE(isAllowedURI("http://example.org/foo", allowed));
}
TEST(nix_isAllowedURI, http_example_com_foo) {
TEST(nix_isAllowedURI, http_example_com_foo)
{
Strings allowed;
allowed.push_back("http://example.com/foo");
@@ -34,7 +36,8 @@ TEST(nix_isAllowedURI, http_example_com_foo) {
// ASSERT_TRUE(isAllowedURI("http://example.com/foo?ok=1", allowed));
}
TEST(nix_isAllowedURI, http) {
TEST(nix_isAllowedURI, http)
{
Strings allowed;
allowed.push_back("http://");
@@ -48,7 +51,8 @@ TEST(nix_isAllowedURI, http) {
ASSERT_FALSE(isAllowedURI("http:foo", allowed));
}
TEST(nix_isAllowedURI, https) {
TEST(nix_isAllowedURI, https)
{
Strings allowed;
allowed.push_back("https://");
@@ -58,7 +62,8 @@ TEST(nix_isAllowedURI, https) {
ASSERT_FALSE(isAllowedURI("http://example.com/https:", allowed));
}
TEST(nix_isAllowedURI, absolute_path) {
TEST(nix_isAllowedURI, absolute_path)
{
Strings allowed;
allowed.push_back("/var/evil"); // bad idea
@@ -76,7 +81,8 @@ TEST(nix_isAllowedURI, absolute_path) {
ASSERT_FALSE(isAllowedURI("http://example.com//var/evil/foo", allowed));
}
TEST(nix_isAllowedURI, file_url) {
TEST(nix_isAllowedURI, file_url)
{
Strings allowed;
allowed.push_back("file:///var/evil"); // bad idea
@@ -103,7 +109,8 @@ TEST(nix_isAllowedURI, file_url) {
ASSERT_FALSE(isAllowedURI("file://", allowed));
}
TEST(nix_isAllowedURI, github_all) {
TEST(nix_isAllowedURI, github_all)
{
Strings allowed;
allowed.push_back("github:");
ASSERT_TRUE(isAllowedURI("github:", allowed));
@@ -117,7 +124,8 @@ TEST(nix_isAllowedURI, github_all) {
ASSERT_FALSE(isAllowedURI("github", allowed));
}
TEST(nix_isAllowedURI, github_org) {
TEST(nix_isAllowedURI, github_org)
{
Strings allowed;
allowed.push_back("github:foo");
ASSERT_FALSE(isAllowedURI("github:", allowed));
@@ -130,7 +138,8 @@ TEST(nix_isAllowedURI, github_org) {
ASSERT_FALSE(isAllowedURI("file:///github:foo/bar/archive/master.tar.gz", allowed));
}
TEST(nix_isAllowedURI, non_scheme_colon) {
TEST(nix_isAllowedURI, non_scheme_colon)
{
Strings allowed;
allowed.push_back("https://foo/bar:");
ASSERT_TRUE(isAllowedURI("https://foo/bar:", allowed));
@@ -138,16 +147,19 @@ TEST(nix_isAllowedURI, non_scheme_colon) {
ASSERT_FALSE(isAllowedURI("https://foo/bar:baz", allowed));
}
class EvalStateTest : public LibExprTest {};
class EvalStateTest : public LibExprTest
{};
TEST_F(EvalStateTest, getBuiltins_ok) {
TEST_F(EvalStateTest, getBuiltins_ok)
{
auto evaled = maybeThunk("builtins");
auto & builtins = state.getBuiltins();
ASSERT_TRUE(builtins.type() == nAttrs);
ASSERT_EQ(evaled, &builtins);
}
TEST_F(EvalStateTest, getBuiltin_ok) {
TEST_F(EvalStateTest, getBuiltin_ok)
{
auto & builtin = state.getBuiltin("toString");
ASSERT_TRUE(builtin.type() == nFunction);
// FIXME
@@ -157,7 +169,8 @@ TEST_F(EvalStateTest, getBuiltin_ok) {
ASSERT_EQ(state.forceBool(builtin2, noPos, "in unit test"), true);
}
TEST_F(EvalStateTest, getBuiltin_fail) {
TEST_F(EvalStateTest, getBuiltin_fail)
{
ASSERT_THROW(state.getBuiltin("nonexistent"), EvalError);
}

View File

@@ -4,65 +4,75 @@
namespace nix {
// Testing the conversion to JSON
class JSONValueTest : public LibExprTest {
protected:
std::string getJSONValue(Value& value) {
std::stringstream ss;
NixStringContext ps;
printValueAsJSON(state, true, value, noPos, ss, ps);
return ss.str();
}
};
TEST_F(JSONValueTest, null) {
Value v;
v.mkNull();
ASSERT_EQ(getJSONValue(v), "null");
class JSONValueTest : public LibExprTest
{
protected:
std::string getJSONValue(Value & value)
{
std::stringstream ss;
NixStringContext ps;
printValueAsJSON(state, true, value, noPos, ss, ps);
return ss.str();
}
};
TEST_F(JSONValueTest, BoolFalse) {
Value v;
v.mkBool(false);
ASSERT_EQ(getJSONValue(v),"false");
}
TEST_F(JSONValueTest, null)
{
Value v;
v.mkNull();
ASSERT_EQ(getJSONValue(v), "null");
}
TEST_F(JSONValueTest, BoolTrue) {
Value v;
v.mkBool(true);
ASSERT_EQ(getJSONValue(v), "true");
}
TEST_F(JSONValueTest, BoolFalse)
{
Value v;
v.mkBool(false);
ASSERT_EQ(getJSONValue(v), "false");
}
TEST_F(JSONValueTest, IntPositive) {
Value v;
v.mkInt(100);
ASSERT_EQ(getJSONValue(v), "100");
}
TEST_F(JSONValueTest, BoolTrue)
{
Value v;
v.mkBool(true);
ASSERT_EQ(getJSONValue(v), "true");
}
TEST_F(JSONValueTest, IntNegative) {
Value v;
v.mkInt(-100);
ASSERT_EQ(getJSONValue(v), "-100");
}
TEST_F(JSONValueTest, IntPositive)
{
Value v;
v.mkInt(100);
ASSERT_EQ(getJSONValue(v), "100");
}
TEST_F(JSONValueTest, String) {
Value v;
v.mkString("test");
ASSERT_EQ(getJSONValue(v), "\"test\"");
}
TEST_F(JSONValueTest, IntNegative)
{
Value v;
v.mkInt(-100);
ASSERT_EQ(getJSONValue(v), "-100");
}
TEST_F(JSONValueTest, StringQuotes) {
Value v;
TEST_F(JSONValueTest, String)
{
Value v;
v.mkString("test");
ASSERT_EQ(getJSONValue(v), "\"test\"");
}
v.mkString("test\"");
ASSERT_EQ(getJSONValue(v), "\"test\\\"\"");
}
TEST_F(JSONValueTest, StringQuotes)
{
Value v;
// The dummy store doesn't support writing files. Fails with this exception message:
// C++ exception with description "error: operation 'addToStoreFromDump' is
// not supported by store 'dummy'" thrown in the test body.
TEST_F(JSONValueTest, DISABLED_Path) {
Value v;
v.mkPath(state.rootPath(CanonPath("/test")));
ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\"");
}
v.mkString("test\"");
ASSERT_EQ(getJSONValue(v), "\"test\\\"\"");
}
// The dummy store doesn't support writing files. Fails with this exception message:
// C++ exception with description "error: operation 'addToStoreFromDump' is
// not supported by store 'dummy'" thrown in the test body.
TEST_F(JSONValueTest, DISABLED_Path)
{
Value v;
v.mkPath(state.rootPath(CanonPath("/test")));
ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\"");
}
} /* namespace nix */

View File

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

View File

@@ -32,8 +32,8 @@ deps_private += rapidcheck
gtest = dependency('gtest')
deps_private += gtest
gtest = dependency('gmock')
deps_private += gtest
gmock = dependency('gmock')
deps_private += gmock
configdata = configuration_data()
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())

View File

@@ -394,6 +394,7 @@ static void primop_bad_return_thunk(
{
nix_init_apply(context, ret, args[0], args[1]);
}
TEST_F(nix_api_expr_test, nix_expr_primop_bad_return_thunk)
{
PrimOp * primop =

View File

@@ -27,6 +27,7 @@ public:
private:
int _x;
static void print_function(void * self, nix_printer * printer) {}
static void show_type_function(void * self, nix_string_return * res) {}
@@ -68,4 +69,4 @@ TEST_F(nix_api_expr_test, nix_expr_eval_external)
nix_state_free(stateFn);
}
}
} // namespace nixC

View File

@@ -120,6 +120,7 @@ TEST_F(nix_api_expr_test, nix_value_set_get_path_invalid)
ASSERT_EQ(nullptr, nix_get_path_string(ctx, value));
assert_ctx_err();
}
TEST_F(nix_api_expr_test, nix_value_set_get_path)
{
const char * p = "/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname";
@@ -399,4 +400,4 @@ TEST_F(nix_api_expr_test, nix_copy_value)
nix_gc_decref(ctx, source);
}
}
} // namespace nixC

File diff suppressed because it is too large Load Diff

View File

@@ -5,86 +5,98 @@
namespace nix {
TEST(LookupPathElem, parse_justPath) {
TEST(LookupPathElem, parse_justPath)
{
ASSERT_EQ(
LookupPath::Elem::parse("foo"),
(LookupPath::Elem {
.prefix = LookupPath::Prefix { .s = "" },
.path = LookupPath::Path { .s = "foo" },
(LookupPath::Elem{
.prefix = LookupPath::Prefix{.s = ""},
.path = LookupPath::Path{.s = "foo"},
}));
}
TEST(LookupPathElem, parse_emptyPrefix) {
TEST(LookupPathElem, parse_emptyPrefix)
{
ASSERT_EQ(
LookupPath::Elem::parse("=foo"),
(LookupPath::Elem {
.prefix = LookupPath::Prefix { .s = "" },
.path = LookupPath::Path { .s = "foo" },
(LookupPath::Elem{
.prefix = LookupPath::Prefix{.s = ""},
.path = LookupPath::Path{.s = "foo"},
}));
}
TEST(LookupPathElem, parse_oneEq) {
TEST(LookupPathElem, parse_oneEq)
{
ASSERT_EQ(
LookupPath::Elem::parse("foo=bar"),
(LookupPath::Elem {
.prefix = LookupPath::Prefix { .s = "foo" },
.path = LookupPath::Path { .s = "bar" },
(LookupPath::Elem{
.prefix = LookupPath::Prefix{.s = "foo"},
.path = LookupPath::Path{.s = "bar"},
}));
}
TEST(LookupPathElem, parse_twoEqs) {
TEST(LookupPathElem, parse_twoEqs)
{
ASSERT_EQ(
LookupPath::Elem::parse("foo=bar=baz"),
(LookupPath::Elem {
.prefix = LookupPath::Prefix { .s = "foo" },
.path = LookupPath::Path { .s = "bar=baz" },
(LookupPath::Elem{
.prefix = LookupPath::Prefix{.s = "foo"},
.path = LookupPath::Path{.s = "bar=baz"},
}));
}
TEST(LookupPathElem, suffixIfPotentialMatch_justPath) {
LookupPath::Prefix prefix { .s = "" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("any/thing"), std::optional { "any/thing" });
TEST(LookupPathElem, suffixIfPotentialMatch_justPath)
{
LookupPath::Prefix prefix{.s = ""};
ASSERT_EQ(prefix.suffixIfPotentialMatch("any/thing"), std::optional{"any/thing"});
}
TEST(LookupPathElem, suffixIfPotentialMatch_misleadingPrefix1) {
LookupPath::Prefix prefix { .s = "foo" };
TEST(LookupPathElem, suffixIfPotentialMatch_misleadingPrefix1)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("fooX"), std::nullopt);
}
TEST(LookupPathElem, suffixIfPotentialMatch_misleadingPrefix2) {
LookupPath::Prefix prefix { .s = "foo" };
TEST(LookupPathElem, suffixIfPotentialMatch_misleadingPrefix2)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("fooX/bar"), std::nullopt);
}
TEST(LookupPathElem, suffixIfPotentialMatch_partialPrefix) {
LookupPath::Prefix prefix { .s = "fooX" };
TEST(LookupPathElem, suffixIfPotentialMatch_partialPrefix)
{
LookupPath::Prefix prefix{.s = "fooX"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo"), std::nullopt);
}
TEST(LookupPathElem, suffixIfPotentialMatch_exactPrefix) {
LookupPath::Prefix prefix { .s = "foo" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo"), std::optional { "" });
TEST(LookupPathElem, suffixIfPotentialMatch_exactPrefix)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo"), std::optional{""});
}
TEST(LookupPathElem, suffixIfPotentialMatch_multiKey) {
LookupPath::Prefix prefix { .s = "foo/bar" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional { "baz" });
TEST(LookupPathElem, suffixIfPotentialMatch_multiKey)
{
LookupPath::Prefix prefix{.s = "foo/bar"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional{"baz"});
}
TEST(LookupPathElem, suffixIfPotentialMatch_trailingSlash) {
LookupPath::Prefix prefix { .s = "foo" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/"), std::optional { "" });
TEST(LookupPathElem, suffixIfPotentialMatch_trailingSlash)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/"), std::optional{""});
}
TEST(LookupPathElem, suffixIfPotentialMatch_trailingDoubleSlash) {
LookupPath::Prefix prefix { .s = "foo" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo//"), std::optional { "/" });
TEST(LookupPathElem, suffixIfPotentialMatch_trailingDoubleSlash)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo//"), std::optional{"/"});
}
TEST(LookupPathElem, suffixIfPotentialMatch_trailingPath) {
LookupPath::Prefix prefix { .s = "foo" };
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional { "bar/baz" });
TEST(LookupPathElem, suffixIfPotentialMatch_trailingPath)
{
LookupPath::Prefix prefix{.s = "foo"};
ASSERT_EQ(prefix.suffixIfPotentialMatch("foo/bar/baz"), std::optional{"bar/baz"});
}
}
} // namespace nix

View File

@@ -1,181 +1,202 @@
#include "nix/expr/tests/libexpr.hh"
namespace nix {
// Testing of trivial expressions
class TrivialExpressionTest : public LibExprTest {};
// Testing of trivial expressions
class TrivialExpressionTest : public LibExprTest
{};
TEST_F(TrivialExpressionTest, true) {
auto v = eval("true");
ASSERT_THAT(v, IsTrue());
}
TEST_F(TrivialExpressionTest, true)
{
auto v = eval("true");
ASSERT_THAT(v, IsTrue());
}
TEST_F(TrivialExpressionTest, false) {
auto v = eval("false");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, false)
{
auto v = eval("false");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, null) {
auto v = eval("null");
ASSERT_THAT(v, IsNull());
}
TEST_F(TrivialExpressionTest, null)
{
auto v = eval("null");
ASSERT_THAT(v, IsNull());
}
TEST_F(TrivialExpressionTest, 1) {
auto v = eval("1");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, 1)
{
auto v = eval("1");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, 1plus1) {
auto v = eval("1+1");
ASSERT_THAT(v, IsIntEq(2));
}
TEST_F(TrivialExpressionTest, 1plus1)
{
auto v = eval("1+1");
ASSERT_THAT(v, IsIntEq(2));
}
TEST_F(TrivialExpressionTest, minus1) {
auto v = eval("-1");
ASSERT_THAT(v, IsIntEq(-1));
}
TEST_F(TrivialExpressionTest, minus1)
{
auto v = eval("-1");
ASSERT_THAT(v, IsIntEq(-1));
}
TEST_F(TrivialExpressionTest, 1minus1) {
auto v = eval("1-1");
ASSERT_THAT(v, IsIntEq(0));
}
TEST_F(TrivialExpressionTest, 1minus1)
{
auto v = eval("1-1");
ASSERT_THAT(v, IsIntEq(0));
}
TEST_F(TrivialExpressionTest, lambdaAdd) {
auto v = eval("let add = a: b: a + b; in add 1 2");
ASSERT_THAT(v, IsIntEq(3));
}
TEST_F(TrivialExpressionTest, lambdaAdd)
{
auto v = eval("let add = a: b: a + b; in add 1 2");
ASSERT_THAT(v, IsIntEq(3));
}
TEST_F(TrivialExpressionTest, list) {
auto v = eval("[]");
ASSERT_THAT(v, IsListOfSize(0));
}
TEST_F(TrivialExpressionTest, list)
{
auto v = eval("[]");
ASSERT_THAT(v, IsListOfSize(0));
}
TEST_F(TrivialExpressionTest, attrs) {
auto v = eval("{}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, attrs)
{
auto v = eval("{}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, float) {
auto v = eval("1.234");
ASSERT_THAT(v, IsFloatEq(1.234));
}
TEST_F(TrivialExpressionTest, float)
{
auto v = eval("1.234");
ASSERT_THAT(v, IsFloatEq(1.234));
}
TEST_F(TrivialExpressionTest, updateAttrs) {
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
ASSERT_THAT(v, IsAttrsOfSize(2));
auto a = v.attrs()->find(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsIntEq(3));
TEST_F(TrivialExpressionTest, updateAttrs)
{
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
ASSERT_THAT(v, IsAttrsOfSize(2));
auto a = v.attrs()->find(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsIntEq(3));
auto b = v.attrs()->find(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(2));
}
auto b = v.attrs()->find(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(2));
}
TEST_F(TrivialExpressionTest, hasAttrOpFalse) {
auto v = eval("{} ? a");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, hasAttrOpFalse)
{
auto v = eval("{} ? a");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, hasAttrOpTrue) {
auto v = eval("{ a = 123; } ? a");
ASSERT_THAT(v, IsTrue());
}
TEST_F(TrivialExpressionTest, hasAttrOpTrue)
{
auto v = eval("{ a = 123; } ? a");
ASSERT_THAT(v, IsTrue());
}
TEST_F(TrivialExpressionTest, withFound) {
auto v = eval("with { a = 23; }; a");
ASSERT_THAT(v, IsIntEq(23));
}
TEST_F(TrivialExpressionTest, withFound)
{
auto v = eval("with { a = 23; }; a");
ASSERT_THAT(v, IsIntEq(23));
}
TEST_F(TrivialExpressionTest, withNotFound) {
ASSERT_THROW(eval("with {}; a"), Error);
}
TEST_F(TrivialExpressionTest, withNotFound)
{
ASSERT_THROW(eval("with {}; a"), Error);
}
TEST_F(TrivialExpressionTest, withOverride) {
auto v = eval("with { a = 23; }; with { a = 42; }; a");
ASSERT_THAT(v, IsIntEq(42));
}
TEST_F(TrivialExpressionTest, withOverride)
{
auto v = eval("with { a = 23; }; with { a = 42; }; a");
ASSERT_THAT(v, IsIntEq(42));
}
TEST_F(TrivialExpressionTest, letOverWith) {
auto v = eval("let a = 23; in with { a = 1; }; a");
ASSERT_THAT(v, IsIntEq(23));
}
TEST_F(TrivialExpressionTest, letOverWith)
{
auto v = eval("let a = 23; in with { a = 1; }; a");
ASSERT_THAT(v, IsIntEq(23));
}
TEST_F(TrivialExpressionTest, multipleLet) {
auto v = eval("let a = 23; in let a = 42; in a");
ASSERT_THAT(v, IsIntEq(42));
}
TEST_F(TrivialExpressionTest, multipleLet)
{
auto v = eval("let a = 23; in let a = 42; in a");
ASSERT_THAT(v, IsIntEq(42));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgs) {
auto v = eval("({ a ? 123 }: a) {}");
ASSERT_THAT(v, IsIntEq(123));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgs)
{
auto v = eval("({ a ? 123 }: a) {}");
ASSERT_THAT(v, IsIntEq(123));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsOverride) {
auto v = eval("({ a ? 123 }: a) { a = 5; }");
ASSERT_THAT(v, IsIntEq(5));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsOverride)
{
auto v = eval("({ a ? 123 }: a) { a = 5; }");
ASSERT_THAT(v, IsIntEq(5));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureBack) {
auto v = eval("({ a ? 123 }@args: args) {}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureBack)
{
auto v = eval("({ a ? 123 }@args: args) {}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureFront) {
auto v = eval("(args@{ a ? 123 }: args) {}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureFront)
{
auto v = eval("(args@{ a ? 123 }: args) {}");
ASSERT_THAT(v, IsAttrsOfSize(0));
}
TEST_F(TrivialExpressionTest, assertThrows) {
ASSERT_THROW(eval("let x = arg: assert arg == 1; 123; in x 2"), Error);
}
TEST_F(TrivialExpressionTest, assertThrows)
{
ASSERT_THROW(eval("let x = arg: assert arg == 1; 123; in x 2"), Error);
}
TEST_F(TrivialExpressionTest, assertPassed) {
auto v = eval("let x = arg: assert arg == 1; 123; in x 1");
ASSERT_THAT(v, IsIntEq(123));
}
TEST_F(TrivialExpressionTest, assertPassed)
{
auto v = eval("let x = arg: assert arg == 1; 123; in x 1");
ASSERT_THAT(v, IsIntEq(123));
}
class AttrSetMergeTrvialExpressionTest :
public TrivialExpressionTest,
public testing::WithParamInterface<const char*>
{};
class AttrSetMergeTrvialExpressionTest : public TrivialExpressionTest, public testing::WithParamInterface<const char *>
{};
TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy) {
// Usually Nix rejects duplicate keys in an attrset but it does allow
// so if it is an attribute set that contains disjoint sets of keys.
// The below is equivalent to `{a.b = 1; a.c = 2; }`.
// The attribute set `a` will be a Thunk at first as the attribuets
// have to be merged (or otherwise computed) and that is done in a lazy
// manner.
TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
{
// Usually Nix rejects duplicate keys in an attrset but it does allow
// so if it is an attribute set that contains disjoint sets of keys.
// The below is equivalent to `{a.b = 1; a.c = 2; }`.
// The attribute set `a` will be a Thunk at first as the attribuets
// have to be merged (or otherwise computed) and that is done in a lazy
// manner.
auto expr = GetParam();
auto v = eval(expr);
ASSERT_THAT(v, IsAttrsOfSize(1));
auto expr = GetParam();
auto v = eval(expr);
ASSERT_THAT(v, IsAttrsOfSize(1));
auto a = v.attrs()->find(createSymbol("a"));
ASSERT_NE(a, nullptr);
auto a = v.attrs()->find(createSymbol("a"));
ASSERT_NE(a, nullptr);
ASSERT_THAT(*a->value, IsThunk());
state.forceValue(*a->value, noPos);
ASSERT_THAT(*a->value, IsThunk());
state.forceValue(*a->value, noPos);
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
auto b = a->value->attrs()->find(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
auto b = a->value->attrs()->find(createSymbol("b"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
auto c = a->value->attrs()->find(createSymbol("c"));
ASSERT_NE(c, nullptr);
ASSERT_THAT(*c->value, IsIntEq(2));
}
auto c = a->value->attrs()->find(createSymbol("c"));
ASSERT_NE(c, nullptr);
ASSERT_THAT(*c->value, IsIntEq(2));
}
INSTANTIATE_TEST_SUITE_P(
attrsetMergeLazy,
AttrSetMergeTrvialExpressionTest,
testing::Values(
"{ a.b = 1; a.c = 2; }",
"{ a = { b = 1; }; a = { c = 2; }; }"
)
);
INSTANTIATE_TEST_SUITE_P(
attrsetMergeLazy,
AttrSetMergeTrvialExpressionTest,
testing::Values("{ a.b = 1; a.c = 2; }", "{ a = { b = 1; }; a = { c = 2; }; }"));
// The following macros ultimately define 48 tests (16 variations on three
// templates). Each template tests an expression that can be written in 2^4
@@ -199,28 +220,34 @@ namespace nix {
// expanded.
#define X_EXPAND_IF0(k, v) k "." v
#define X_EXPAND_IF1(k, v) k " = { " v " };"
#define X4(w, x, y, z) \
TEST_F(TrivialExpressionTest, nestedAttrsetMerge##w##x##y##z) { \
auto v = eval("{ a.b = { c = 1; d = 2; }; } == { " \
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " }"); \
ASSERT_THAT(v, IsTrue()); \
}; \
TEST_F(TrivialExpressionTest, nestedAttrsetMergeDup##w##x##y##z) { \
ASSERT_THROW(eval("{ " \
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "c = 2;")) " }"), Error); \
}; \
TEST_F(TrivialExpressionTest, nestedAttrsetMergeLet##w##x##y##z) { \
auto v = eval("{ b = { c = 1; d = 2; }; } == (let " \
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " in a)"); \
ASSERT_THAT(v, IsTrue()); \
#define X4(w, x, y, z) \
TEST_F(TrivialExpressionTest, nestedAttrsetMerge##w##x##y##z) \
{ \
auto v = eval( \
"{ a.b = { c = 1; d = 2; }; } == { " X_EXPAND_IF##w( \
"a", X_EXPAND_IF##x("b", "c = 1;")) " " X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " }"); \
ASSERT_THAT(v, IsTrue()); \
}; \
TEST_F(TrivialExpressionTest, nestedAttrsetMergeDup##w##x##y##z) \
{ \
ASSERT_THROW( \
eval( \
"{ " X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " X_EXPAND_IF##y( \
"a", X_EXPAND_IF##z("b", "c = 2;")) " }"), \
Error); \
}; \
TEST_F(TrivialExpressionTest, nestedAttrsetMergeLet##w##x##y##z) \
{ \
auto v = eval( \
"{ b = { c = 1; d = 2; }; } == (let " X_EXPAND_IF##w( \
"a", X_EXPAND_IF##x("b", "c = 1;")) " " X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " in a)"); \
ASSERT_THAT(v, IsTrue()); \
};
#define X3(...) X4(__VA_ARGS__, 0) X4(__VA_ARGS__, 1)
#define X2(...) X3(__VA_ARGS__, 0) X3(__VA_ARGS__, 1)
#define X1(...) X2(__VA_ARGS__, 0) X2(__VA_ARGS__, 1)
X1(0) X1(1)
X1(0)
X1(1)
#undef X_EXPAND_IF0
#undef X_EXPAND_IF1
#undef X1
@@ -228,74 +255,88 @@ namespace nix {
#undef X3
#undef X4
TEST_F(TrivialExpressionTest, functor) {
auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5");
ASSERT_THAT(v, IsIntEq(15));
}
TEST_F(TrivialExpressionTest, functor)
{
auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5");
ASSERT_THAT(v, IsIntEq(15));
}
TEST_F(TrivialExpressionTest, forwardPipe) {
auto v = eval("1 |> builtins.add 2 |> builtins.mul 3");
ASSERT_THAT(v, IsIntEq(9));
}
TEST_F(TrivialExpressionTest, forwardPipe)
{
auto v = eval("1 |> builtins.add 2 |> builtins.mul 3");
ASSERT_THAT(v, IsIntEq(9));
}
TEST_F(TrivialExpressionTest, backwardPipe) {
auto v = eval("builtins.add 1 <| builtins.mul 2 <| 3");
ASSERT_THAT(v, IsIntEq(7));
}
TEST_F(TrivialExpressionTest, backwardPipe)
{
auto v = eval("builtins.add 1 <| builtins.mul 2 <| 3");
ASSERT_THAT(v, IsIntEq(7));
}
TEST_F(TrivialExpressionTest, forwardPipeEvaluationOrder) {
auto v = eval("1 |> null |> (x: 2)");
ASSERT_THAT(v, IsIntEq(2));
}
TEST_F(TrivialExpressionTest, forwardPipeEvaluationOrder)
{
auto v = eval("1 |> null |> (x: 2)");
ASSERT_THAT(v, IsIntEq(2));
}
TEST_F(TrivialExpressionTest, backwardPipeEvaluationOrder) {
auto v = eval("(x: 1) <| null <| 2");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, backwardPipeEvaluationOrder)
{
auto v = eval("(x: 1) <| null <| 2");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsDoNotAssociate) {
ASSERT_THROW(eval("(x: 1) <| 2 |> (x: 3)"), ParseError);
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsDoNotAssociate)
{
ASSERT_THROW(eval("(x: 1) <| 2 |> (x: 3)"), ParseError);
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensLeft) {
auto v = eval("((x: 1) <| 2) |> (x: 3)");
ASSERT_THAT(v, IsIntEq(3));
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensLeft)
{
auto v = eval("((x: 1) <| 2) |> (x: 3)");
ASSERT_THAT(v, IsIntEq(3));
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensRight) {
auto v = eval("(x: 1) <| (2 |> (x: 3))");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, differentPipeOperatorsParensRight)
{
auto v = eval("(x: 1) <| (2 |> (x: 3))");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, forwardPipeLowestPrecedence) {
auto v = eval("false -> true |> (x: !x)");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, forwardPipeLowestPrecedence)
{
auto v = eval("false -> true |> (x: !x)");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, backwardPipeLowestPrecedence) {
auto v = eval("(x: !x) <| false -> true");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, backwardPipeLowestPrecedence)
{
auto v = eval("(x: !x) <| false -> true");
ASSERT_THAT(v, IsFalse());
}
TEST_F(TrivialExpressionTest, forwardPipeStrongerThanElse) {
auto v = eval("if true then 1 else 2 |> 3");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, forwardPipeStrongerThanElse)
{
auto v = eval("if true then 1 else 2 |> 3");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, backwardPipeStrongerThanElse) {
auto v = eval("if true then 1 else 2 <| 3");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, backwardPipeStrongerThanElse)
{
auto v = eval("if true then 1 else 2 <| 3");
ASSERT_THAT(v, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, bindOr) {
auto v = eval("{ or = 1; }");
ASSERT_THAT(v, IsAttrsOfSize(1));
auto b = v.attrs()->find(createSymbol("or"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, bindOr)
{
auto v = eval("{ or = 1; }");
ASSERT_THAT(v, IsAttrsOfSize(1));
auto b = v.attrs()->find(createSymbol("or"));
ASSERT_NE(b, nullptr);
ASSERT_THAT(*b->value, IsIntEq(1));
}
TEST_F(TrivialExpressionTest, orCantBeUsed) {
ASSERT_THROW(eval("let or = 1; in or"), Error);
}
TEST_F(TrivialExpressionTest, orCantBeUsed)
{
ASSERT_THROW(eval("let or = 1; in or"), Error);
}
} /* namespace nix */

View File

@@ -10,46 +10,42 @@ namespace nix {
// Test a few cases of invalid string context elements.
TEST(NixStringContextElemTest, empty_invalid) {
EXPECT_THROW(
NixStringContextElem::parse(""),
BadNixStringContextElem);
TEST(NixStringContextElemTest, empty_invalid)
{
EXPECT_THROW(NixStringContextElem::parse(""), BadNixStringContextElem);
}
TEST(NixStringContextElemTest, single_bang_invalid) {
EXPECT_THROW(
NixStringContextElem::parse("!"),
BadNixStringContextElem);
TEST(NixStringContextElemTest, single_bang_invalid)
{
EXPECT_THROW(NixStringContextElem::parse("!"), BadNixStringContextElem);
}
TEST(NixStringContextElemTest, double_bang_invalid) {
EXPECT_THROW(
NixStringContextElem::parse("!!/"),
BadStorePath);
TEST(NixStringContextElemTest, double_bang_invalid)
{
EXPECT_THROW(NixStringContextElem::parse("!!/"), BadStorePath);
}
TEST(NixStringContextElemTest, eq_slash_invalid) {
EXPECT_THROW(
NixStringContextElem::parse("=/"),
BadStorePath);
TEST(NixStringContextElemTest, eq_slash_invalid)
{
EXPECT_THROW(NixStringContextElem::parse("=/"), BadStorePath);
}
TEST(NixStringContextElemTest, slash_invalid) {
EXPECT_THROW(
NixStringContextElem::parse("/"),
BadStorePath);
TEST(NixStringContextElemTest, slash_invalid)
{
EXPECT_THROW(NixStringContextElem::parse("/"), BadStorePath);
}
/**
* Round trip (string <-> data structure) test for
* `NixStringContextElem::Opaque`.
*/
TEST(NixStringContextElemTest, opaque) {
TEST(NixStringContextElemTest, opaque)
{
std::string_view opaque = "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x";
auto elem = NixStringContextElem::parse(opaque);
auto * p = std::get_if<NixStringContextElem::Opaque>(&elem.raw);
ASSERT_TRUE(p);
ASSERT_EQ(p->path, StorePath { opaque });
ASSERT_EQ(p->path, StorePath{opaque});
ASSERT_EQ(elem.to_string(), opaque);
}
@@ -57,12 +53,13 @@ TEST(NixStringContextElemTest, opaque) {
* Round trip (string <-> data structure) test for
* `NixStringContextElem::DrvDeep`.
*/
TEST(NixStringContextElemTest, drvDeep) {
TEST(NixStringContextElemTest, drvDeep)
{
std::string_view drvDeep = "=g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
auto elem = NixStringContextElem::parse(drvDeep);
auto * p = std::get_if<NixStringContextElem::DrvDeep>(&elem.raw);
ASSERT_TRUE(p);
ASSERT_EQ(p->drvPath, StorePath { drvDeep.substr(1) });
ASSERT_EQ(p->drvPath, StorePath{drvDeep.substr(1)});
ASSERT_EQ(elem.to_string(), drvDeep);
}
@@ -70,15 +67,18 @@ TEST(NixStringContextElemTest, drvDeep) {
* Round trip (string <-> data structure) test for a simpler
* `NixStringContextElem::Built`.
*/
TEST(NixStringContextElemTest, built_opaque) {
TEST(NixStringContextElemTest, built_opaque)
{
std::string_view built = "!foo!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv";
auto elem = NixStringContextElem::parse(built);
auto * p = std::get_if<NixStringContextElem::Built>(&elem.raw);
ASSERT_TRUE(p);
ASSERT_EQ(p->output, "foo");
ASSERT_EQ(*p->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque {
.path = StorePath { built.substr(5) },
}));
ASSERT_EQ(
*p->drvPath,
((SingleDerivedPath) SingleDerivedPath::Opaque{
.path = StorePath{built.substr(5)},
}));
ASSERT_EQ(elem.to_string(), built);
}
@@ -86,7 +86,8 @@ TEST(NixStringContextElemTest, built_opaque) {
* Round trip (string <-> data structure) test for a more complex,
* inductive `NixStringContextElem::Built`.
*/
TEST(NixStringContextElemTest, built_built) {
TEST(NixStringContextElemTest, built_built)
{
/**
* We set these in tests rather than the regular globals so we don't have
* to worry about race conditions if the tests run concurrently.
@@ -102,9 +103,11 @@ TEST(NixStringContextElemTest, built_built) {
auto * drvPath = std::get_if<SingleDerivedPath::Built>(&*p->drvPath);
ASSERT_TRUE(drvPath);
ASSERT_EQ(drvPath->output, "bar");
ASSERT_EQ(*drvPath->drvPath, ((SingleDerivedPath) SingleDerivedPath::Opaque {
.path = StorePath { built.substr(9) },
}));
ASSERT_EQ(
*drvPath->drvPath,
((SingleDerivedPath) SingleDerivedPath::Opaque{
.path = StorePath{built.substr(9)},
}));
ASSERT_EQ(elem.to_string(), built);
}
@@ -112,17 +115,15 @@ TEST(NixStringContextElemTest, built_built) {
* Without the right experimental features enabled, we cannot parse a
* complex inductive string context element.
*/
TEST(NixStringContextElemTest, built_built_xp) {
TEST(NixStringContextElemTest, built_built_xp)
{
ASSERT_THROW(
NixStringContextElem::parse("!foo!bar!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"), MissingExperimentalFeature);
NixStringContextElem::parse("!foo!bar!g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x.drv"), MissingExperimentalFeature);
}
#ifndef COVERAGE
RC_GTEST_PROP(
NixStringContextElemTest,
prop_round_rip,
(const NixStringContextElem & o))
RC_GTEST_PROP(NixStringContextElemTest, prop_round_rip, (const NixStringContextElem & o))
{
ExperimentalFeatureSettings xpSettings;
xpSettings.set("experimental-features", "dynamic-derivations");
@@ -131,4 +132,4 @@ RC_GTEST_PROP(
#endif
}
} // namespace nix

View File

@@ -106,14 +106,11 @@ TEST_F(ValuePrintingTests, vApp)
TEST_F(ValuePrintingTests, vLambda)
{
Env env {
.up = nullptr,
.values = { }
};
Env env{.up = nullptr, .values = {}};
PosTable::Origin origin = state.positions.addOrigin(std::monostate(), 1);
auto posIdx = state.positions.add(origin, 0);
auto body = ExprInt(0);
auto formals = Formals {};
auto formals = Formals{};
ExprLambda eLambda(posIdx, createSymbol("a"), &formals, &body);
@@ -130,9 +127,7 @@ TEST_F(ValuePrintingTests, vLambda)
TEST_F(ValuePrintingTests, vPrimOp)
{
Value vPrimOp;
PrimOp primOp{
.name = "puppy"
};
PrimOp primOp{.name = "puppy"};
vPrimOp.mkPrimOp(&primOp);
test(vPrimOp, "«primop puppy»");
@@ -140,9 +135,7 @@ TEST_F(ValuePrintingTests, vPrimOp)
TEST_F(ValuePrintingTests, vPrimOpApp)
{
PrimOp primOp{
.name = "puppy"
};
PrimOp primOp{.name = "puppy"};
Value vPrimOp;
vPrimOp.mkPrimOp(&primOp);
@@ -161,16 +154,19 @@ TEST_F(ValuePrintingTests, vExternal)
{
return "";
}
std::string typeOf() const override
{
return "";
}
virtual std::ostream & print(std::ostream & str) const override
{
str << "testing-external!";
return str;
}
} myExternal;
Value vExternal;
vExternal.mkExternal(&myExternal);
@@ -220,10 +216,13 @@ TEST_F(ValuePrintingTests, depthAttrs)
Value vNested;
vNested.mkAttrs(builder2.finish());
test(vNested, "{ nested = { ... }; one = 1; two = 2; }", PrintOptions { .maxDepth = 1 });
test(vNested, "{ nested = { nested = { ... }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 2 });
test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 3 });
test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 4 });
test(vNested, "{ nested = { ... }; one = 1; two = 2; }", PrintOptions{.maxDepth = 1});
test(
vNested,
"{ nested = { nested = { ... }; one = 1; two = 2; }; one = 1; two = 2; }",
PrintOptions{.maxDepth = 2});
test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions{.maxDepth = 3});
test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions{.maxDepth = 4});
}
TEST_F(ValuePrintingTests, depthList)
@@ -256,11 +255,11 @@ TEST_F(ValuePrintingTests, depthList)
Value vList;
vList.mkList(list);
test(vList, "[ 1 2 { ... } ]", PrintOptions { .maxDepth = 1 });
test(vList, "[ 1 2 { nested = { ... }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 2 });
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 3 });
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 4 });
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions { .maxDepth = 5 });
test(vList, "[ 1 2 { ... } ]", PrintOptions{.maxDepth = 1});
test(vList, "[ 1 2 { nested = { ... }; one = 1; two = 2; } ]", PrintOptions{.maxDepth = 2});
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions{.maxDepth = 3});
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions{.maxDepth = 4});
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", PrintOptions{.maxDepth = 5});
}
struct StringPrintingTests : LibExprTest
@@ -272,9 +271,7 @@ struct StringPrintingTests : LibExprTest
v.mkString(literal);
std::stringstream out;
printValue(state, out, v, PrintOptions {
.maxStringLength = maxLength
});
printValue(state, out, v, PrintOptions{.maxStringLength = maxLength});
ASSERT_EQ(out.str(), expected);
}
};
@@ -305,15 +302,9 @@ TEST_F(ValuePrintingTests, attrsTypeFirst)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ type = \"puppy\"; apple = \"apple\"; }",
PrintOptions {
.maxAttrs = 100
});
test(vAttrs, "{ type = \"puppy\"; apple = \"apple\"; }", PrintOptions{.maxAttrs = 100});
test(vAttrs,
"{ apple = \"apple\"; type = \"puppy\"; }",
PrintOptions { });
test(vAttrs, "{ apple = \"apple\"; type = \"puppy\"; }", PrintOptions{});
}
TEST_F(ValuePrintingTests, ansiColorsInt)
@@ -321,11 +312,7 @@ TEST_F(ValuePrintingTests, ansiColorsInt)
Value v;
v.mkInt(10);
test(v,
ANSI_CYAN "10" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_CYAN "10" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsFloat)
@@ -333,11 +320,7 @@ TEST_F(ValuePrintingTests, ansiColorsFloat)
Value v;
v.mkFloat(1.6);
test(v,
ANSI_CYAN "1.6" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_CYAN "1.6" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsBool)
@@ -345,11 +328,7 @@ TEST_F(ValuePrintingTests, ansiColorsBool)
Value v;
v.mkBool(true);
test(v,
ANSI_CYAN "true" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_CYAN "true" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsString)
@@ -357,11 +336,7 @@ TEST_F(ValuePrintingTests, ansiColorsString)
Value v;
v.mkString("puppy");
test(v,
ANSI_MAGENTA "\"puppy\"" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_MAGENTA "\"puppy\"" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsStringElided)
@@ -369,12 +344,10 @@ TEST_F(ValuePrintingTests, ansiColorsStringElided)
Value v;
v.mkString("puppy");
test(v,
ANSI_MAGENTA "\"pup\" " ANSI_FAINT "«2 bytes elided»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.maxStringLength = 3
});
test(
v,
ANSI_MAGENTA "\"pup\" " ANSI_FAINT "«2 bytes elided»" ANSI_NORMAL,
PrintOptions{.ansiColors = true, .maxStringLength = 3});
}
TEST_F(ValuePrintingTests, ansiColorsPath)
@@ -382,11 +355,7 @@ TEST_F(ValuePrintingTests, ansiColorsPath)
Value v;
v.mkPath(state.rootPath(CanonPath("puppy")));
test(v,
ANSI_GREEN "/puppy" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_GREEN "/puppy" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsNull)
@@ -394,11 +363,7 @@ TEST_F(ValuePrintingTests, ansiColorsNull)
Value v;
v.mkNull();
test(v,
ANSI_CYAN "null" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_CYAN "null" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsAttrs)
@@ -416,11 +381,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrs)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; two = " ANSI_CYAN "2" ANSI_NORMAL "; }",
PrintOptions {
.ansiColors = true
});
test(
vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; two = " ANSI_CYAN "2" ANSI_NORMAL "; }",
PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsDerivation)
@@ -434,20 +398,15 @@ TEST_F(ValuePrintingTests, ansiColorsDerivation)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
ANSI_GREEN "«derivation»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true,
.derivationPaths = true
});
test(
vAttrs,
ANSI_GREEN "«derivation»" ANSI_NORMAL,
PrintOptions{.ansiColors = true, .force = true, .derivationPaths = true});
test(vAttrs,
"{ type = " ANSI_MAGENTA "\"derivation\"" ANSI_NORMAL "; }",
PrintOptions {
.ansiColors = true,
.force = true
});
test(
vAttrs,
"{ type = " ANSI_MAGENTA "\"derivation\"" ANSI_NORMAL "; }",
PrintOptions{.ansiColors = true, .force = true});
}
TEST_F(ValuePrintingTests, ansiColorsError)
@@ -458,14 +417,13 @@ TEST_F(ValuePrintingTests, ansiColorsError)
Value vError;
vError.mkApp(&throw_, &message);
test(vError,
ANSI_RED
"«error: uh oh!»"
ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true,
});
test(
vError,
ANSI_RED "«error: uh oh!»" ANSI_NORMAL,
PrintOptions{
.ansiColors = true,
.force = true,
});
}
TEST_F(ValuePrintingTests, ansiColorsDerivationError)
@@ -486,30 +444,20 @@ TEST_F(ValuePrintingTests, ansiColorsDerivationError)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ drvPath = "
ANSI_RED
"«error: uh oh!»"
ANSI_NORMAL
"; type = "
ANSI_MAGENTA
"\"derivation\""
ANSI_NORMAL
"; }",
PrintOptions {
.ansiColors = true,
.force = true
});
test(
vAttrs,
"{ drvPath = " ANSI_RED "«error: uh oh!»" ANSI_NORMAL "; type = " ANSI_MAGENTA "\"derivation\"" ANSI_NORMAL
"; }",
PrintOptions{.ansiColors = true, .force = true});
test(vAttrs,
ANSI_RED
"«error: uh oh!»"
ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true,
.derivationPaths = true,
});
test(
vAttrs,
ANSI_RED "«error: uh oh!»" ANSI_NORMAL,
PrintOptions{
.ansiColors = true,
.force = true,
.derivationPaths = true,
});
}
TEST_F(ValuePrintingTests, ansiColorsAssert)
@@ -523,12 +471,7 @@ TEST_F(ValuePrintingTests, ansiColorsAssert)
Value v;
state.mkThunk_(v, &expr);
test(v,
ANSI_RED "«error: assertion 'false' failed»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true
});
test(v, ANSI_RED "«error: assertion 'false' failed»" ANSI_NORMAL, PrintOptions{.ansiColors = true, .force = true});
}
TEST_F(ValuePrintingTests, ansiColorsList)
@@ -545,77 +488,51 @@ TEST_F(ValuePrintingTests, ansiColorsList)
Value vList;
vList.mkList(list);
test(vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA "«nullptr»" ANSI_NORMAL " ]",
PrintOptions {
.ansiColors = true
});
test(
vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_CYAN "2" ANSI_NORMAL " " ANSI_MAGENTA "«nullptr»" ANSI_NORMAL " ]",
PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsLambda)
{
Env env {
.up = nullptr,
.values = { }
};
Env env{.up = nullptr, .values = {}};
PosTable::Origin origin = state.positions.addOrigin(std::monostate(), 1);
auto posIdx = state.positions.add(origin, 0);
auto body = ExprInt(0);
auto formals = Formals {};
auto formals = Formals{};
ExprLambda eLambda(posIdx, createSymbol("a"), &formals, &body);
Value vLambda;
vLambda.mkLambda(&env, &eLambda);
test(vLambda,
ANSI_BLUE "«lambda @ «none»:1:1»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true
});
test(vLambda, ANSI_BLUE "«lambda @ «none»:1:1»" ANSI_NORMAL, PrintOptions{.ansiColors = true, .force = true});
eLambda.setName(createSymbol("puppy"));
test(vLambda,
ANSI_BLUE "«lambda puppy @ «none»:1:1»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true,
.force = true
});
test(vLambda, ANSI_BLUE "«lambda puppy @ «none»:1:1»" ANSI_NORMAL, PrintOptions{.ansiColors = true, .force = true});
}
TEST_F(ValuePrintingTests, ansiColorsPrimOp)
{
PrimOp primOp{
.name = "puppy"
};
PrimOp primOp{.name = "puppy"};
Value v;
v.mkPrimOp(&primOp);
test(v,
ANSI_BLUE "«primop puppy»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_BLUE "«primop puppy»" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsPrimOpApp)
{
PrimOp primOp{
.name = "puppy"
};
PrimOp primOp{.name = "puppy"};
Value vPrimOp;
vPrimOp.mkPrimOp(&primOp);
Value v;
v.mkPrimOpApp(&vPrimOp, nullptr);
test(v,
ANSI_BLUE "«partially applied primop puppy»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_BLUE "«partially applied primop puppy»" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsThunk)
@@ -623,11 +540,7 @@ TEST_F(ValuePrintingTests, ansiColorsThunk)
Value v;
v.mkThunk(nullptr, nullptr);
test(v,
ANSI_MAGENTA "«thunk»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_MAGENTA "«thunk»" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsBlackhole)
@@ -635,11 +548,7 @@ TEST_F(ValuePrintingTests, ansiColorsBlackhole)
Value v;
v.mkBlackhole();
test(v,
ANSI_RED "«potential infinite recursion»" ANSI_NORMAL,
PrintOptions {
.ansiColors = true
});
test(v, ANSI_RED "«potential infinite recursion»" ANSI_NORMAL, PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
@@ -656,11 +565,7 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ a = { }; b = " ANSI_MAGENTA "«repeated»" ANSI_NORMAL "; }",
PrintOptions {
.ansiColors = true
});
test(vAttrs, "{ a = { }; b = " ANSI_MAGENTA "«repeated»" ANSI_NORMAL "; }", PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, ansiColorsListRepeated)
@@ -676,11 +581,7 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
Value vList;
vList.mkList(list);
test(vList,
"[ { } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]",
PrintOptions {
.ansiColors = true
});
test(vList, "[ { } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]", PrintOptions{.ansiColors = true});
}
TEST_F(ValuePrintingTests, listRepeated)
@@ -696,12 +597,8 @@ TEST_F(ValuePrintingTests, listRepeated)
Value vList;
vList.mkList(list);
test(vList, "[ { } «repeated» ]", PrintOptions { });
test(vList,
"[ { } { } ]",
PrintOptions {
.trackRepeated = false
});
test(vList, "[ { } «repeated» ]", PrintOptions{});
test(vList, "[ { } { } ]", PrintOptions{.trackRepeated = false});
}
TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
@@ -719,12 +616,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«1 attribute elided»" ANSI_NORMAL " }",
PrintOptions {
.ansiColors = true,
.maxAttrs = 1
});
test(
vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«1 attribute elided»" ANSI_NORMAL " }",
PrintOptions{.ansiColors = true, .maxAttrs = 1});
Value vThree;
vThree.mkInt(3);
@@ -732,12 +627,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
builder.insert(state.symbols.create("three"), &vThree);
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«2 attributes elided»" ANSI_NORMAL " }",
PrintOptions {
.ansiColors = true,
.maxAttrs = 1
});
test(
vAttrs,
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«2 attributes elided»" ANSI_NORMAL " }",
PrintOptions{.ansiColors = true, .maxAttrs = 1});
}
TEST_F(ValuePrintingTests, ansiColorsListElided)
@@ -751,37 +644,33 @@ TEST_F(ValuePrintingTests, ansiColorsListElided)
vTwo.mkInt(2);
{
auto list = state.buildList(2);
list.elems[0] = &vOne;
list.elems[1] = &vTwo;
Value vList;
vList.mkList(list);
auto list = state.buildList(2);
list.elems[0] = &vOne;
list.elems[1] = &vTwo;
Value vList;
vList.mkList(list);
test(vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«1 item elided»" ANSI_NORMAL " ]",
PrintOptions {
.ansiColors = true,
.maxListItems = 1
});
test(
vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«1 item elided»" ANSI_NORMAL " ]",
PrintOptions{.ansiColors = true, .maxListItems = 1});
}
Value vThree;
vThree.mkInt(3);
{
auto list = state.buildList(3);
list.elems[0] = &vOne;
list.elems[1] = &vTwo;
list.elems[2] = &vThree;
Value vList;
vList.mkList(list);
auto list = state.buildList(3);
list.elems[0] = &vOne;
list.elems[1] = &vTwo;
list.elems[2] = &vThree;
Value vList;
vList.mkList(list);
test(vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«2 items elided»" ANSI_NORMAL " ]",
PrintOptions {
.ansiColors = true,
.maxListItems = 1
});
test(
vList,
"[ " ANSI_CYAN "1" ANSI_NORMAL " " ANSI_FAINT "«2 items elided»" ANSI_NORMAL " ]",
PrintOptions{.ansiColors = true, .maxListItems = 1});
}
}

View File

@@ -1,10 +1,8 @@
#include "nix/expr/attr-path.hh"
#include "nix/expr/eval-inline.hh"
namespace nix {
static Strings parseAttrPath(std::string_view s)
{
Strings res;
@@ -19,18 +17,19 @@ static Strings parseAttrPath(std::string_view s)
while (1) {
if (i == s.end())
throw ParseError("missing closing quote in selection path '%1%'", s);
if (*i == '"') break;
if (*i == '"')
break;
cur.push_back(*i++);
}
} else
cur.push_back(*i);
++i;
}
if (!cur.empty()) res.push_back(cur);
if (!cur.empty())
res.push_back(cur);
return res;
}
std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
{
std::vector<Symbol> res;
@@ -39,9 +38,8 @@ std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
return res;
}
std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
std::pair<Value *, PosIdx>
findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & autoArgs, Value & vIn)
{
Strings tokens = parseAttrPath(attrPath);
@@ -65,10 +63,12 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
if (!attrIndex) {
if (v->type() != nAttrs)
state.error<TypeError>(
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v)).debugThrow();
state
.error<TypeError>(
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v))
.debugThrow();
if (attr.empty())
throw Error("empty attribute name in selection path '%1%'", attrPath);
@@ -79,7 +79,8 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
attrNames.insert(std::string(state.symbols[attr.name]));
auto suggestions = Suggestions::bestMatches(attrNames, attr);
throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath);
throw AttrPathNotFound(
suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath);
}
v = &*a->value;
pos = a->pos;
@@ -88,23 +89,23 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
else {
if (!v->isList())
state.error<TypeError>(
"the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath,
showType(*v)).debugThrow();
state
.error<TypeError>(
"the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath,
showType(*v))
.debugThrow();
if (*attrIndex >= v->listSize())
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath);
v = v->listElems()[*attrIndex];
pos = noPos;
}
}
return {v, pos};
}
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
{
Value * v2;
@@ -118,17 +119,17 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
// FIXME: is it possible to extract the Pos object instead of doing this
// toString + parsing?
NixStringContext context;
auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
auto path =
state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
auto fn = path.path.abs();
auto fail = [fn]() {
throw ParseError("cannot parse 'meta.position' attribute '%s'", fn);
};
auto fail = [fn]() { throw ParseError("cannot parse 'meta.position' attribute '%s'", fn); };
try {
auto colon = fn.rfind(':');
if (colon == std::string::npos) fail();
if (colon == std::string::npos)
fail();
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
} catch (std::invalid_argument & e) {
@@ -137,5 +138,4 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
}
}
}
} // namespace nix

View File

@@ -3,11 +3,8 @@
#include <algorithm>
namespace nix {
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
@@ -22,7 +19,6 @@ Bindings * EvalState::allocBindings(size_t capacity)
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings((Bindings::size_t) capacity);
}
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
{
auto value = state.allocValue();
@@ -30,24 +26,21 @@ Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
return *value;
}
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
{
return alloc(state.symbols.create(name), pos);
}
void Bindings::sort()
{
if (size_) std::sort(begin(), end());
if (size_)
std::sort(begin(), end());
}
Value & Value::mkAttrs(BindingsBuilder & bindings)
{
mkAttrs(bindings.finish());
return *this;
}
}
} // namespace nix

View File

@@ -11,8 +11,10 @@ namespace nix::eval_cache {
CachedEvalError::CachedEvalError(ref<AttrCursor> cursor, Symbol attr)
: EvalError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
, cursor(cursor), attr(attr)
{ }
, cursor(cursor)
, attr(attr)
{
}
void CachedEvalError::force()
{
@@ -25,7 +27,8 @@ void CachedEvalError::force()
}
// Shouldn't happen.
throw EvalError(state, "evaluation of cached failed attribute '%s' unexpectedly succeeded", cursor->getAttrPathStr(attr));
throw EvalError(
state, "evaluation of cached failed attribute '%s' unexpectedly succeeded", cursor->getAttrPathStr(attr));
}
static const char * schema = R"sql(
@@ -59,10 +62,7 @@ struct AttrDb
SymbolTable & symbols;
AttrDb(
const StoreDirConfig & cfg,
const Hash & fingerprint,
SymbolTable & symbols)
AttrDb(const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
: cfg(cfg)
, _state(std::make_unique<Sync<State>>())
, symbols(symbols)
@@ -78,17 +78,16 @@ struct AttrDb
state->db.isCache();
state->db.exec(schema);
state->insertAttribute.create(state->db,
"insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)");
state->insertAttribute.create(
state->db, "insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)");
state->insertAttributeWithContext.create(state->db,
"insert or replace into Attributes(parent, name, type, value, context) values (?, ?, ?, ?, ?)");
state->insertAttributeWithContext.create(
state->db, "insert or replace into Attributes(parent, name, type, value, context) values (?, ?, ?, ?, ?)");
state->queryAttribute.create(state->db,
"select rowid, type, value, context from Attributes where parent = ? and name = ?");
state->queryAttribute.create(
state->db, "select rowid, type, value, context from Attributes where parent = ? and name = ?");
state->queryAttributes.create(state->db,
"select name from Attributes where parent = ?");
state->queryAttributes.create(state->db, "select name from Attributes where parent = ?");
state->txn = std::make_unique<SQLiteTxn>(state->db);
}
@@ -108,7 +107,8 @@ struct AttrDb
template<typename F>
AttrId doSQLite(F && fun)
{
if (failed) return 0;
if (failed)
return 0;
try {
return fun();
} catch (SQLiteError &) {
@@ -118,116 +118,76 @@ struct AttrDb
}
}
AttrId setAttrs(
AttrKey key,
const std::vector<Symbol> & attrs)
AttrId setAttrs(AttrKey key, const std::vector<Symbol> & attrs)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::FullAttrs)
(0, false).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::FullAttrs) (0, false).exec();
AttrId rowId = state->db.getLastInsertedRowId();
assert(rowId);
for (auto & attr : attrs)
state->insertAttribute.use()
(rowId)
(symbols[attr])
(AttrType::Placeholder)
(0, false).exec();
state->insertAttribute.use()(rowId)(symbols[attr])(AttrType::Placeholder) (0, false).exec();
return rowId;
});
}
AttrId setString(
AttrKey key,
std::string_view s,
const char * * context = nullptr)
AttrId setString(AttrKey key, std::string_view s, const char ** context = nullptr)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
if (context) {
std::string ctx;
for (const char * * p = context; *p; ++p) {
if (p != context) ctx.push_back(' ');
for (const char ** p = context; *p; ++p) {
if (p != context)
ctx.push_back(' ');
ctx.append(*p);
}
state->insertAttributeWithContext.use()
(key.first)
(symbols[key.second])
(AttrType::String)
(s)
(ctx).exec();
state->insertAttributeWithContext.use()(key.first)(symbols[key.second])(AttrType::String) (s) (ctx)
.exec();
} else {
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::String)
(s).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::String) (s).exec();
}
return state->db.getLastInsertedRowId();
});
}
AttrId setBool(
AttrKey key,
bool b)
AttrId setBool(AttrKey key, bool b)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Bool)
(b ? 1 : 0).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Bool) (b ? 1 : 0).exec();
return state->db.getLastInsertedRowId();
});
}
AttrId setInt(
AttrKey key,
int n)
AttrId setInt(AttrKey key, int n)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Int)
(n).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Int) (n).exec();
return state->db.getLastInsertedRowId();
});
}
AttrId setListOfStrings(
AttrKey key,
const std::vector<std::string> & l)
AttrId setListOfStrings(AttrKey key, const std::vector<std::string> & l)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::ListOfStrings)
(dropEmptyInitThenConcatStringsSep("\t", l)).exec();
state->insertAttribute
.use()(key.first)(symbols[key.second])(
AttrType::ListOfStrings) (dropEmptyInitThenConcatStringsSep("\t", l))
.exec();
return state->db.getLastInsertedRowId();
});
@@ -235,15 +195,10 @@ struct AttrDb
AttrId setPlaceholder(AttrKey key)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Placeholder)
(0, false).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Placeholder) (0, false).exec();
return state->db.getLastInsertedRowId();
});
@@ -251,15 +206,10 @@ struct AttrDb
AttrId setMissing(AttrKey key)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Missing)
(0, false).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Missing) (0, false).exec();
return state->db.getLastInsertedRowId();
});
@@ -267,15 +217,10 @@ struct AttrDb
AttrId setMisc(AttrKey key)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Misc)
(0, false).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Misc) (0, false).exec();
return state->db.getLastInsertedRowId();
});
@@ -283,15 +228,10 @@ struct AttrDb
AttrId setFailed(AttrKey key)
{
return doSQLite([&]()
{
return doSQLite([&]() {
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(AttrType::Failed)
(0, false).exec();
state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Failed) (0, false).exec();
return state->db.getLastInsertedRowId();
});
@@ -302,51 +242,49 @@ struct AttrDb
auto state(_state->lock());
auto queryAttribute(state->queryAttribute.use()(key.first)(symbols[key.second]));
if (!queryAttribute.next()) return {};
if (!queryAttribute.next())
return {};
auto rowId = (AttrId) queryAttribute.getInt(0);
auto type = (AttrType) queryAttribute.getInt(1);
switch (type) {
case AttrType::Placeholder:
return {{rowId, placeholder_t()}};
case AttrType::FullAttrs: {
// FIXME: expensive, should separate this out.
std::vector<Symbol> attrs;
auto queryAttributes(state->queryAttributes.use()(rowId));
while (queryAttributes.next())
attrs.emplace_back(symbols.create(queryAttributes.getStr(0)));
return {{rowId, attrs}};
}
case AttrType::String: {
NixStringContext context;
if (!queryAttribute.isNull(3))
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), ";"))
context.insert(NixStringContextElem::parse(s));
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
}
case AttrType::Bool:
return {{rowId, queryAttribute.getInt(2) != 0}};
case AttrType::Int:
return {{rowId, int_t{NixInt{queryAttribute.getInt(2)}}}};
case AttrType::ListOfStrings:
return {{rowId, tokenizeString<std::vector<std::string>>(queryAttribute.getStr(2), "\t")}};
case AttrType::Missing:
return {{rowId, missing_t()}};
case AttrType::Misc:
return {{rowId, misc_t()}};
case AttrType::Failed:
return {{rowId, failed_t()}};
default:
throw Error("unexpected type in evaluation cache");
case AttrType::Placeholder:
return {{rowId, placeholder_t()}};
case AttrType::FullAttrs: {
// FIXME: expensive, should separate this out.
std::vector<Symbol> attrs;
auto queryAttributes(state->queryAttributes.use()(rowId));
while (queryAttributes.next())
attrs.emplace_back(symbols.create(queryAttributes.getStr(0)));
return {{rowId, attrs}};
}
case AttrType::String: {
NixStringContext context;
if (!queryAttribute.isNull(3))
for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), ";"))
context.insert(NixStringContextElem::parse(s));
return {{rowId, string_t{queryAttribute.getStr(2), context}}};
}
case AttrType::Bool:
return {{rowId, queryAttribute.getInt(2) != 0}};
case AttrType::Int:
return {{rowId, int_t{NixInt{queryAttribute.getInt(2)}}}};
case AttrType::ListOfStrings:
return {{rowId, tokenizeString<std::vector<std::string>>(queryAttribute.getStr(2), "\t")}};
case AttrType::Missing:
return {{rowId, missing_t()}};
case AttrType::Misc:
return {{rowId, misc_t()}};
case AttrType::Failed:
return {{rowId, failed_t()}};
default:
throw Error("unexpected type in evaluation cache");
}
}
};
static std::shared_ptr<AttrDb> makeAttrDb(
const StoreDirConfig & cfg,
const Hash & fingerprint,
SymbolTable & symbols)
static std::shared_ptr<AttrDb> makeAttrDb(const StoreDirConfig & cfg, const Hash & fingerprint, SymbolTable & symbols)
{
try {
return std::make_shared<AttrDb>(cfg, fingerprint, symbols);
@@ -357,9 +295,7 @@ static std::shared_ptr<AttrDb> makeAttrDb(
}
EvalCache::EvalCache(
std::optional<std::reference_wrapper<const Hash>> useCache,
EvalState & state,
RootLoader rootLoader)
std::optional<std::reference_wrapper<const Hash>> useCache, EvalState & state, RootLoader rootLoader)
: db(useCache ? makeAttrDb(*state.store, *useCache, state.symbols) : nullptr)
, state(state)
, rootLoader(rootLoader)
@@ -381,11 +317,10 @@ ref<AttrCursor> EvalCache::getRoot()
}
AttrCursor::AttrCursor(
ref<EvalCache> root,
Parent parent,
Value * value,
std::optional<std::pair<AttrId, AttrValue>> && cachedValue)
: root(root), parent(parent), cachedValue(std::move(cachedValue))
ref<EvalCache> root, Parent parent, Value * value, std::optional<std::pair<AttrId, AttrValue>> && cachedValue)
: root(root)
, parent(parent)
, cachedValue(std::move(cachedValue))
{
if (value)
_value = allocRootValue(value);
@@ -470,13 +405,11 @@ Value & AttrCursor::forceValue()
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
if (v.type() == nString)
cachedValue = {root->db->setString(getKey(), v.c_str(), v.context()),
string_t{v.c_str(), {}}};
cachedValue = {root->db->setString(getKey(), v.c_str(), v.context()), string_t{v.c_str(), {}}};
else if (v.type() == nPath) {
auto path = v.path().path;
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
}
else if (v.type() == nBool)
} else if (v.type() == nBool)
cachedValue = {root->db->setBool(getKey(), v.boolean()), v.boolean()};
else if (v.type() == nInt)
cachedValue = {root->db->setInt(getKey(), v.integer().value), int_t{v.integer()}};
@@ -518,14 +451,14 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
else if (std::get_if<failed_t>(&attr->second))
throw CachedEvalError(ref(shared_from_this()), name);
else
return std::make_shared<AttrCursor>(root,
std::make_pair(ref(shared_from_this()), name), nullptr, std::move(attr));
return std::make_shared<AttrCursor>(
root, std::make_pair(ref(shared_from_this()), name), nullptr, std::move(attr));
}
// Incomplete attrset, so need to fall thru and
// evaluate to see whether 'name' exists
} else
return nullptr;
//error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
// error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
}
}
@@ -533,7 +466,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
if (v.type() != nAttrs)
return nullptr;
//error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
// error<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
auto attr = v.attrs()->get(name);
@@ -618,17 +551,15 @@ string_t AttrCursor::getStringWithContext()
if (auto s = std::get_if<string_t>(&cachedValue->second)) {
bool valid = true;
for (auto & c : s->second) {
const StorePath & path = std::visit(overloaded {
[&](const NixStringContextElem::DrvDeep & d) -> const StorePath & {
return d.drvPath;
const StorePath & path = std::visit(
overloaded{
[&](const NixStringContextElem::DrvDeep & d) -> const StorePath & { return d.drvPath; },
[&](const NixStringContextElem::Built & b) -> const StorePath & {
return b.drvPath->getBaseStorePath();
},
[&](const NixStringContextElem::Opaque & o) -> const StorePath & { return o.path; },
},
[&](const NixStringContextElem::Built & b) -> const StorePath & {
return b.drvPath->getBaseStorePath();
},
[&](const NixStringContextElem::Opaque & o) -> const StorePath & {
return o.path;
},
}, c.raw);
c.raw);
if (!root->state.store->isValidPath(path)) {
valid = false;
break;
@@ -649,8 +580,7 @@ string_t AttrCursor::getStringWithContext()
NixStringContext context;
copyContext(v, context);
return {v.c_str(), std::move(context)};
}
else if (v.type() == nPath)
} else if (v.type() == nPath)
return {v.path().to_string(), {}};
else
root->state.error<TypeError>("'%s' is not a string but %s", getAttrPathStr(), showType(v)).debugThrow();
@@ -722,7 +652,8 @@ std::vector<std::string> AttrCursor::getListOfStrings()
std::vector<std::string> res;
for (auto & elem : v.listItems())
res.push_back(std::string(root->state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching")));
res.push_back(
std::string(root->state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching")));
if (root->db)
cachedValue = {root->db->setListOfStrings(getKey(), res), res};
@@ -778,10 +709,10 @@ StorePath AttrCursor::forceDerivation()
been garbage-collected. So force it to be regenerated. */
aDrvPath->forceValue();
if (!root->state.store->isValidPath(drvPath))
throw Error("don't know how to recreate store derivation '%s'!",
root->state.store->printStorePath(drvPath));
throw Error(
"don't know how to recreate store derivation '%s'!", root->state.store->printStorePath(drvPath));
}
return drvPath;
}
}
} // namespace nix::eval_cache

View File

@@ -44,12 +44,13 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrame(const Env & env, const Expr
// NOTE: This is abusing side-effects.
// TODO: check compatibility with nested debugger calls.
// TODO: What side-effects??
error.state.debugTraces.push_front(DebugTrace{
.pos = expr.getPos(),
.expr = expr,
.env = env,
.hint = HintFmt("Fake frame for debugging purposes"),
.isError = true});
error.state.debugTraces.push_front(
DebugTrace{
.pos = expr.getPos(),
.expr = expr,
.env = env,
.hint = HintFmt("Fake frame for debugging purposes"),
.isError = true});
return *this;
}
@@ -96,7 +97,8 @@ template<class T>
void EvalErrorBuilder<T>::panic()
{
logError(error.info());
printError("This is a bug! An unexpected condition occurred, causing the Nix evaluator to have to stop. If you could share a reproducible example or a core dump, please open an issue at https://github.com/NixOS/nix/issues");
printError(
"This is a bug! An unexpected condition occurred, causing the Nix evaluator to have to stop. If you could share a reproducible example or a core dump, please open an issue at https://github.com/NixOS/nix/issues");
abort();
}
@@ -112,4 +114,4 @@ template class EvalErrorBuilder<InfiniteRecursionError>;
template class EvalErrorBuilder<InvalidPathError>;
template class EvalErrorBuilder<IFDError>;
}
} // namespace nix

View File

@@ -19,12 +19,14 @@ Strings EvalSettings::parseNixPath(const std::string & s)
auto start2 = p;
while (p != s.end() && *p != ':') {
if (*p == '=') start2 = p + 1;
if (*p == '=')
start2 = p + 1;
++p;
}
if (p == s.end()) {
if (p != start) res.push_back(std::string(start, p));
if (p != start)
res.push_back(std::string(start, p));
break;
}
@@ -32,10 +34,12 @@ Strings EvalSettings::parseNixPath(const std::string & s)
auto prefix = std::string(start2, s.end());
if (EvalSettings::isPseudoUrl(prefix) || hasPrefix(prefix, "flake:")) {
++p;
while (p != s.end() && *p != ':') ++p;
while (p != s.end() && *p != ':')
++p;
}
res.push_back(std::string(start, p));
if (p == s.end()) break;
if (p == s.end())
break;
}
++p;
@@ -75,11 +79,14 @@ Strings EvalSettings::getDefaultNixPath()
bool EvalSettings::isPseudoUrl(std::string_view s)
{
if (s.compare(0, 8, "channel:") == 0) return true;
if (s.compare(0, 8, "channel:") == 0)
return true;
size_t pos = s.find("://");
if (pos == std::string::npos) return false;
if (pos == std::string::npos)
return false;
std::string scheme(s, 0, pos);
return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git" || scheme == "s3" || scheme == "ssh";
return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git"
|| scheme == "s3" || scheme == "ssh";
}
std::string EvalSettings::resolvePseudoUrl(std::string_view url)
@@ -98,9 +105,7 @@ const std::string & EvalSettings::getCurrentSystem() const
Path getNixDefExpr()
{
return settings.useXDGBaseDirectories
? getStateDir() + "/defexpr"
: getHome() + "/.nix-defexpr";
return settings.useXDGBaseDirectories ? getStateDir() + "/defexpr" : getHome() + "/.nix-defexpr";
}
} // namespace nix

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