Compare commits
417
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9446732466 | ||
|
|
b5c3c21792 | ||
|
|
fc8bd88cf4 | ||
|
|
9b2761d66d | ||
|
|
fe79b90055 | ||
|
|
0d14c2b67a | ||
|
|
9760c00591 | ||
|
|
bf3ebde25f | ||
|
|
423d8b03c8 | ||
|
|
acbb3cff2d | ||
|
|
38dd196b03 | ||
|
|
d46adb45eb | ||
|
|
0dbfa7b26e | ||
|
|
4737d8b65e | ||
|
|
c948b350fb | ||
|
|
8db8ac9a67 | ||
|
|
3f6a1e45c9 | ||
|
|
ede0851fb4 | ||
|
|
5af069b248 | ||
|
|
f93af1db1f | ||
|
|
3acba7951a | ||
|
|
44255c316d | ||
|
|
d953e138a2 | ||
|
|
fafe647bc2 | ||
|
|
37e8904ba7 | ||
|
|
3413ab5629 | ||
|
|
a1c09bed7b | ||
|
|
8c1ece93cc | ||
|
|
c314c5e581 | ||
|
|
6e8bc92ca5 | ||
|
|
539c340c66 | ||
|
|
5c7ea4f446 | ||
|
|
92ed9fee7d | ||
|
|
4f5e5e9bdf | ||
|
|
06996718c3 | ||
|
|
cb44fe7c15 | ||
|
|
67f07e05df | ||
|
|
bc63b007e5 | ||
|
|
f51943f171 | ||
|
|
5530de4673 | ||
|
|
faf00ad022 | ||
|
|
c0808bd855 | ||
|
|
93d5221b9b | ||
|
|
21ad02c1d0 | ||
|
|
8ddcdfb59c | ||
|
|
445b7c7d8a | ||
|
|
9a96086381 | ||
|
|
7c76053d93 | ||
|
|
95e088de72 | ||
|
|
369e3f82f0 | ||
|
|
a2ae14bfd8 | ||
|
|
172515bd8b | ||
|
|
cdda2454f6 | ||
|
|
f7687fa414 | ||
|
|
9611018c27 | ||
|
|
2a9e560570 | ||
|
|
53e0b6ecfb | ||
|
|
fb76a4d335 | ||
|
|
9dd58224ea | ||
|
|
61eed2c97c | ||
|
|
07a26fc776 | ||
|
|
71c392ae0f | ||
|
|
7fa6e785ff | ||
|
|
1f37fc85ac | ||
|
|
5db5eed43d | ||
|
|
d30027a37a | ||
|
|
2f2bc90d92 | ||
|
|
014845ddf1 | ||
|
|
8e74d1ceeb | ||
|
|
ce698198f0 | ||
|
|
81559ea8ad | ||
|
|
473c1bdcab | ||
|
|
9ff702554d | ||
|
|
8468dc65c7 | ||
|
|
f47cd0fc88 | ||
|
|
d6a7fb5f6a | ||
|
|
a5d02bcdf9 | ||
|
|
9a3e3a5560 | ||
|
|
dd7d7450a5 | ||
|
|
276a771210 | ||
|
|
ea931d4d03 | ||
|
|
32f7a93f71 | ||
|
|
a65e9e5828 | ||
|
|
a4fa93d469 | ||
|
|
ef1d62ec6c | ||
|
|
0bfa58ff53 | ||
|
|
2e5780ebc8 | ||
|
|
1e064e08fa | ||
|
|
1ed0814859 | ||
|
|
12802b492a | ||
|
|
e9520ffd06 | ||
|
|
63006438c4 | ||
|
|
e44dbfe97a | ||
|
|
94bb66c867 | ||
|
|
85d600ca4d | ||
|
|
37aeb3059d | ||
|
|
105d8ceb36 | ||
|
|
66d7128512 | ||
|
|
f815b966c4 | ||
|
|
2297d3f895 | ||
|
|
7c650ea241 | ||
|
|
564f464772 | ||
|
|
9fb5315d06 | ||
|
|
81d5f0a7d9 | ||
|
|
f5754dc90a | ||
|
|
cb8262e11c | ||
|
|
3593f5555e | ||
|
|
985afeeb4d | ||
|
|
35cb0cb28b | ||
|
|
5892ed2731 | ||
|
|
89a0ddc108 | ||
|
|
9554a1ae29 | ||
|
|
003883306d | ||
|
|
e635db77e3 | ||
|
|
7af000ddff | ||
|
|
f017f9ddd3 | ||
|
|
650809f66e | ||
|
|
f5cddcfc09 | ||
|
|
66f6dbda32 | ||
|
|
a911b44a31 | ||
|
|
74d820e5e8 | ||
|
|
9cf91b7385 | ||
|
|
c4a077d0b8 | ||
|
|
ac74dc3a2b | ||
|
|
34e592ea6a | ||
|
|
95a9a4cece | ||
|
|
b0d7a81613 | ||
|
|
f116608a20 | ||
|
|
0bec915522 | ||
|
|
519957bd59 | ||
|
|
950c213ddf | ||
|
|
16bed313c6 | ||
|
|
33e832ba5a | ||
|
|
6334e91b2f | ||
|
|
fbdb177b31 | ||
|
|
6a9b66357e | ||
|
|
13f54451e6 | ||
|
|
103cd44a04 | ||
|
|
eeaa72b62b | ||
|
|
94ca95714e | ||
|
|
df0e1993b7 | ||
|
|
b62cc7b361 | ||
|
|
c859d03013 | ||
|
|
8088927b90 | ||
|
|
3dba1d341a | ||
|
|
3b1298efce | ||
|
|
b22f2bc8e9 | ||
|
|
986a98d32f | ||
|
|
4ba19f68fb | ||
|
|
43777939eb | ||
|
|
7d7e16ecec | ||
|
|
5be7956592 | ||
|
|
8a9094303b | ||
|
|
a378c61948 | ||
|
|
d0bcdfa6c4 | ||
|
|
d1d96cc4c8 | ||
|
|
27af6989bb | ||
|
|
efb04754be | ||
|
|
001a078b96 | ||
|
|
d75c399b29 | ||
|
|
1338e93bc9 | ||
|
|
60e984f0cf | ||
|
|
40cf413a48 | ||
|
|
90536e27e1 | ||
|
|
5d02800e57 | ||
|
|
40be91afbf | ||
|
|
fb85228755 | ||
|
|
12156d3beb | ||
|
|
c1746300a9 | ||
|
|
2e0c1a5ea9 | ||
|
|
21fc0ddce5 | ||
|
|
b967f1d5fe | ||
|
|
08a362a540 | ||
|
|
d0e0969810 | ||
|
|
116895acb1 | ||
|
|
86eddb9e27 | ||
|
|
3c8096e5cb | ||
|
|
72cce7be3f | ||
|
|
1ecfff9c37 | ||
|
|
72292671a9 | ||
|
|
1c28270c9d | ||
|
|
6b7076f81c | ||
|
|
d73211356a | ||
|
|
b1a0e3c002 | ||
|
|
763a61bb7c | ||
|
|
7df8b15b39 | ||
|
|
3aad088cf1 | ||
|
|
add8a4df9f | ||
|
|
9903bed3f4 | ||
|
|
486d1a1437 | ||
|
|
6e2349d2e1 | ||
|
|
834450e237 | ||
|
|
8005d17365 | ||
|
|
69957a971e | ||
|
|
684f93e783 | ||
|
|
11950a0a79 | ||
|
|
beb193d1e2 | ||
|
|
4ae6fb5a8f | ||
|
|
c95b73d8a1 | ||
|
|
a778b0f85a | ||
|
|
56ead73fda | ||
|
|
22eb47f0fd | ||
|
|
8b2f8d538b | ||
|
|
fb1b211037 | ||
|
|
8b0ac51f12 | ||
|
|
9c22a4d31b | ||
|
|
c83b13eafd | ||
|
|
d65838a900 | ||
|
|
c68f0cdf00 | ||
|
|
14eff10fe4 | ||
|
|
923abe347c | ||
|
|
64864c3730 | ||
|
|
10488f7431 | ||
|
|
8c567c0424 | ||
|
|
a042bbde56 | ||
|
|
61146c73ce | ||
|
|
f55ed83991 | ||
|
|
212a14bb1f | ||
|
|
7c716b9716 | ||
|
|
2b3bdda027 | ||
|
|
97c76c4655 | ||
|
|
c82407fc1e | ||
|
|
982d049d3b | ||
|
|
5cd7055044 | ||
|
|
6f18e1ebde | ||
|
|
a839c31e6c | ||
|
|
30bec83fa4 | ||
|
|
d82b212d33 | ||
|
|
220251ba51 | ||
|
|
9f682204b5 | ||
|
|
f9e7df01f3 | ||
|
|
f7edee7c14 | ||
|
|
6c2609c5f9 | ||
|
|
af27d1ecd8 | ||
|
|
1e3b45546c | ||
|
|
ce3e1d1e7a | ||
|
|
2d49efaa2e | ||
|
|
98b55c3a1d | ||
|
|
a83bf24281 | ||
|
|
02c35ea9df | ||
|
|
a8d6577bf0 | ||
|
|
59e364c2a8 | ||
|
|
b020d1fc27 | ||
|
|
2734a9cf94 | ||
|
|
5f1344dd8a | ||
|
|
faee771b30 | ||
|
|
b8cc54df0a | ||
|
|
67f1aafd61 | ||
|
|
1d9d40b2a6 | ||
|
|
343aca3a27 | ||
|
|
5ce1d8463a | ||
|
|
b77687945e | ||
|
|
4308ec1ae4 | ||
|
|
65551175e3 | ||
|
|
068f4b147d | ||
|
|
0ff8f91325 | ||
|
|
b0e619b8bd | ||
|
|
564d931134 | ||
|
|
dccde94369 | ||
|
|
60b89c63db | ||
|
|
60578b4d7d | ||
|
|
eadce58a90 | ||
|
|
ca55060ac6 | ||
|
|
77b6f6734f | ||
|
|
e2d00ac3a8 | ||
|
|
3ba5ef91bc | ||
|
|
e5de1d13c4 | ||
|
|
878e181882 | ||
|
|
c852ae60da | ||
|
|
765771a355 | ||
|
|
14291856e4 | ||
|
|
e7d6212f77 | ||
|
|
f98ee07573 | ||
|
|
580df9bdb3 | ||
|
|
52b64662a4 | ||
|
|
689eb45630 | ||
|
|
ece99fee23 | ||
|
|
4dbbd721eb | ||
|
|
e55cd3beea | ||
|
|
5a06b17b91 | ||
|
|
f6077314fa | ||
|
|
a020f5f6cb | ||
|
|
fbf7a8b440 | ||
|
|
31ff77b3f9 | ||
|
|
c1f4c60bc2 | ||
|
|
8497f0fe19 | ||
|
|
4682e40183 | ||
|
|
d726236e27 | ||
|
|
326cbecb61 | ||
|
|
a322fcea4a | ||
|
|
a0fb52c0af | ||
|
|
822997bd34 | ||
|
|
4180b84a67 | ||
|
|
3571817e3a | ||
|
|
3caf3e1e08 | ||
|
|
9865ebaaa6 | ||
|
|
7f7a38f278 | ||
|
|
0012887310 | ||
|
|
4ea8c9d643 | ||
|
|
43e79f4434 | ||
|
|
299813f324 | ||
|
|
d6e1b11d3e | ||
|
|
51a5025913 | ||
|
|
ed9b7f4f84 | ||
|
|
649d8cd08f | ||
|
|
9adf6f4568 | ||
|
|
03cbc0ecb9 | ||
|
|
1caf2afb1d | ||
|
|
7ff60b7445 | ||
|
|
fc6291e46d | ||
|
|
40f154c0ed | ||
|
|
f389a54079 | ||
|
|
7ef4466018 | ||
|
|
a9f2aab226 | ||
|
|
99edc2ae38 | ||
|
|
896a123605 | ||
|
|
0d484aa498 | ||
|
|
86b213e632 | ||
|
|
a3dd07535c | ||
|
|
5df2cccc49 | ||
|
|
345e3d068a | ||
|
|
19edaed81b | ||
|
|
5b1715e633 | ||
|
|
0b29859cfe | ||
|
|
1bfc37fea5 | ||
|
|
8f300fbd82 | ||
|
|
36073781fb | ||
|
|
b63d4a0c62 | ||
|
|
ee0c195eba | ||
|
|
7752927660 | ||
|
|
3edc272341 | ||
|
|
9b05636937 | ||
|
|
9889c79fe3 | ||
|
|
732de75f67 | ||
|
|
d5db0b1abc | ||
|
|
b0c7c1ec66 | ||
|
|
d31310bf59 | ||
|
|
8e05cc1e6c | ||
|
|
a16ceb9411 | ||
|
|
aa33c34c9b | ||
|
|
ccd2862666 | ||
|
|
47ddd11933 | ||
|
|
7f4f86795c | ||
|
|
a5240b23ab | ||
|
|
8fb642b6e0 | ||
|
|
1a52e4f755 | ||
|
|
3f7519526f | ||
|
|
289e7a6b5a | ||
|
|
f12b60273b | ||
|
|
04daff94e3 | ||
|
|
4780dd6bc4 | ||
|
|
b86863d935 | ||
|
|
624f44bf25 | ||
|
|
0e6b3435a1 | ||
|
|
ae5d8dae1b | ||
|
|
852da07b67 | ||
|
|
bf32085d63 | ||
|
|
cd1ceffb0e | ||
|
|
0478949c72 | ||
|
|
2265536e85 | ||
|
|
14dc84ed03 | ||
|
|
619a93bd54 | ||
|
|
5dc7671d81 | ||
|
|
b6038e988d | ||
|
|
531d040e8c | ||
|
|
ca9256a789 | ||
|
|
4b66e1e24f | ||
|
|
37b22dae04 | ||
|
|
31954b5136 | ||
|
|
acf963468f | ||
|
|
c1631b0a39 | ||
|
|
aca19187d0 | ||
|
|
19e0ce2c03 | ||
|
|
8a6b84df14 | ||
|
|
eccbe9586a | ||
|
|
2f794733b2 | ||
|
|
5f298f74c9 | ||
|
|
79246a3733 | ||
|
|
789b19a0cf | ||
|
|
0943b214c9 | ||
|
|
2afdf1ed66 | ||
|
|
ed381cd58a | ||
|
|
4046e019ca | ||
|
|
8ab5743904 | ||
|
|
7ae0409989 | ||
|
|
80202e3ca3 | ||
|
|
727258241f | ||
|
|
5246cea6c8 | ||
|
|
8f88590d13 | ||
|
|
3f07c65510 | ||
|
|
b7fc37b015 | ||
|
|
ca1dc3f70b | ||
|
|
b2fc007811 | ||
|
|
82aa1ccab4 | ||
|
|
df0137226d | ||
|
|
81c2e0ac8e | ||
|
|
24db81eaf2 | ||
|
|
cc183fdbc1 | ||
|
|
f5ae72d445 | ||
|
|
6de6cae3e7 | ||
|
|
8f7ab26f96 | ||
|
|
c14486ae8d | ||
|
|
e9505dcc5a | ||
|
|
f2a49032a6 | ||
|
|
92eccfbd68 | ||
|
|
4715d557ef | ||
|
|
991d8ce275 | ||
|
|
72589e7032 | ||
|
|
644176a631 | ||
|
|
63ee2cdda3 | ||
|
|
d7c37324bb | ||
|
|
75c0de3e3c | ||
|
|
fc4a160878 | ||
|
|
b7b1b9723f | ||
|
|
9d8f433246 | ||
|
|
742303dc3a | ||
|
|
de552c42cb |
@@ -16,6 +16,8 @@ Checks:
|
||||
- -bugprone-unchecked-optional-access
|
||||
# many warnings, seems like a questionable lint
|
||||
- -bugprone-branch-clone
|
||||
# extremely noisy before clang 19: https://github.com/llvm/llvm-project/issues/93959
|
||||
- -bugprone-multi-level-implicit-pointer-conversion
|
||||
# all thrown exceptions must derive from std::exception
|
||||
- hicpp-exception-baseclass
|
||||
# capturing async lambdas are dangerous
|
||||
@@ -33,3 +35,4 @@ Checks:
|
||||
|
||||
CheckOptions:
|
||||
bugprone-reserved-identifier.AllowedIdentifiers: '__asan_default_options'
|
||||
bugprone-unused-return-value.AllowCastToVoid: true
|
||||
|
||||
@@ -29,3 +29,7 @@ trim_trailing_whitespace = false
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
max_line_length = 0
|
||||
|
||||
[meson.build]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Missing or incorrect documentation
|
||||
about: Help us improve the reference manual
|
||||
title: ''
|
||||
labels: documentation
|
||||
labels: docs
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
@@ -19,10 +19,10 @@ assignees: ''
|
||||
|
||||
<!-- make sure this issue is not redundant or obsolete -->
|
||||
|
||||
- [ ] checked [latest Lix manual] \([source]\)
|
||||
- [ ] checked [latest Lix manual] or its [source code]
|
||||
- [ ] checked [documentation issues] and [recent documentation changes] for possible duplicates
|
||||
|
||||
[latest Nix manual]: https://docs.lix.systems/manual/lix/nightly
|
||||
[source]: https://git.lix.systems/lix-project/lix/src/main/doc/manual/src
|
||||
[latest Lix manual]: https://docs.lix.systems/manual/lix/nightly
|
||||
[source code]: https://git.lix.systems/lix-project/lix/src/main/doc/manual/src
|
||||
[documentation issues]: https://git.lix.systems/lix-project/lix/issues?labels=151&state=all
|
||||
[recent documentation changes]: https://gerrit.lix.systems/q/p:lix+path:%22%5Edoc/manual/.*%22
|
||||
|
||||
@@ -36,3 +36,6 @@ buildtime.bin
|
||||
|
||||
# Rust build files when using Cargo (not actually supported for building but it spews the files anyway)
|
||||
/target/
|
||||
|
||||
# Python compiled files from the code generators and test suite
|
||||
*.pyc
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Fiona Behrens <me@kloenk.dev>
|
||||
Fiona Behrens <me@kloenk.dev> <me@kloenk.de>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["src/lix-doc"]
|
||||
members = ["lix/lix-doc"]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
|
||||
+10
-4
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p bash -p hyperfine
|
||||
|
||||
set -euo pipefail
|
||||
shopt -s inherit_errexit
|
||||
@@ -21,16 +22,21 @@ fi
|
||||
_exit=""
|
||||
trap "$_exit" EXIT
|
||||
|
||||
# XXX: yes this is very silly. flakes~!!
|
||||
nix build --impure --expr '(builtins.getFlake "git+file:.").inputs.nixpkgs.outPath' -o bench/nixpkgs
|
||||
flake_args=("--extra-experimental-features" "nix-command flakes")
|
||||
|
||||
# XXX: yes this is very silly. flakes~!!
|
||||
nix build "${flake_args[@]}" --impure --expr '(builtins.getFlake "git+file:.").inputs.nixpkgs.outPath' -o bench/nixpkgs
|
||||
|
||||
# We must ignore the global config, or else NIX_PATH won't work reliably.
|
||||
# See https://github.com/NixOS/nix/issues/9574
|
||||
export NIX_CONF_DIR='/var/empty'
|
||||
export NIX_REMOTE="$(mktemp -d)"
|
||||
_exit='rm -rfv "$NIX_REMOTE"; $_exit'
|
||||
export NIX_PATH="nixpkgs=bench/nixpkgs:nixos-config=bench/configuration.nix"
|
||||
|
||||
builds=("$@")
|
||||
|
||||
flake_args="--extra-experimental-features 'nix-command flakes'"
|
||||
flake_args="${flake_args[*]@Q}"
|
||||
|
||||
hyperfineArgs=(
|
||||
--parameter-list BUILD "$(IFS=,; echo "${builds[*]}")"
|
||||
|
||||
+10
-21
@@ -32,8 +32,8 @@
|
||||
hardware = {
|
||||
enableRedistributableFirmware = true;
|
||||
cpu.intel.updateMicrocode = true;
|
||||
opengl.driSupport32Bit = true;
|
||||
opengl.extraPackages = with pkgs; [
|
||||
graphics.enable32Bit = true;
|
||||
graphics.extraPackages = with pkgs; [
|
||||
vaapiIntel
|
||||
intel-media-driver
|
||||
intel-compute-runtime
|
||||
@@ -93,16 +93,17 @@
|
||||
|
||||
i18n = {
|
||||
defaultLocale = "en_US.UTF-8";
|
||||
inputMethod.enabled = "ibus";
|
||||
inputMethod.enable = true;
|
||||
inputMethod.type = "ibus";
|
||||
};
|
||||
|
||||
services = {
|
||||
libinput.enable = true;
|
||||
xserver = {
|
||||
enable = true;
|
||||
layout = "us";
|
||||
xkbVariant = "altgr-intl";
|
||||
xkbOptions = "ctrl:nocaps";
|
||||
libinput.enable = true;
|
||||
xkb.layout = "us";
|
||||
xkb.variant = "altgr-intl";
|
||||
xkb.options = "ctrl:nocaps";
|
||||
wacom.enable = true;
|
||||
videoDrivers = [ "modesetting" ];
|
||||
modules = [ pkgs.xf86_input_wacom ];
|
||||
@@ -121,17 +122,6 @@
|
||||
'';
|
||||
};
|
||||
|
||||
sound.enable = true;
|
||||
hardware.pulseaudio = {
|
||||
enable = true;
|
||||
package = pkgs.pulseaudioFull;
|
||||
daemon.config = {
|
||||
lock-memory = "yes";
|
||||
realtime-scheduling = "yes";
|
||||
rlimit-rtprio = "-1";
|
||||
};
|
||||
};
|
||||
|
||||
programs = {
|
||||
light.enable = true;
|
||||
wireshark = {
|
||||
@@ -146,7 +136,7 @@
|
||||
fonts.packages = with pkgs; [
|
||||
font-awesome
|
||||
noto-fonts
|
||||
noto-fonts-cjk
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-emoji
|
||||
noto-fonts-extra
|
||||
dejavu_fonts
|
||||
@@ -239,7 +229,7 @@
|
||||
file
|
||||
firefox
|
||||
fluidsynth
|
||||
gnome3.adwaita-icon-theme
|
||||
adwaita-icon-theme
|
||||
gnuplot
|
||||
graphviz
|
||||
helm
|
||||
@@ -252,7 +242,6 @@
|
||||
libqalculate
|
||||
libreoffice
|
||||
man-pages
|
||||
nheko
|
||||
nix-diff
|
||||
nix-index
|
||||
nix-output-monitor
|
||||
|
||||
@@ -33,32 +33,7 @@ GENERATE_LATEX = NO
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
# FIXME Make this list more maintainable somehow. We could maybe generate this
|
||||
# in the Makefile, but we would need to change how `.in` files are preprocessed
|
||||
# so they can expand variables despite configure variables.
|
||||
|
||||
INPUT = \
|
||||
src/libcmd \
|
||||
src/libexpr \
|
||||
src/libexpr/flake \
|
||||
tests/unit/libexpr \
|
||||
tests/unit/libexpr/value \
|
||||
tests/unit/libexpr/test \
|
||||
tests/unit/libexpr/test/value \
|
||||
src/libexpr/value \
|
||||
src/libfetchers \
|
||||
src/libmain \
|
||||
src/libstore \
|
||||
src/libstore/build \
|
||||
src/libstore/builtins \
|
||||
tests/unit/libstore \
|
||||
tests/unit/libstore/test \
|
||||
src/libutil \
|
||||
tests/unit/libutil \
|
||||
tests/unit/libutil/test \
|
||||
src/nix \
|
||||
src/nix-env \
|
||||
src/nix-store
|
||||
INPUT = @INPUT_PATHS@
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
|
||||
# in the source code. If set to NO, only conditional compilation will be
|
||||
@@ -97,3 +72,15 @@ EXPAND_AS_DEFINED = \
|
||||
DECLARE_WORKER_SERIALISER \
|
||||
DECLARE_SERVE_SERIALISER \
|
||||
LENGTH_PREFIXED_PROTO_HELPER
|
||||
|
||||
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
|
||||
# Stripping is only done if one of the specified strings matches the left-hand
|
||||
# part of the path. The tag can be used to show relative paths in the file list.
|
||||
# If left blank the directory from which doxygen is run is used as the path to
|
||||
# strip.
|
||||
#
|
||||
# Note that you can specify absolute paths here, but also relative paths, which
|
||||
# will be relative from the directory where doxygen is started.
|
||||
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
|
||||
|
||||
STRIP_FROM_PATH = "@PROJECT_SOURCE_ROOT@"
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
internal_api_sources = [
|
||||
'lix/libcmd',
|
||||
'lix/libexpr',
|
||||
'lix/libexpr/flake',
|
||||
'tests/unit/libexpr',
|
||||
'tests/unit/libexpr/value',
|
||||
'tests/unit/libexpr/test',
|
||||
'tests/unit/libexpr/test/value',
|
||||
'lix/libexpr/value',
|
||||
'lix/libfetchers',
|
||||
'lix/libmain',
|
||||
'lix/libstore',
|
||||
'lix/libstore/build',
|
||||
'lix/libstore/builtins',
|
||||
'tests/unit/libstore',
|
||||
'tests/unit/libstore/test',
|
||||
'lix/libutil',
|
||||
'tests/unit/libutil',
|
||||
'tests/unit/libutil/test',
|
||||
'lix/nix',
|
||||
'lix/nix-env',
|
||||
'lix/nix-store',
|
||||
]
|
||||
|
||||
# We feed Doxygen absolute paths so it can be invoked from any working directory.
|
||||
internal_api_sources_absolute = []
|
||||
foreach src : internal_api_sources
|
||||
internal_api_sources_absolute += '"' + (meson.project_source_root() / src) + '"'
|
||||
endforeach
|
||||
|
||||
internal_api_sources_oneline = ' \\\n '.join(internal_api_sources_absolute)
|
||||
|
||||
doxygen_cfg = configure_file(
|
||||
input : 'doxygen.cfg.in',
|
||||
output : 'doxygen.cfg',
|
||||
@@ -5,22 +37,16 @@ doxygen_cfg = configure_file(
|
||||
'PACKAGE_VERSION': meson.project_version(),
|
||||
'RAPIDCHECK_HEADERS': rapidcheck_meson.get_variable('includedir'),
|
||||
'docdir' : meson.current_build_dir(),
|
||||
'INPUT_PATHS' : internal_api_sources_oneline,
|
||||
'PROJECT_SOURCE_ROOT' : meson.project_source_root(),
|
||||
},
|
||||
)
|
||||
|
||||
internal_api_docs = custom_target(
|
||||
'internal-api-docs',
|
||||
command : [
|
||||
bash,
|
||||
# Meson can you please just give us a `workdir` argument to custom targets...
|
||||
'-c',
|
||||
# We have to prefix the doxygen_cfg path with the project build root
|
||||
# because of the cd in front.
|
||||
'cd @0@ && @1@ @2@/@INPUT0@'.format(
|
||||
meson.project_source_root(),
|
||||
doxygen.full_path(),
|
||||
meson.project_build_root(),
|
||||
),
|
||||
doxygen.full_path(),
|
||||
'@INPUT0@',
|
||||
],
|
||||
input : [
|
||||
doxygen_cfg,
|
||||
|
||||
@@ -70,6 +70,10 @@ horrors:
|
||||
iFreilicht:
|
||||
github: iFreilicht
|
||||
|
||||
ian-h-chamberlain:
|
||||
forgejo: ian-h-chamberlain
|
||||
github: ian-h-chamberlain
|
||||
|
||||
isabelroses:
|
||||
forgejo: isabelroses
|
||||
github: isabelroses
|
||||
@@ -78,13 +82,28 @@ jade:
|
||||
forgejo: jade
|
||||
github: lf-
|
||||
|
||||
just1602:
|
||||
forgejo: just1602
|
||||
|
||||
kiara:
|
||||
github: KiaraGrouwstra
|
||||
|
||||
kjeremy:
|
||||
github: kjeremy
|
||||
|
||||
kloenk:
|
||||
display_name: Fiona Behrens
|
||||
forgejo: kloenk
|
||||
github: kloenk
|
||||
|
||||
lheckemann:
|
||||
forgejo: lheckemann
|
||||
github: lheckemann
|
||||
|
||||
lilyball:
|
||||
forgejo: lilyball
|
||||
github: lilyball
|
||||
|
||||
lovesegfault:
|
||||
github: lovesegfault
|
||||
|
||||
@@ -141,9 +160,17 @@ valentin:
|
||||
display_name: Valentin Gagarin
|
||||
github: fricklerhandwerk
|
||||
|
||||
vigress8:
|
||||
display_name: Vigress
|
||||
forgejo: vigress8
|
||||
github: vigress8
|
||||
|
||||
winter:
|
||||
forgejo: winter
|
||||
github: winterqt
|
||||
|
||||
yshui:
|
||||
github: yshui
|
||||
|
||||
zimbatm:
|
||||
github: zimbatm
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
let
|
||||
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||
inherit (import ./utils.nix) optionalString squash;
|
||||
in
|
||||
|
||||
builtinsInfo:
|
||||
let
|
||||
showBuiltin =
|
||||
name:
|
||||
{
|
||||
doc,
|
||||
type,
|
||||
impure-only,
|
||||
}:
|
||||
let
|
||||
type' = optionalString (type != null) " (${type})";
|
||||
|
||||
impureNotice = optionalString impure-only ''
|
||||
> **Note**
|
||||
>
|
||||
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||
'';
|
||||
in
|
||||
squash ''
|
||||
<dt id="builtins-${name}">
|
||||
<a href="#builtins-${name}"><code>${name}</code></a>${type'}
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
${doc}
|
||||
|
||||
${impureNotice}
|
||||
|
||||
</dd>
|
||||
'';
|
||||
in
|
||||
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
||||
@@ -1,35 +0,0 @@
|
||||
let
|
||||
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||
inherit (import ./utils.nix) optionalString squash;
|
||||
in
|
||||
|
||||
builtinsInfo:
|
||||
let
|
||||
showBuiltin =
|
||||
name:
|
||||
{
|
||||
doc,
|
||||
args,
|
||||
arity,
|
||||
experimental-feature,
|
||||
}:
|
||||
let
|
||||
experimentalNotice = optionalString (experimental-feature != null) ''
|
||||
This function is only available if the [${experimental-feature}](@docroot@/contributing/experimental-features.md#xp-feature-${experimental-feature}) experimental feature is enabled.
|
||||
'';
|
||||
in
|
||||
squash ''
|
||||
<dt id="builtins-${name}">
|
||||
<a href="#builtins-${name}"><code>${name} ${listArgs args}</code></a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
${doc}
|
||||
|
||||
${experimentalNotice}
|
||||
|
||||
</dd>
|
||||
'';
|
||||
listArgs = args: concatStringsSep " " (map (s: "<var>${s}</var>") args);
|
||||
in
|
||||
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
||||
@@ -1,14 +0,0 @@
|
||||
# Usually "experimental" or "deprecated"
|
||||
kind:
|
||||
# "xp" or "dp"
|
||||
kindShort:
|
||||
|
||||
with builtins;
|
||||
with import ./utils.nix;
|
||||
|
||||
let
|
||||
showExperimentalFeature = name: doc: ''
|
||||
- [`${name}`](@docroot@/contributing/${kind}-features.md#${kindShort}-feature-${name})
|
||||
'';
|
||||
in
|
||||
xps: indent " " (concatStrings (attrValues (mapAttrs showExperimentalFeature xps)))
|
||||
@@ -1,18 +0,0 @@
|
||||
# Usually "experimental" or "deprecated"
|
||||
_kind:
|
||||
# "xp" or "dp"
|
||||
kindShort:
|
||||
|
||||
with builtins;
|
||||
with import ./utils.nix;
|
||||
|
||||
let
|
||||
showFeature =
|
||||
name: doc:
|
||||
squash ''
|
||||
## [`${name}`]{#${kindShort}-feature-${name}}
|
||||
|
||||
${doc}
|
||||
'';
|
||||
in
|
||||
xps: (concatStringsSep "\n" (attrValues (mapAttrs showFeature xps)))
|
||||
+130
-22
@@ -1,26 +1,134 @@
|
||||
with builtins;
|
||||
|
||||
let
|
||||
inherit (builtins)
|
||||
attrNames
|
||||
attrValues
|
||||
fromJSON
|
||||
listToAttrs
|
||||
mapAttrs
|
||||
concatStringsSep
|
||||
concatMap
|
||||
length
|
||||
lessThan
|
||||
replaceStrings
|
||||
sort
|
||||
;
|
||||
inherit (import ./utils.nix)
|
||||
concatStrings
|
||||
optionalString
|
||||
filterAttrs
|
||||
trim
|
||||
squash
|
||||
unique
|
||||
showSettings
|
||||
;
|
||||
splitLines = s: filter (x: !isList x) (split "\n" s);
|
||||
|
||||
concatStrings = concatStringsSep "";
|
||||
|
||||
replaceStringsRec =
|
||||
from: to: string:
|
||||
# recursively replace occurrences of `from` with `to` within `string`
|
||||
# example:
|
||||
# replaceStringRec "--" "-" "hello-----world"
|
||||
# => "hello-world"
|
||||
let
|
||||
replaced = replaceStrings [ from ] [ to ] string;
|
||||
in
|
||||
if replaced == string then string else replaceStringsRec from to replaced;
|
||||
|
||||
squash = replaceStringsRec "\n\n\n" "\n\n";
|
||||
|
||||
trim =
|
||||
string:
|
||||
# trim trailing spaces and squash non-leading spaces
|
||||
let
|
||||
trimLine =
|
||||
line:
|
||||
let
|
||||
# separate leading spaces from the rest
|
||||
parts = split "(^ *)" line;
|
||||
spaces = head (elemAt parts 1);
|
||||
rest = elemAt parts 2;
|
||||
# drop trailing spaces
|
||||
body = head (split " *$" rest);
|
||||
in
|
||||
spaces + replaceStringsRec " " " " body;
|
||||
in
|
||||
concatStringsSep "\n" (map trimLine (splitLines string));
|
||||
|
||||
# FIXME: O(n^2)
|
||||
unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [ ];
|
||||
|
||||
nameValuePair = name: value: { inherit name value; };
|
||||
|
||||
filterAttrs =
|
||||
pred: set:
|
||||
listToAttrs (
|
||||
concatMap (
|
||||
name:
|
||||
let
|
||||
v = set.${name};
|
||||
in
|
||||
if pred name v then [ (nameValuePair name v) ] else [ ]
|
||||
) (attrNames set)
|
||||
);
|
||||
|
||||
optionalString = cond: string: if cond then string else "";
|
||||
|
||||
showSetting =
|
||||
{ inlineHTML }:
|
||||
name:
|
||||
{
|
||||
description,
|
||||
documentDefault,
|
||||
defaultValue,
|
||||
aliases,
|
||||
value,
|
||||
experimentalFeature,
|
||||
}:
|
||||
let
|
||||
result = squash ''
|
||||
- ${
|
||||
if inlineHTML then ''<span id="conf-${name}">[`${name}`](#conf-${name})</span>'' else ''`${name}`''
|
||||
}
|
||||
|
||||
${indent " " body}
|
||||
'';
|
||||
|
||||
experimentalFeatureNote = optionalString (experimentalFeature != null) ''
|
||||
> **Warning**
|
||||
> This setting is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
To change this setting, you need to make sure the corresponding experimental feature,
|
||||
[`${experimentalFeature}`](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature}),
|
||||
is enabled.
|
||||
For example, include the following in [`nix.conf`](#):
|
||||
|
||||
```
|
||||
extra-experimental-features = ${experimentalFeature}
|
||||
${name} = ...
|
||||
```
|
||||
'';
|
||||
|
||||
# separate body to cleanly handle indentation
|
||||
body = ''
|
||||
${description}
|
||||
|
||||
${experimentalFeatureNote}
|
||||
|
||||
**Default:** ${showDefault documentDefault defaultValue}
|
||||
|
||||
${showAliases aliases}
|
||||
'';
|
||||
|
||||
showDefault =
|
||||
documentDefault: defaultValue:
|
||||
if documentDefault then
|
||||
# a StringMap value type is specified as a string, but
|
||||
# this shows the value type. The empty stringmap is `null` in
|
||||
# JSON, but that converts to `{ }` here.
|
||||
if defaultValue == "" || defaultValue == [ ] || isAttrs defaultValue then
|
||||
"*empty*"
|
||||
else if isBool defaultValue then
|
||||
if defaultValue then "`true`" else "`false`"
|
||||
else
|
||||
"`${toString defaultValue}`"
|
||||
else
|
||||
"*machine-specific*";
|
||||
|
||||
showAliases =
|
||||
aliases:
|
||||
optionalString (aliases != [ ])
|
||||
"**Deprecated alias:** ${(concatStringsSep ", " (map (s: "`${s}`") aliases))}";
|
||||
in
|
||||
result;
|
||||
|
||||
indent =
|
||||
prefix: s: concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s));
|
||||
|
||||
showSettings =
|
||||
args: settingsInfo: concatStrings (attrValues (mapAttrs (showSetting args) settingsInfo));
|
||||
in
|
||||
|
||||
inlineHTML: commandDump:
|
||||
|
||||
+6
-61
@@ -15,56 +15,6 @@ nix_eval_for_docs_common = nix_for_docs + [
|
||||
]
|
||||
nix_eval_for_docs = nix_eval_for_docs_common + '--raw'
|
||||
|
||||
conf_file_json = custom_target(
|
||||
command : nix_for_docs + [ 'show-config', '--json' ],
|
||||
capture : true,
|
||||
output : 'conf-file.json',
|
||||
env : nix_env_for_docs,
|
||||
# FIXME: put the actual lib targets in here? meson have introspection challenge 2024 though.
|
||||
build_always_stale : true,
|
||||
)
|
||||
|
||||
nix_conf_file_md_body = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'(import @INPUT0@).showSettings { inlineHTML = true; } (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
],
|
||||
capture : true,
|
||||
input : [
|
||||
'utils.nix',
|
||||
conf_file_json,
|
||||
],
|
||||
output : 'conf-file.md.body',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
nix_conf_file_md = custom_target(
|
||||
command : [ 'cat', '@INPUT@' ],
|
||||
capture : true,
|
||||
input : [
|
||||
'src/command-ref/conf-file.md',
|
||||
nix_conf_file_md_body,
|
||||
],
|
||||
output : 'conf-file.md',
|
||||
)
|
||||
|
||||
nix_exp_features_json = custom_target(
|
||||
command : [ nix, '__dump-xp-features' ],
|
||||
capture : true,
|
||||
output : 'xp-features.json',
|
||||
# FIXME: put the actual lib targets in here? meson have introspection challenge 2024 though.
|
||||
build_always_stale : true,
|
||||
)
|
||||
|
||||
language_json = custom_target(
|
||||
command: [nix, '__dump-language'],
|
||||
output : 'language.json',
|
||||
capture : true,
|
||||
env : nix_env_for_docs,
|
||||
# FIXME: put the actual lib targets in here? meson have introspection challenge 2024 though.
|
||||
build_always_stale : true,
|
||||
)
|
||||
|
||||
nix3_cli_json = custom_target(
|
||||
command : [ nix, '__dump-cli' ],
|
||||
capture : true,
|
||||
@@ -78,12 +28,8 @@ generate_manual_deps = files(
|
||||
'generate-deps.py',
|
||||
)
|
||||
|
||||
# Generates builtins.md and builtin-constants.md.
|
||||
subdir('src/language')
|
||||
# Generates new-cli pages, {experimental,deprecated}-features-shortlist.md, and conf-file.md.
|
||||
# Generates new-cli pages and conf-file.md.
|
||||
subdir('src/command-ref')
|
||||
# Generates {experimental,deprecated}-feature-descriptions.md.
|
||||
subdir('src/contributing')
|
||||
# Generates rl-next-generated.md.
|
||||
subdir('src/release-notes')
|
||||
|
||||
@@ -126,20 +72,19 @@ manual = custom_target(
|
||||
'manual',
|
||||
'markdown',
|
||||
],
|
||||
install : true,
|
||||
install_dir : [
|
||||
datadir / 'doc/nix',
|
||||
false,
|
||||
],
|
||||
depfile : 'manual.d',
|
||||
env : {
|
||||
'RUST_LOG': 'info',
|
||||
'MDBOOK_SUBSTITUTE_SEARCH': meson.current_build_dir() / 'src',
|
||||
},
|
||||
)
|
||||
manual_html = manual[0]
|
||||
manual_md = manual[1]
|
||||
|
||||
install_subdir(
|
||||
manual_html.full_path(),
|
||||
install_dir : datadir / 'doc/nix',
|
||||
)
|
||||
|
||||
nix_nested_manpages = [
|
||||
[ 'nix-env',
|
||||
[
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
synopsis: "Build failures caused by `allowSubstitutes = false` while being the wrong system now produce a decent error"
|
||||
issues: [fj#484]
|
||||
cls: [1841]
|
||||
category: Fixes
|
||||
credits: jade
|
||||
---
|
||||
|
||||
Nix allows derivations to set `allowSubstitutes = false` in order to force them to be built locally without querying substituters for them.
|
||||
This is useful for derivations that are very fast to build (especially if they produce large output).
|
||||
However, this can shoot you in the foot if the derivation *has* to be substituted such as if the derivation is for another architecture, which is what `--always-allow-substitutes` is for.
|
||||
|
||||
Perhaps such derivations that are known to be impossible to build locally should ignore `allowSubstitutes` (irrespective of remote builders) in the future, but this at least reports the failure and solution directly.
|
||||
|
||||
```
|
||||
$ nix build -f fail.nix
|
||||
error: a 'unicornsandrainbows-linux' with features {} is required to build '/nix/store/...-meow.drv', but I am a 'x86_64-linux' with features {...}
|
||||
|
||||
Hint: the failing derivation has allowSubstitutes set to false, forcing it to be built rather than substituted.
|
||||
Passing --always-allow-substitutes to force substitution may resolve this failure if the path is available in a substituter.
|
||||
```
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
synopsis: Deprecated language features
|
||||
issues: [fj#437]
|
||||
cls: [1785, 1736, 1735, 1744]
|
||||
category: Breaking Changes
|
||||
credits: [piegames, horrors]
|
||||
---
|
||||
|
||||
A system for deprecation (and then the planned removal) of undesired language features has been put into place.
|
||||
It is controlled via feature flags much like experimental features, except that the deprecations are enabled default,
|
||||
and can be disabled via the flags for backwards compatibility (opt-out with `--extra-deprecated-features` or the Nix configuration file).
|
||||
|
||||
- `url-literals`: **URL literals** have long been obsolete and discouraged of use, and now they are officially deprecated.
|
||||
This means that all URLs must be properly put within quotes like all other strings.
|
||||
- `rec-set-overrides`: **__overrides** is an old arcane syntax which has not been in use for more than a decade.
|
||||
It is soft-deprecated with a warning only, with the plan to turn that into an error in a future release.
|
||||
- `ancient-let`: **The old `let` syntax** (`let { body = …; … }`) is soft-deprecated with a warning as well. Use the regular `let … in` instead.
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
synopsis: HTTP proxy environment variables are now respected for S3 binary cache stores
|
||||
issues: [fj#433]
|
||||
cls: [1788]
|
||||
category: Fixes
|
||||
credits: jade
|
||||
---
|
||||
|
||||
Due to "legacy reasons" (according to the AWS C++ SDK docs), the AWS SDK ignores system proxy configuration by default.
|
||||
We turned it back on.
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
synopsis: Relative and tilde paths in configuration
|
||||
issues: [fj#482]
|
||||
cls: [1851, 1863, 1864]
|
||||
category: Features
|
||||
credits: [9999years]
|
||||
---
|
||||
|
||||
[Configuration settings](@docroot@/command-ref/conf-file.md) can now refer to
|
||||
files with paths relative to the file they're written in or relative to your
|
||||
home directory (with `~/`).
|
||||
|
||||
This makes settings like
|
||||
[`repl-overlays`](@docroot@/command-ref/conf-file.md#conf-repl-overlays) and
|
||||
[`secret-key-files`](@docroot@/command-ref/conf-file.md#conf-repl-overlays)
|
||||
much easier to set, especially if you'd like to refer to files in an existing
|
||||
dotfiles repo cloned into your home directory.
|
||||
|
||||
If you put `repl-overlays = repl.nix` in your `~/.config/nix/nix.conf`, it'll
|
||||
load `~/.config/nix/repl.nix`. Similarly, you can set `repl-overlays =
|
||||
~/.dotfiles/repl.nix` to load a file relative to your home directory.
|
||||
|
||||
Configuration files can also
|
||||
[`include`](@docroot@/command-ref/conf-file.md#file-format) paths relative to
|
||||
your home directory.
|
||||
|
||||
Only user configuration files (like `$XDG_CONFIG_HOME/nix/nix.conf` or the
|
||||
files listed in `$NIX_USER_CONF_FILES`) can use tilde paths relative to your
|
||||
home directory. Configuration listed in the `$NIX_CONFIG` environment variable
|
||||
may not use relative paths.
|
||||
@@ -198,6 +198,7 @@
|
||||
- [Release Notes](release-notes/release-notes.md)
|
||||
- [Upcoming release](release-notes/rl-next.md)
|
||||
<!-- RELENG-AUTO-INSERTION-MARKER (see releng/release_notes.py) -->
|
||||
- [Lix 2.92 (2025-01-18)](release-notes/rl-2.92.md)
|
||||
- [Lix 2.91 (2024-08-12)](release-notes/rl-2.91.md)
|
||||
- [Lix 2.90 (2024-07-10)](release-notes/rl-2.90.md)
|
||||
- [Nix 2.18 (2023-09-20)](release-notes/rl-2.18.md)
|
||||
|
||||
@@ -34,9 +34,15 @@ keep-outputs = true # Nice for developers
|
||||
keep-derivations = true # Idem
|
||||
```
|
||||
|
||||
Other files can be included with a line like `include <path>`, where `<path>` is interpreted relative to the current configuration file.
|
||||
Other files can be included with a line like `include <path>`.
|
||||
A missing file is an error unless `!include` is used instead.
|
||||
|
||||
Paths in `include`s and option values are interpreted relative to the current configuration file.
|
||||
In user configuration files, paths starting with `~/` are tilde expanded (by replacing the tilde by the value of `$HOME`).
|
||||
|
||||
Only user configuration files (like `$XDG_CONFIG_HOME/nix/nix.conf` or the files listed in `$NIX_USER_CONF_FILES`) can use tilde paths relative to your home directory.
|
||||
Configuration listed in the `$NIX_CONFIG` environment variable may not use relative paths.
|
||||
|
||||
A configuration setting usually overrides any previous value.
|
||||
However, for settings that take a list of items, you can prefix the name of the setting by `extra-` to *append* to the previous value.
|
||||
|
||||
|
||||
@@ -1,37 +1,3 @@
|
||||
experimental_features_shortlist_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ "experimental" "xp" (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
],
|
||||
input : [
|
||||
'../../generate-features-shortlist.nix',
|
||||
nix_exp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
output : 'experimental-features-shortlist.md',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
dp_features_json = custom_target(
|
||||
command : [nix, '__dump-dp-features'],
|
||||
capture : true,
|
||||
output : 'dp-features.json',
|
||||
)
|
||||
|
||||
deprecated_features_shortlist_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ "deprecated" "dp" (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
],
|
||||
input : [
|
||||
'../../generate-features-shortlist.nix',
|
||||
dp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
output : 'deprecated-features-shortlist.md',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
# Intermediate step for manpage generation.
|
||||
# This splorks the output of generate-manpage.nix as JSON,
|
||||
# which gets written as a directory tree below.
|
||||
@@ -65,17 +31,23 @@ nix3_cli_files = custom_target(
|
||||
|
||||
conf_file_md = custom_target(
|
||||
command : [
|
||||
nix_eval_for_docs,
|
||||
'--expr',
|
||||
'(import @INPUT0@).showSettings { inlineHTML = true; } (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
python.full_path(),
|
||||
'@SOURCE_ROOT@/lix/code-generation/build_settings.py',
|
||||
'--kernel', host_machine.system(),
|
||||
'--docs', '@OUTPUT@',
|
||||
'--experimental-features', '@SOURCE_ROOT@/lix/libutil/experimental-features',
|
||||
'@INPUT@',
|
||||
],
|
||||
capture : true,
|
||||
input : [
|
||||
'../../utils.nix',
|
||||
conf_file_json,
|
||||
experimental_features_shortlist_md,
|
||||
deprecated_features_shortlist_md,
|
||||
libexpr_setting_definitions,
|
||||
libfetchers_setting_definitions,
|
||||
file_transfer_setting_definitions,
|
||||
libstore_setting_definitions,
|
||||
archive_setting_definitions,
|
||||
feature_setting_definitions,
|
||||
logging_setting_definitions,
|
||||
daemon_setting_definitions,
|
||||
develop_settings_definitions,
|
||||
],
|
||||
output : 'conf-file.md',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
@@ -34,4 +34,4 @@ However, we do not live in such an ideal world, and currently this goal is so fa
|
||||
|
||||
# Currently available deprecated features
|
||||
|
||||
{{#include @generated@/contributing/deprecated-feature-descriptions.md}}
|
||||
{{#include @generated@/../../../lix/libutil/deprecated-feature-descriptions.md}}
|
||||
|
||||
@@ -99,4 +99,4 @@ This means that experimental features and RFCs are orthogonal mechanisms, and ca
|
||||
|
||||
# Currently available experimental features
|
||||
|
||||
{{#include @generated@/contributing/experimental-feature-descriptions.md}}
|
||||
{{#include @generated@/../../../lix/libutil/experimental-feature-descriptions.md}}
|
||||
|
||||
@@ -102,14 +102,14 @@ $ meson compile -C build nixexpr
|
||||
All targets may be addressed as their output, relative to the build directory, e.g.:
|
||||
|
||||
```bash
|
||||
$ meson compile -C build src/libexpr/liblixexpr.so
|
||||
$ meson compile -C build lix/libexpr/liblixexpr.so
|
||||
```
|
||||
|
||||
But Meson does not consider intermediate files like object files targets.
|
||||
To build a specific object file, use Ninja directly and specify the output file relative to the build directory:
|
||||
|
||||
```bash
|
||||
$ ninja -C build src/libexpr/liblixexpr.so.p/nixexpr.cc.o
|
||||
$ ninja -C build lix/libexpr/liblixexpr.so.p/nixexpr.cc.o
|
||||
```
|
||||
|
||||
To inspect the canonical source of truth on what the state of the buildsystem configuration is, use:
|
||||
@@ -137,7 +137,7 @@ You can also build Lix for one of the [supported platforms](#platforms).
|
||||
|
||||
Lix can be built for various platforms, as specified in [`flake.nix`]:
|
||||
|
||||
[`flake.nix`]: https://git.lix.systems/lix-project/lix/src/branch/main/flake.nix
|
||||
[`flake.nix`]: https://git.lix.systems/lix-project/lix/lix/branch/main/flake.nix
|
||||
|
||||
- `x86_64-linux`
|
||||
- `x86_64-darwin`
|
||||
@@ -399,3 +399,76 @@ The following properties are supported:
|
||||
|
||||
Releases have a precomputed `rl-MAJOR.MINOR.md`, and no `rl-next.md`.
|
||||
Set `buildUnreleasedNotes = true;` in `flake.nix` to build the release notes on the fly.
|
||||
|
||||
## Adding experimental or deprecated features, global settings, or builtins
|
||||
|
||||
Experimental and deprecated features, global settings, and builtins are generally referenced both in the code and in the documentation.
|
||||
To prevent duplication or divergence, they are defined in data files, and a script generates the necessary glue.
|
||||
The data file format is similar to the release notes: it consists of a YAML metadata header, followed by the documentation in Markdown format.
|
||||
|
||||
### Experimental or deprecated features
|
||||
|
||||
Experimental and deprecated features support the following metadata properties:
|
||||
* `name` (required): user-facing name of the feature, to be used in `nix.conf` options and on the command line.
|
||||
This should also be the stem of the file name (with extension `md`).
|
||||
* `internalName` (required): identifier used to refer to the feature inside the C++ code.
|
||||
|
||||
Experimental feature data files should live in `lix/libutil/experimental-features`, and deprecated features in `lix/libutil/deprecated-features`.
|
||||
They must be listed in the `experimental_feature_definitions` or `deprecated_feature_definitions` lists in `lix/libutil/meson.build` respectively to be considered by the build system.
|
||||
|
||||
### Global settings
|
||||
|
||||
Global settings support the following metadata properties:
|
||||
* `name` (required): user-facing name of the setting, to be used as key in `nix.conf` and in the `--option` command line argument.
|
||||
* `internalName` (required): identifier used to refer to the setting inside the C++ code.
|
||||
* `platforms` (optional): a list specifying the platforms on which this setting is available.
|
||||
If not specified, it is available on all platforms.
|
||||
Valid platform names are `darwin`, `linux`.
|
||||
* `type` (optional): C++ type of the setting value.
|
||||
This specifies the setting object type as `Setting<T>`; if more control is required, use `settingType` instead.
|
||||
* `settingType` (required if `type` is not specified): C++ type of the setting object.
|
||||
* `default` (optional): default value of the setting.
|
||||
`null`, truth values, integers, strings and lists are supported as long as the correct YAML type is used, `type` is not taken into account).
|
||||
Other types, machine-dependent values or non-standard representations must be handled using `defaultExpr` and `defaultText` instead.
|
||||
* `defaultExpr` (required if `default` is not specified): a string containing the C++ expression representing the default value.
|
||||
* `defaultText` (required if `default` is not specified): a string containing the Markdown expression representing the default value in the documentation.
|
||||
Literal values are conventionally surrounded by backticks, and a system-dependent value is signaled by `*machine-specific*`.
|
||||
* `aliases` (optional): a list of secondary user-facing names under which the setting is available.
|
||||
Defaults to empty if not specified.
|
||||
* `experimentalFeature` (optional): the user-facing name of the experimental feature which needs to be enabled to change the setting.
|
||||
If not specified, no experimental feature is required.
|
||||
* `deprecated` (optional): whether the setting is deprecated and shown as such in the documentation for `nix.conf`.
|
||||
Defaults to false if not specified.
|
||||
|
||||
Settings are not collected in a single place in the source tree, so an appropriate place needs to be found for the setting to live.
|
||||
Look for related setting definition files under second-level subdirectories of `lix` whose name includes `settings`.
|
||||
Then add the new file there, and don't forget to register it in the appropriate `meson.build` file.
|
||||
|
||||
### Builtin functions
|
||||
|
||||
The following metadata properties are supported for builtin functions:
|
||||
* `name` (required): the language-facing name (as a member of the `builtins` attribute set) of the function.
|
||||
* `implementation` (optional): a C++ expression specifying the implementation of the builtin.
|
||||
It must be a function of signature `void(EvalState &, PosIdx, Value * *, Value &)`.
|
||||
If not specified, defaults to `prim_${name}`.
|
||||
* `renameInGlobalScope` (optional): whether the definiton should be "hidden" in the global scope by prefixing its name with two underscores.
|
||||
If not specified, defaults to `true`.
|
||||
* `args` (required): list containing the names of the arguments, as shown in the documentation.
|
||||
All arguments must be listed here since the function arity is derived as the length of this list.
|
||||
* `experimental_feature` (optional): the user-facing name of the experimental feature which needs to be enabled for the bultin function to be available.
|
||||
If not specified, no experimental feature is required.
|
||||
|
||||
New builtin function definition files must be added to `lix/libexpr/builtins` and registered in the `builtin_definitions` list in `lix/libexpr/meson.build`.
|
||||
|
||||
### Builtin constants
|
||||
The following metadata properties are supported for builtin constants:
|
||||
* `name` (required): the language-facing name (as a member of the `builtins` attribute set) of the constant.
|
||||
* `type` (required): the Nix language type of the constant; the C++ type is automatically derived.
|
||||
* `constructorArgs` (optional): list of strings containing C++ expressions passed as arguments to the appropriate `Value` constructor.
|
||||
If the value computation is more complex, `implementation` can be used instead.
|
||||
* `implementation` (required if `constructorArgs` is not specified): string containing a C++ expressing computing the value of the constant.
|
||||
* `impure` (optional): whether the constant is considered impure.
|
||||
Impure constants are not available when pure evaluation mode is activated.
|
||||
Defaults to `false` when not specified.
|
||||
|
||||
New builtin constant definition files must be added to `lix/libexpr/builtin-constants` and registered in the `builtin_constant_definitions` list in `lix/libexpr/meson.build`.
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# Intermediate step for experimental-feature-descriptions.md.
|
||||
# This splorks the output of generate-xp-features.nix as JSON,
|
||||
# which gets written as a directory tree below.
|
||||
experimental_feature_descriptions_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ "experimental" "xp" (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
],
|
||||
input : [
|
||||
'../../generate-features.nix',
|
||||
nix_exp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
output : 'experimental-feature-descriptions.md',
|
||||
)
|
||||
|
||||
deprecated_feature_descriptions_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ "deprecated" "dp" (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
||||
],
|
||||
input : [
|
||||
'../../generate-features.nix',
|
||||
dp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
output : 'deprecated-feature-descriptions.md',
|
||||
)
|
||||
@@ -13,7 +13,7 @@ The unit tests are defined using the [googletest] and [rapidcheck] frameworks.
|
||||
>
|
||||
> ```
|
||||
> …
|
||||
> ├── src
|
||||
> ├── lix
|
||||
> │ ├── libexpr
|
||||
> │ │ ├── …
|
||||
> │ │ ├── value
|
||||
@@ -46,10 +46,10 @@ The unit tests are defined using the [googletest] and [rapidcheck] frameworks.
|
||||
> … … … … … …
|
||||
> ```
|
||||
|
||||
The unit tests for each Lix library (`liblixexpr`, `liblixstore`, etc..) live inside a directory `src/${library_shortname}/tests` within the directory for the library (`src/${library_shortname}`).
|
||||
The unit tests for each Lix library (`liblixexpr`, `liblixstore`, etc..) live inside a directory `lix/${library_shortname}/tests` within the directory for the library (`lix/${library_shortname}`).
|
||||
|
||||
The data is in `tests/unit/LIBNAME/data/LIBNAME`, with one subdir per library, with the same name as where the code goes.
|
||||
For example, `liblixstore` code is in `src/libstore`, and its test data is in `tests/unit/libstore/data/libstore`.
|
||||
For example, `liblixstore` code is in `lix/libstore`, and its test data is in `tests/unit/libstore/data/libstore`.
|
||||
The path to the unit test data directory is passed to the unit test executable with the environment variable `_NIX_TEST_UNIT_DATA`.
|
||||
|
||||
### Running tests
|
||||
@@ -345,7 +345,7 @@ rg '(?:[^A-Za-z]|^)(_[A-Z][^-\[ }/:");$(]+)' -r '$1' --no-filename --only-matchi
|
||||
rg '\$\{?([A-Z][^-\[ }/:");]+)' -r '$1' --no-filename --only-matching tests | sort -u > vars.txt
|
||||
```
|
||||
|
||||
I grepped `src/` for `get[eE]nv\("` to find the mentions in Lix code.
|
||||
I grepped `lix/` for `get[eE]nv\("` to find the mentions in Lix code.
|
||||
|
||||
### Used by Lix testing support code
|
||||
|
||||
@@ -361,8 +361,8 @@ I grepped `src/` for `get[eE]nv\("` to find the mentions in Lix code.
|
||||
|
||||
- `_NIX_FORCE_HTTP` - Forces file URIs to be treated as remote ones.
|
||||
|
||||
Used by `src/libfetchers/git.cc`, `src/libstore/http-binary-cache-store.cc`,
|
||||
`src/libstore/local-binary-cache-store.cc`. Seems to be for forcing Git
|
||||
Used by `lix/libfetchers/git.cc`, `lix/libstore/http-binary-cache-store.cc`,
|
||||
`lix/libstore/local-binary-cache-store.cc`. Seems to be for forcing Git
|
||||
clones of `git+file://` URLs, making the HTTP binary
|
||||
cache store accept `file://` URLs (presumably passing them to curl?), and
|
||||
unknown reasons for the local binary cache.
|
||||
@@ -374,7 +374,7 @@ I grepped `src/` for `get[eE]nv\("` to find the mentions in Lix code.
|
||||
`structuredAttrs` documentation.
|
||||
- `NIX_BIN_DIR`, `NIX_STORE_DIR` (or its inconsistently-used old alias `NIX_STORE`), `NIX_DATA_DIR`,
|
||||
`NIX_LOG_DIR`, `NIX_LOG_DIR`, `NIX_STATE_DIR`, `NIX_CONF_DIR` -
|
||||
Overrides compile-time configuration of various locations used by Lix. See `src/libstore/globals.cc`.
|
||||
Overrides compile-time configuration of various locations used by Lix. See `lix/libstore/globals.cc`.
|
||||
|
||||
**Expected value**: a directory
|
||||
- `NIX_DAEMON_SOCKET_PATH` (optional) - Overrides the daemon socket path from `$NIX_STATE_DIR/daemon-socket/socket`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installing a Binary Distribution
|
||||
|
||||
See https://lix.systems/install/ for more details.
|
||||
See <https://lix.systems/install/> for more details.
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ These constants are built into the Nix language evaluator:
|
||||
|
||||
<dl>
|
||||
|
||||
{{#include @generated@/language/builtin-constants.md}}
|
||||
{{#include @generated@/../../../lix/libexpr/builtin-constants.md}}
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
@@ -15,6 +15,6 @@ For convenience, some built-ins can be accessed directly:
|
||||
<dd><p><var>derivation</var> is described in
|
||||
<a href="derivations.md">its own section</a>.</p></dd>
|
||||
|
||||
{{#include @generated@/language/builtins.md}}
|
||||
{{#include @generated@/../../../lix/libexpr/builtins.md}}
|
||||
|
||||
</dl>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
builtins_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ (builtins.fromJSON (builtins.readFile @INPUT1@)).builtins',
|
||||
],
|
||||
capture : true,
|
||||
input : [
|
||||
'../../generate-builtins.nix',
|
||||
language_json,
|
||||
],
|
||||
output : 'builtins.md',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
builtin_constants_md = custom_target(
|
||||
command : nix_eval_for_docs + [
|
||||
'--expr',
|
||||
'import @INPUT0@ (builtins.fromJSON (builtins.readFile @INPUT1@)).constants',
|
||||
],
|
||||
capture : true,
|
||||
input : [
|
||||
'../../generate-builtin-constants.nix',
|
||||
language_json,
|
||||
],
|
||||
output : 'builtin-constants.md',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
@@ -26,8 +26,8 @@
|
||||
| Logical conjunction (`AND`) | *bool* `&&` *bool* | left | 12 |
|
||||
| Logical disjunction (`OR`) | *bool* <code>\|\|</code> *bool* | left | 13 |
|
||||
| [Logical implication] | *bool* `->` *bool* | none | 14 |
|
||||
| \[Experimental\] [Function piping] | *expr* |> *func* | left | 15 |
|
||||
| \[Experimental\] [Function piping] | *expr* <| *func* | right | 16 |
|
||||
| \[Experimental\] [Function piping] | *expr* `\|>` *func* | left | 15 |
|
||||
| \[Experimental\] [Function piping] | *expr* `<\|` *func* | right | 16 |
|
||||
|
||||
[string]: ./values.md#type-string
|
||||
[path]: ./values.md#type-path
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
# Lix 2.92 "Bombe glacée" (2025-01-18)
|
||||
|
||||
|
||||
# Lix 2.92.0 (2025-01-18)
|
||||
|
||||
## Breaking Changes
|
||||
- Deprecated language features [fj#437](https://git.lix.systems/lix-project/lix/issues/437) [#861](https://github.com/NixOS/nix/issues/861) [cl/1785](https://gerrit.lix.systems/c/lix/+/1785) [cl/1736](https://gerrit.lix.systems/c/lix/+/1736) [cl/1735](https://gerrit.lix.systems/c/lix/+/1735) [cl/1744](https://gerrit.lix.systems/c/lix/+/1744) [cl/2206](https://gerrit.lix.systems/c/lix/+/2206)
|
||||
|
||||
A system for deprecation (and then the planned removal) of undesired language features has been put into place.
|
||||
It is controlled via feature flags much like experimental features, except that the deprecations are enabled default,
|
||||
and can be disabled via the flags for backwards compatibility (opt-out with `--extra-deprecated-features` or the Nix configuration file).
|
||||
|
||||
- `url-literals`: **URL literals** have long been obsolete and discouraged of use, and now they are officially deprecated.
|
||||
This means that all URLs must be properly put within quotes like all other strings.
|
||||
- `rec-set-overrides`: **__overrides** is an old arcane syntax which has not been in use for more than a decade.
|
||||
It is soft-deprecated with a warning only, with the plan to turn that into an error in a future release.
|
||||
- `ancient-let`: **The old `let` syntax** (`let { body = …; … }`) is soft-deprecated with a warning as well. Use the regular `let … in` instead.
|
||||
- `shadow-internal-symbols`: Arithmetic expressions like `5 - 3` internally expand to `__sub 5 3`, where `__sub` maps to a subtraction builtin. Shadowing such a symbols would affect the evaluation of such operations, but in a very inconsistent way, and is therefore deprecated now. **Affected symbols are:** `__sub`, `__mul`, `__div` and `__lessThan`. Note that these symbols may still be used as variable names as long as they do not shadow internal operations, so e.g. `let __sub = x: y: x + y; in __sub 3 5` remains valid code.
|
||||
- **Call to action:** If you have any use cases or workflows that depend on being able to override the `__nixPath` and `__findFile` symbols, please reach out to us. We want to eventually deprecate overriding these as well, and need input on how to design a better alternative.
|
||||
|
||||
Many thanks to [piegames](https://git.lix.systems/piegames) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
- transfers no longer allow arbitrary url schemas [cl/2106](https://gerrit.lix.systems/c/lix/+/2106)
|
||||
|
||||
Lix no longer allows transfers using arbitrary url schemas. Only `http://`, `https://`, `ftp://`, `ftps://`, and `file://` urls are supported going forward. This affects `builtins.fetchurl`, `<nix/fetchurl.nix>`, transfers to and from binary caches, and all other uses of the internal file transfer code. Flake inputs using multi-protocol schemas (e.g. `git+ssh`) are not affected as those use external utilities to transfer data.
|
||||
|
||||
The `s3://` scheme is not affected at all by this change and continues to work if S3 support is built into Lix.
|
||||
|
||||
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
- Removing the `.` default argument passed to the `nix fmt` formatter [#11438](https://github.com/NixOS/nix/pull/11438) [cl/1902](https://gerrit.lix.systems/c/lix/+/1902)
|
||||
|
||||
The underlying formatter no longer receives the ". " default argument when `nix fmt` is called with no arguments.
|
||||
|
||||
This change was necessary as the formatter wasn't able to distinguish between
|
||||
a user wanting to format the current folder with `nix fmt .` or the generic
|
||||
`nix fmt`.
|
||||
|
||||
The default behaviour is now the responsibility of the formatter itself, and
|
||||
allows tools such as treefmt to format the whole tree instead of only the
|
||||
current directory and below.
|
||||
|
||||
This may cause issues with some formatters: nixfmt, nixpkgs-fmt and alejandra currently format stdin when no arguments are passed.
|
||||
|
||||
Here is a small wrapper example that will restore the previous behaviour for such a formatter:
|
||||
|
||||
```nix
|
||||
{
|
||||
outputs = { self, nixpkgs, systems }:
|
||||
let
|
||||
eachSystem = nixpkgs.lib.genAttrs (import systems) (system: nixpkgs.legacyPackages.${system});
|
||||
in
|
||||
{
|
||||
formatter = eachSystem (pkgs:
|
||||
pkgs.writeShellScriptBin "formatter" ''
|
||||
if [[ $# = 0 ]]; set -- .; fi
|
||||
exec "${pkgs.nixfmt-rfc-style}/bin/nixfmt "$@"
|
||||
'');
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Many thanks to [zimbatm](https://github.com/zimbatm) for this.
|
||||
|
||||
## Features
|
||||
- Relative and tilde paths in configuration [fj#482](https://git.lix.systems/lix-project/lix/issues/482) [cl/1851](https://gerrit.lix.systems/c/lix/+/1851) [cl/1863](https://gerrit.lix.systems/c/lix/+/1863) [cl/1864](https://gerrit.lix.systems/c/lix/+/1864)
|
||||
|
||||
[Configuration settings](@docroot@/command-ref/conf-file.md) can now refer to
|
||||
files with paths relative to the file they're written in or relative to your
|
||||
home directory (with `~/`).
|
||||
|
||||
This makes settings like
|
||||
[`repl-overlays`](@docroot@/command-ref/conf-file.md#conf-repl-overlays) and
|
||||
[`secret-key-files`](@docroot@/command-ref/conf-file.md#conf-repl-overlays)
|
||||
much easier to set, especially if you'd like to refer to files in an existing
|
||||
dotfiles repo cloned into your home directory.
|
||||
|
||||
If you put `repl-overlays = repl.nix` in your `~/.config/nix/nix.conf`, it'll
|
||||
load `~/.config/nix/repl.nix`. Similarly, you can set `repl-overlays =
|
||||
~/.dotfiles/repl.nix` to load a file relative to your home directory.
|
||||
|
||||
Configuration files can also
|
||||
[`include`](@docroot@/command-ref/conf-file.md#file-format) paths relative to
|
||||
your home directory.
|
||||
|
||||
Only user configuration files (like `$XDG_CONFIG_HOME/nix/nix.conf` or the
|
||||
files listed in `$NIX_USER_CONF_FILES`) can use tilde paths relative to your
|
||||
home directory. Configuration listed in the `$NIX_CONFIG` environment variable
|
||||
may not use relative paths.
|
||||
|
||||
Many thanks to [wiggles](https://git.lix.systems/rbt) for this.
|
||||
|
||||
## Improvements
|
||||
- Improved error messages for bad attr paths [cl/2277](https://gerrit.lix.systems/c/lix/+/2277) [cl/2280](https://gerrit.lix.systems/c/lix/+/2280)
|
||||
|
||||
Lix now includes much more detail when a bad attribute path is accessed at the command line:
|
||||
|
||||
```
|
||||
» nix eval -f '<nixpkgs>' lixVersions.lix_2_92
|
||||
error: attribute 'lix_2_92' in selection path 'lixVersions.lix_2_92' not found
|
||||
Did you mean one of lix_2_90 or lix_2_91?
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
» nix eval --impure -f '<nixpkgs>' lixVersions.lix_2_92
|
||||
error: attribute 'lix_2_92' in selection path 'lixVersions.lix_2_92' not found inside path 'lixVersions', whose contents are: { __unfix__ = «lambda @ /nix/store/hfz1qqd0z8amlgn8qwich1dvkmldik36-source/lib/fixed-points.nix:
|
||||
447:7»; buildLix = «thunk»; extend = «thunk»; latest = «thunk»; lix_2_90 = «thunk»; lix_2_91 = «thunk»; override = «thunk»; overrideDerivation = «thunk»; recurseForDerivations = true; stable = «thunk»; }
|
||||
Did you mean one of lix_2_90 or lix_2_91?
|
||||
```
|
||||
|
||||
This should avoid some unnecessary trips to the repl or to the debugger by giving some information about the value being selected on that was unexpected.
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- Small error message improvements [cl/2185](https://gerrit.lix.systems/c/lix/+/2185) [cl/2187](https://gerrit.lix.systems/c/lix/+/2187)
|
||||
|
||||
When an attribute selection fails, the error message now correctly points to the attribute in the chain that failed instead of at the beginning of the entire chain.
|
||||
```diff
|
||||
error: attribute 'x' missing
|
||||
- at /pwd/lang/eval-fail-remove.nix:4:3:
|
||||
+ at /pwd/lang/eval-fail-remove.nix:4:29:
|
||||
3| in
|
||||
4| (removeAttrs attrs ["x"]).x
|
||||
- | ^
|
||||
+ | ^
|
||||
5|
|
||||
```
|
||||
|
||||
Failed asserts don't print the failed assertion expression anymore in the error message. That code was buggy and the information was redundant anyways, given that the error position already more accurately shows what exactly failed.
|
||||
|
||||
Many thanks to [piegames](https://git.lix.systems/piegames) for this.
|
||||
- Improvements to interactive flake config [cl/2066](https://gerrit.lix.systems/c/lix/+/2066)
|
||||
|
||||
If `accept-flake-config` is set to `ask` and a `flake.nix` defines `nixConfig`,
|
||||
Lix will ask on the CLI which of these settings should be used for the command.
|
||||
|
||||
Now, it's possible to answer with `N` (as opposed to `n` to only reject the setting
|
||||
that is asked for) to reject _all untrusted_ entries from the flake's `nixConf`
|
||||
section.
|
||||
|
||||
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
|
||||
- `nix --version` now shows details about the installation by default [fj#620](https://git.lix.systems/lix-project/lix/issues/620) [cl/2365](https://gerrit.lix.systems/c/lix/+/2365)
|
||||
|
||||
This happened with `nix-env --version` by default, but due to [oddities around the nix3 CLI's verbosity](https://gerrit.lix.systems/c/lix/+/1370), it used to be `nix --verbose --version`.
|
||||
|
||||
No longer:
|
||||
|
||||
```
|
||||
$ nix --version
|
||||
nix (Lix, like Nix) 2.92.0-dev-pre20250117-0d14c2b
|
||||
System type: x86_64-linux
|
||||
Additional system types: i686-linux, x86_64-v1-linux, x86_64-v2-linux, x86_64-v3-linux
|
||||
Features: gc, signed-caches
|
||||
System configuration file: /etc/nix/nix.conf
|
||||
User configuration files: /home/jade/.config/nix/nix.conf:/etc/xdg/nix/nix.conf
|
||||
Store directory: /nix/store
|
||||
State directory: /nix/var/nix
|
||||
Data directory: /nix/store/rliimcnqkplrqdgm4z6yqclpr6c32wh6-lix-2.92.0-dev-pre20250117-0d14c2b/share
|
||||
```
|
||||
|
||||
Many thanks to [just1602](https://git.lix.systems/just1602) for this.
|
||||
- `nix repl` correctly tab-completes attribute names that require quotes [cl/1783](https://gerrit.lix.systems/c/lix/+/1783)
|
||||
|
||||
The REPL (`nix repl`) now includes quotes as part of attribute names while completing with `<TAB>`,
|
||||
if necessary. For example, attribute names like `"hello@example.com"` or `"hello world"` would
|
||||
be suggested without quotes, resulting in invalid syntax.
|
||||
|
||||
Many thanks to [ian-h-chamberlain](https://git.lix.systems/ian-h-chamberlain) for this.
|
||||
- Reproducibility check builds now report all differing outputs [cl/2069](https://gerrit.lix.systems/c/lix/+/2069)
|
||||
|
||||
`nix-build --check` allows rerunning the build of an already-built derivation to check that it produces the same output again.
|
||||
|
||||
If a multiple-output derivation with impure behaviour is built with `--check`, only the first output would be shown in the resulting error message (and kept for comparison):
|
||||
|
||||
```
|
||||
error: derivation '/nix/store/4spy3nz1661zm15gkybsy1h5f36aliwx-python3.11-test-1.0.0.drv' may not be deterministic: output '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test
|
||||
-1.0.0-dist' differs from '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist.check'
|
||||
```
|
||||
|
||||
Now, all differing outputs are kept and reported:
|
||||
```
|
||||
error: derivation '4spy3nz1661zm15gkybsy1h5f36aliwx-python3.11-test-1.0.0.drv' may not be deterministic: outputs differ
|
||||
output differs: output '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist' differs from '/nix/store/ccqcp01zg18wp9iadzmzimqzdi3ll08d-python3.11-test-1.0.0-dist.check'
|
||||
output differs: output '/nix/store/yl59v08356i841c560alb0zmk7q16klb-python3.11-test-1.0.0' differs from '/nix/store/yl59v08356i841c560alb0zmk7q16klb-python3.11-test-1.0.0.check'
|
||||
```
|
||||
|
||||
Many thanks to [lheckemann](https://git.lix.systems/lheckemann) for this.
|
||||
- Some Lix crashes now produce reporting instructions and a stack trace, then abort [cl/1854](https://gerrit.lix.systems/c/lix/+/1854)
|
||||
|
||||
Lix, being a C++ program, can crash in a few kinds of ways.
|
||||
It can obviously do a memory access violation, which will generate a core dump and thus be relatively debuggable.
|
||||
But, worse, it could throw an unhandled exception, and, in the past, we would just show the message but not where it comes from, in spite of this always being a bug, since we expect all such errors to be translated to a Lix specific error.
|
||||
Now the latter kind of bug should print reporting instructions, a rudimentary stack trace and (depending on system configuration) generate a core dump.
|
||||
|
||||
Sample output:
|
||||
|
||||
```
|
||||
Lix crashed. This is a bug. We would appreciate if you report it along with what caused it at https://git.lix.systems/lix-project/lix/issues with the following information included:
|
||||
|
||||
Exception: std::runtime_error: test exception
|
||||
Stack trace:
|
||||
0# nix::printStackTrace() in /home/jade/lix/lix3/build/lix/nix/../libutil/liblixutil.so
|
||||
1# 0x000073C9862331F2 in /home/jade/lix/lix3/build/lix/nix/../libmain/liblixmain.so
|
||||
2# 0x000073C985F2E21A in /nix/store/p44qan69linp3ii0xrviypsw2j4qdcp2-gcc-13.2.0-lib/lib/libstdc++.so.6
|
||||
3# 0x000073C985F2E285 in /nix/store/p44qan69linp3ii0xrviypsw2j4qdcp2-gcc-13.2.0-lib/lib/libstdc++.so.6
|
||||
4# nix::handleExceptions(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void ()>) in /home/jade/lix/lix3/build/lix/nix/../libmain/liblixmain.so
|
||||
...
|
||||
```
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- Add a `temp-dir` setting to set the temporary directory location [#7731](https://github.com/NixOS/nix/issues/7731) [#8995](https://github.com/NixOS/nix/issues/8995) [fj#112](https://git.lix.systems/lix-project/lix/issues/112) [fj#253](https://git.lix.systems/lix-project/lix/issues/253) [cl/2103](https://gerrit.lix.systems/c/lix/+/2103)
|
||||
|
||||
[`temp-dir`](@docroot@/command-ref/conf-file.md#conf-temp-dir) can now be set in the Nix
|
||||
configuration to change the temporary directory. This can be used to relocate all temporary files
|
||||
to another filesystem without affecting the `TMPDIR` env var inherited by interactive
|
||||
`nix-shell`/`nix shell` shells or `nix run` commands.
|
||||
|
||||
Also on macOS, the `TMPDIR` env var is no longer unset for interactive shells when pointing
|
||||
to a per-session `/var/folders/` directory.
|
||||
|
||||
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
|
||||
|
||||
## Fixes
|
||||
- Build failures caused by `allowSubstitutes = false` while being the wrong system now produce a decent error [fj#484](https://git.lix.systems/lix-project/lix/issues/484) [cl/1841](https://gerrit.lix.systems/c/lix/+/1841)
|
||||
|
||||
Nix allows derivations to set `allowSubstitutes = false` in order to force them to be built locally without querying substituters for them.
|
||||
This is useful for derivations that are very fast to build (especially if they produce large output).
|
||||
However, this can shoot you in the foot if the derivation *has* to be substituted such as if the derivation is for another architecture, which is what `--always-allow-substitutes` is for.
|
||||
|
||||
Perhaps such derivations that are known to be impossible to build locally should ignore `allowSubstitutes` (irrespective of remote builders) in the future, but this at least reports the failure and solution directly.
|
||||
|
||||
```
|
||||
$ nix build -f fail.nix
|
||||
error: a 'unicornsandrainbows-linux' with features {} is required to build '/nix/store/...-meow.drv', but I am a 'x86_64-linux' with features {...}
|
||||
|
||||
Hint: the failing derivation has allowSubstitutes set to false, forcing it to be built rather than substituted.
|
||||
Passing --always-allow-substitutes to force substitution may resolve this failure if the path is available in a substituter.
|
||||
```
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- `Alt+Left` and `Alt+Right` go back/forwards by words in `nix repl` [fj#501](https://git.lix.systems/lix-project/lix/issues/501) [cl/1883](https://gerrit.lix.systems/c/lix/+/1883)
|
||||
|
||||
`nix repl` now recognizes `Alt+Left` and `Alt+Right` for navigating by words
|
||||
when entering input in `nix repl` on more terminals/platforms.
|
||||
|
||||
Many thanks to [wiggles](https://git.lix.systems/rbt) for this.
|
||||
- Ctrl-C stops Nix commands much more reliably and responsively [#7245](https://github.com/NixOS/nix/issues/7245) [fj#393](https://git.lix.systems/lix-project/lix/issues/393) [#11618](https://github.com/NixOS/nix/pull/11618) [cl/2016](https://gerrit.lix.systems/c/lix/+/2016)
|
||||
|
||||
CTRL-C will now stop Nix commands much more reliably and responsively. While
|
||||
there are still some cases where a Nix command can be slow or unresponsive
|
||||
following a `SIGINT` (please report these as issues!), the vast majority of
|
||||
signals will now cause the Nix command to quit quickly and consistently.
|
||||
|
||||
Many thanks to [Robert Hensing](https://github.com/roberth) and [wiggles](https://git.lix.systems/rbt) for this.
|
||||
- restore backwards-compatibility of `builtins.fetchGit` with Nix 2.3 [#5291](https://github.com/NixOS/nix/issues/5291) [#5128](https://github.com/NixOS/nix/issues/5128)
|
||||
|
||||
Compatibility with `builtins.fetchGit` from Nix 2.3 has been restored as follows:
|
||||
|
||||
* Until now, each `ref` was prefixed with `refs/heads` unless it starts with `refs/` itself.
|
||||
|
||||
Now, this is not done if the `ref` looks like a commit hash.
|
||||
|
||||
* Specifying `builtins.fetchGit { ref = "a-tag"; /* … */ }` was broken because `refs/heads` was appended.
|
||||
|
||||
Now, the fetcher doesn't turn a ref into `refs/heads/ref`, but into `refs/*/ref`. That way,
|
||||
the value in `ref` can be either a tag or a branch.
|
||||
|
||||
* The ref resolution happens the same way as in git:
|
||||
|
||||
* If `refs/ref` exists, it's used.
|
||||
* If a tag `refs/tags/ref` exists, it's used.
|
||||
* If a branch `refs/heads/ref` exists, it's used.
|
||||
|
||||
Many thanks to [ma27](https://git.lix.systems/ma27) for this.
|
||||
- Flakes/restrict-eval no longer allow reading contents of impure paths
|
||||
|
||||
Flakes and `--restrict-eval` now correctly restrict access to paths as intended.
|
||||
In prior versions since at least 2.18, `nix eval --raw .#lol` for the following flake didn't throw an error and acted as if `--impure` was passed.
|
||||
|
||||
Thanks to the person who reported this for telling us about it.
|
||||
This was handled as a low-severity security bug, but is not a violation of the [documented security model](../installation/multi-user.md) as untrusted Nix code should be assumed to have the privileges of the user running the evaluator.
|
||||
To report a security bug, email a report to `security at lix dot systems`.
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {};
|
||||
outputs = {...}: {
|
||||
lol = builtins.readFile "${/etc/passwd}";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
- HTTP proxy environment variables are now respected for S3 binary cache stores [fj#433](https://git.lix.systems/lix-project/lix/issues/433) [cl/1788](https://gerrit.lix.systems/c/lix/+/1788)
|
||||
|
||||
Due to "legacy reasons" (according to the AWS C++ SDK docs), the AWS SDK ignores system proxy configuration by default.
|
||||
We turned it back on.
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- Fix potential store corruption with auto-optimise-store [#7273](https://github.com/NixOS/nix/issues/7273) [cl/2100](https://gerrit.lix.systems/c/lix/+/2100)
|
||||
|
||||
Optimising store paths (and other operations involving temporary files) no longer use `random(3)`
|
||||
to generate filenames. On darwin systems this was observed to potentially cause store corruption
|
||||
when using [`auto-optimise-store`](@docroot@/command-ref/conf-file.md#conf-auto-optimise-store),
|
||||
though this corruption was possible on any system whose `random(3)` does not have locking around
|
||||
the global state.
|
||||
|
||||
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
|
||||
- Change `nix-build -o ""` to behave like `--no-out-link` [cl/2103](https://gerrit.lix.systems/c/lix/+/2103)
|
||||
|
||||
[`nix-build`](@docroot@/command-ref/nix-build.md) now treats <code>[--out-link](@docroot@/command-ref/nix-build.md#opt-out-link) ''</code>
|
||||
the same as [`--no-out-link`](@docroot@/command-ref/nix-build.md#opt-no-out-link). This matches
|
||||
[`nix build`](@docroot@/command-ref/new-cli/nix3-build.md) behavior. Previously when building the default output it
|
||||
would have resulted in throwing an error saying the current working directory already exists, and when building any
|
||||
other output it would have resulted in a symlink starting with a hyphen such as `-doc`, which is a footgun for
|
||||
terminal commands.
|
||||
|
||||
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
|
||||
- Ignore broken `/etc/ssl/certs/ca-certificates.crt` symlink [fj#560](https://git.lix.systems/lix-project/lix/issues/560) [cl/2144](https://gerrit.lix.systems/c/lix/+/2144)
|
||||
|
||||
[`ssl-cert-file`](@docroot@/command-ref/conf-file.md#conf-ssl-cert-file) now checks its default
|
||||
value for a broken symlink before using it. This fixes a problem on macOS where uninstalling
|
||||
nix-darwin may leave behind a broken symlink at `/etc/ssl/certs/ca-certificates.crt` that was
|
||||
stopping Lix from using the cert at `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt`.
|
||||
|
||||
Many thanks to [lilyball](https://git.lix.systems/lilyball) for this.
|
||||
- `<nix/fetchurl.nix>` now uses TLS verification [#11585](https://github.com/NixOS/nix/pull/11585)
|
||||
|
||||
Previously `<nix/fetchurl.nix>` did not do TLS verification. This was because the Nix sandbox in the past did not have access to TLS certificates, and Nix checks the hash of the fetched file anyway. However, this can expose authentication data from `netrc` and URLs to man-in-the-middle attackers. In addition, Nix now in some cases (such as when using impure derivations) does *not* check the hash. Therefore we have now enabled TLS verification. This means that downloads by `<nix/fetchurl.nix>` will now fail if you're fetching from a HTTPS server that does not have a valid certificate.
|
||||
|
||||
`<nix/fetchurl.nix>` is also known as the builtin derivation builder `builtin:fetchurl`. It's not to be confused with the evaluation-time function `builtins.fetchurl`, which was not affected by this issue.
|
||||
|
||||
Many thanks to [Eelco Dolstra](https://github.com/edolstra) for this.
|
||||
|
||||
## Packaging
|
||||
- readline support removed [cl/1885](https://gerrit.lix.systems/c/lix/+/1885)
|
||||
|
||||
Support for building Lix with [`readline`][readline] instead of
|
||||
[`editline`][editline] has been removed. `readline` support hasn't worked for a
|
||||
long time (attempting to use it would lead to build errors) and would make Lix
|
||||
subject to the GPL if it did work. In the future, we're hoping to replace
|
||||
`editline` with [`rustyline`][rustyline] for improved ergonomics in the `nix
|
||||
repl`.
|
||||
|
||||
[readline]: https://en.wikipedia.org/wiki/GNU_Readline
|
||||
[editline]: https://github.com/troglobit/editline
|
||||
[rustyline]: https://github.com/kkawakam/rustyline
|
||||
|
||||
Many thanks to [wiggles](https://git.lix.systems/rbt) for this.
|
||||
|
||||
## Development
|
||||
- Includes are now qualified with library name everywhere [cl/2178](https://gerrit.lix.systems/c/lix/+/2178) [cl/2362](https://gerrit.lix.systems/c/lix/+/2362)
|
||||
|
||||
The Lix includes have all been rearranged to be of the form `"lix/libexpr/foo.hh"` instead of `"foo.hh"`.
|
||||
This was already supported externally for a migration period, but it is now being applied to all the internal usages within Lix itself.
|
||||
The goal of this change is to both clarify where a file is from and to avoid polluting global include paths with things like `config.h` that might conflict with other projects.
|
||||
|
||||
Lix 2.92 removes support for the old `"foo.hh"` include form either internally or externally (that is, via pkg-config for things linking to Lix).
|
||||
|
||||
For other details, see the release notes of Lix 2.90.0, under "Rename all the libraries" in Breaking Changes.
|
||||
|
||||
To fix an external project with sources in `src` which has a separate build directory (such that headers are in `../src` relative to where the compiler is running), use a checkout of Lix 2.91 to run the following:
|
||||
|
||||
```
|
||||
lix_root=$HOME/lix
|
||||
(cd $lix_root && nix develop -c 'meson setup build && ninja -C build subprojects/lix-clang-tidy/liblix-clang-tidy.so')
|
||||
run-clang-tidy -checks='-*,lix-fixincludes' -load=$lix_root/build/subprojects/lix-clang-tidy/liblix-clang-tidy.so -p build/ -header-filter '\.\./src/.*\.h' -fix src
|
||||
```
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- The beginnings of a new pytest-based functional test suite [cl/2036](https://gerrit.lix.systems/c/lix/+/2036) [cl/2037](https://gerrit.lix.systems/c/lix/+/2037)
|
||||
|
||||
The existing integration/functional test suite is based on a large volume of shell scripts.
|
||||
This often makes it somewhat challenging to debug at the best of times.
|
||||
The goal of the pytest test suite is to make tests have more obvious dependencies on files and to make tests more concise and easier to write, as well as making new testing methods like snapshot testing easy.
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- Dependency on monolithic coreutils removed [cl/2108](https://gerrit.lix.systems/c/lix/+/2108)
|
||||
|
||||
Previously, the build erroneously depended on a `coreutils` binary, which requires `coreutils` to be built with a specific configuration. This was only used in one test and was not required to be a single binary. This dependency is removed now.
|
||||
|
||||
Many thanks to [Vigress](https://git.lix.systems/vigress8) for this.
|
||||
- All Lix threads are named [cl/2210](https://gerrit.lix.systems/c/lix/+/2210)
|
||||
|
||||
Lix now sets thread names on all of its secondary threads, which will make debugger usage slightly nicer and easier.
|
||||
|
||||
```
|
||||
(gdb) info thr
|
||||
Id Target Id Frame
|
||||
* 1 LWP 3719283 "nix-daemon" 0x00007e558587da0f in accept ()
|
||||
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
|
||||
2 LWP 3719284 "signal handler" 0x00007e55857b2bea in sigtimedwait ()
|
||||
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
|
||||
```
|
||||
|
||||
Many thanks to [jade](https://git.lix.systems/jade) for this.
|
||||
- Set `X-GitHub-Api-Version` header [fj#255](https://git.lix.systems/lix-project/lix/issues/255) [cl/1925](https://gerrit.lix.systems/c/lix/+/1925)
|
||||
|
||||
Sets the `X-GitHub-Api-Version` header to `2022-11-28` for calls to the
|
||||
GitHub API.
|
||||
This follows the later version as per
|
||||
https://docs.github.com/en/rest/about-the-rest-api/api-versions?apiVersion=2022-11-28.
|
||||
|
||||
This affected the check on whether to use the API versus unauthenticated
|
||||
calls as well, given the headers would no longer be empty if the
|
||||
authentication token were missing.
|
||||
The workaround to this used here is to use a check similar to an existing
|
||||
check for the token.
|
||||
|
||||
In the current implementation, headers are (still) similarly sent to
|
||||
non-authenticated as well as GitHub on-prem calls.
|
||||
For what it's worth, manual curl calls with such a header seemed to
|
||||
break nor unauthenticated calls nor ones to the github.com API.
|
||||
|
||||
Many thanks to [kiara](https://github.com/KiaraGrouwstra) for this.
|
||||
|
||||
## Miscellany
|
||||
- Drop support for `xz` and `bzip2` Content-Encoding [cl/2134](https://gerrit.lix.systems/c/lix/+/2134)
|
||||
|
||||
Lix no longer supports the non-standard HTTP Content-Encoding values `xz` and `bzip2`.
|
||||
We do not expect this to cause any problems in practice since these encodings *aren't*
|
||||
standard, and any server delivering them anyway without being asked to is already well
|
||||
and truly set on the path of causing inexplicable client breakages.
|
||||
|
||||
Lix's ability to decompress files compressed with `xz` or `bzip2` is unaffected. We're
|
||||
only bringing Lix more in line with the HTTP standard; all post-transfer data handling
|
||||
remains as it was before.
|
||||
|
||||
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||
@@ -1,139 +0,0 @@
|
||||
with builtins;
|
||||
|
||||
rec {
|
||||
splitLines = s: filter (x: !isList x) (split "\n" s);
|
||||
|
||||
concatStrings = concatStringsSep "";
|
||||
|
||||
attrsToList =
|
||||
a:
|
||||
map (name: {
|
||||
inherit name;
|
||||
value = a.${name};
|
||||
}) (builtins.attrNames a);
|
||||
|
||||
replaceStringsRec =
|
||||
from: to: string:
|
||||
# recursively replace occurrences of `from` with `to` within `string`
|
||||
# example:
|
||||
# replaceStringRec "--" "-" "hello-----world"
|
||||
# => "hello-world"
|
||||
let
|
||||
replaced = replaceStrings [ from ] [ to ] string;
|
||||
in
|
||||
if replaced == string then string else replaceStringsRec from to replaced;
|
||||
|
||||
squash = replaceStringsRec "\n\n\n" "\n\n";
|
||||
|
||||
trim =
|
||||
string:
|
||||
# trim trailing spaces and squash non-leading spaces
|
||||
let
|
||||
trimLine =
|
||||
line:
|
||||
let
|
||||
# separate leading spaces from the rest
|
||||
parts = split "(^ *)" line;
|
||||
spaces = head (elemAt parts 1);
|
||||
rest = elemAt parts 2;
|
||||
# drop trailing spaces
|
||||
body = head (split " *$" rest);
|
||||
in
|
||||
spaces + replaceStringsRec " " " " body;
|
||||
in
|
||||
concatStringsSep "\n" (map trimLine (splitLines string));
|
||||
|
||||
# FIXME: O(n^2)
|
||||
unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [ ];
|
||||
|
||||
nameValuePair = name: value: { inherit name value; };
|
||||
|
||||
filterAttrs =
|
||||
pred: set:
|
||||
listToAttrs (
|
||||
concatMap (
|
||||
name:
|
||||
let
|
||||
v = set.${name};
|
||||
in
|
||||
if pred name v then [ (nameValuePair name v) ] else [ ]
|
||||
) (attrNames set)
|
||||
);
|
||||
|
||||
optionalString = cond: string: if cond then string else "";
|
||||
|
||||
showSetting =
|
||||
{ inlineHTML }:
|
||||
name:
|
||||
{
|
||||
description,
|
||||
documentDefault,
|
||||
defaultValue,
|
||||
aliases,
|
||||
value,
|
||||
experimentalFeature,
|
||||
}:
|
||||
let
|
||||
result = squash ''
|
||||
- ${
|
||||
if inlineHTML then ''<span id="conf-${name}">[`${name}`](#conf-${name})</span>'' else ''`${name}`''
|
||||
}
|
||||
|
||||
${indent " " body}
|
||||
'';
|
||||
|
||||
experimentalFeatureNote = optionalString (experimentalFeature != null) ''
|
||||
> **Warning**
|
||||
> This setting is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
To change this setting, you need to make sure the corresponding experimental feature,
|
||||
[`${experimentalFeature}`](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature}),
|
||||
is enabled.
|
||||
For example, include the following in [`nix.conf`](#):
|
||||
|
||||
```
|
||||
extra-experimental-features = ${experimentalFeature}
|
||||
${name} = ...
|
||||
```
|
||||
'';
|
||||
|
||||
# separate body to cleanly handle indentation
|
||||
body = ''
|
||||
${description}
|
||||
|
||||
${experimentalFeatureNote}
|
||||
|
||||
**Default:** ${showDefault documentDefault defaultValue}
|
||||
|
||||
${showAliases aliases}
|
||||
'';
|
||||
|
||||
showDefault =
|
||||
documentDefault: defaultValue:
|
||||
if documentDefault then
|
||||
# a StringMap value type is specified as a string, but
|
||||
# this shows the value type. The empty stringmap is `null` in
|
||||
# JSON, but that converts to `{ }` here.
|
||||
if defaultValue == "" || defaultValue == [ ] || isAttrs defaultValue then
|
||||
"*empty*"
|
||||
else if isBool defaultValue then
|
||||
if defaultValue then "`true`" else "`false`"
|
||||
else
|
||||
"`${toString defaultValue}`"
|
||||
else
|
||||
"*machine-specific*";
|
||||
|
||||
showAliases =
|
||||
aliases:
|
||||
optionalString (aliases != [ ])
|
||||
"**Deprecated alias:** ${(concatStringsSep ", " (map (s: "`${s}`") aliases))}";
|
||||
in
|
||||
result;
|
||||
|
||||
indent =
|
||||
prefix: s: concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s));
|
||||
|
||||
showSettings =
|
||||
args: settingsInfo: concatStrings (attrValues (mapAttrs (showSetting args) settingsInfo));
|
||||
}
|
||||
Generated
+10
-10
@@ -19,11 +19,11 @@
|
||||
"nix2container": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1720642556,
|
||||
"narHash": "sha256-qsnqk13UmREKmRT7c8hEnz26X3GFFyIQrqx4EaRc1Is=",
|
||||
"lastModified": 1724996935,
|
||||
"narHash": "sha256-njRK9vvZ1JJsP8oV2OgkBrpJhgQezI03S7gzskCcHos=",
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"rev": "3853e5caf9ad24103b13aa6e0e8bcebb47649fe4",
|
||||
"rev": "fa6bb0a1159f55d071ba99331355955ae30b3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -34,16 +34,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1721931987,
|
||||
"narHash": "sha256-1Zg8LY0T5EfXtv0Kf4M6SFnjH7Eto4VV+EKJ/YSnhiI=",
|
||||
"lastModified": 1733348545,
|
||||
"narHash": "sha256-b4JrUmqT0vFNx42aEN9LTWOHomkTKL/ayLopflVf81U=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e21630230c77140bc6478a21cd71e8bb73706fce",
|
||||
"rev": "9ecb50d2fae8680be74c08bb0a995c5383747f89",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05-small",
|
||||
"ref": "nixos-24.11-small",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -67,11 +67,11 @@
|
||||
"pre-commit-hooks": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1721042469,
|
||||
"narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=",
|
||||
"lastModified": 1733318908,
|
||||
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "f451c19376071a90d8c58ab1a953c6e9840527fd",
|
||||
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "Lix: A modern, delicious implementation of the Nix package manager";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05-small";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11-small";
|
||||
nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||
pre-commit-hooks = {
|
||||
url = "github:cachix/git-hooks.nix";
|
||||
@@ -99,9 +99,10 @@
|
||||
];
|
||||
|
||||
stdenvs = [
|
||||
"gccStdenv"
|
||||
# see assertion in package.nix why these two are disabled
|
||||
# "stdenv"
|
||||
# "gccStdenv"
|
||||
"clangStdenv"
|
||||
"stdenv"
|
||||
"libcxxStdenv"
|
||||
"ccacheStdenv"
|
||||
];
|
||||
@@ -121,7 +122,11 @@
|
||||
name = "${stdenvName}Packages";
|
||||
value = f stdenvName;
|
||||
}) stdenvs
|
||||
);
|
||||
)
|
||||
// {
|
||||
# TODO delete this and reënable gcc stdenvs once gcc compiles kj coros correctly
|
||||
stdenvPackages = f "clangStdenv";
|
||||
};
|
||||
|
||||
# Memoize nixpkgs for different platforms for efficiency.
|
||||
nixpkgsFor = forAllSystems (
|
||||
@@ -133,14 +138,7 @@
|
||||
localSystem = {
|
||||
inherit system;
|
||||
};
|
||||
crossSystem =
|
||||
if crossSystem == null then
|
||||
null
|
||||
else
|
||||
{
|
||||
system = crossSystem;
|
||||
}
|
||||
// lib.optionalAttrs (crossSystem == "x86_64-freebsd") { useLLVM = true; };
|
||||
crossSystem = if crossSystem == null then null else { system = crossSystem; };
|
||||
overlays = [ (overlayFor (p: p.${stdenv})) ];
|
||||
};
|
||||
stdenvs = forAllStdenvs (make-pkgs null);
|
||||
@@ -149,7 +147,7 @@
|
||||
{
|
||||
inherit stdenvs native;
|
||||
static = native.pkgsStatic;
|
||||
cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "stdenv");
|
||||
cross = forAllCrossSystems (crossSystem: make-pkgs crossSystem "clangStdenv");
|
||||
}
|
||||
);
|
||||
|
||||
@@ -212,7 +210,7 @@
|
||||
|
||||
# A Nixpkgs overlay that overrides the 'nix' and
|
||||
# 'nix.perl-bindings' packages.
|
||||
overlays.default = overlayFor (p: p.stdenv);
|
||||
overlays.default = overlayFor (p: p.clangStdenv);
|
||||
|
||||
hydraJobs = {
|
||||
# Binary package for various platforms.
|
||||
@@ -264,6 +262,8 @@
|
||||
nix = pkgs.callPackage ./package.nix {
|
||||
inherit versionSuffix officialRelease buildUnreleasedNotes;
|
||||
inherit (pkgs) build-release-notes;
|
||||
# Required since we don't support gcc stdenv
|
||||
stdenv = pkgs.clangStdenv;
|
||||
internalApiDocs = true;
|
||||
busybox-sandbox-shell = pkgs.busybox-sandbox-shell;
|
||||
};
|
||||
@@ -321,6 +321,8 @@
|
||||
inherit (nixpkgs) pkgs;
|
||||
in
|
||||
pkgs.callPackage ./package.nix {
|
||||
# Required since we don't support gcc stdenv
|
||||
stdenv = pkgs.clangStdenv;
|
||||
versionSuffix = "";
|
||||
lintInsteadOfBuild = true;
|
||||
};
|
||||
@@ -348,10 +350,10 @@
|
||||
name = "nixpkgs-lib-tests";
|
||||
paths =
|
||||
[ testWithNix ]
|
||||
# FIXME: This is disabled on darwin due to a nixpkgs bug https://github.com/NixOS/nixpkgs/issues/319147
|
||||
# After that is fixed, it should be restored to use lib/tests/release.nix as before, rather than this reimplementation.
|
||||
# NOTE: nixpkgs 24.11 is being ... *creative*, and requires this dance to override
|
||||
# the evaluator used for the test. it will break again in the future, don't worry.
|
||||
++ lib.optionals pkgs.stdenv.isLinux [
|
||||
(import (nixpkgs + "/pkgs/test/release") { inherit pkgs lib nix; })
|
||||
(pkgs.callPackage "${nixpkgs}/ci/eval" { nixVersions.nix_2_24 = nix; }).attrpathsSuperset
|
||||
];
|
||||
}
|
||||
);
|
||||
@@ -484,7 +486,7 @@
|
||||
let
|
||||
pkgs = nixpkgsFor.${system}.cross.${crossSystem};
|
||||
in
|
||||
makeShell pkgs pkgs.stdenv
|
||||
makeShell pkgs pkgs.clangStdenv
|
||||
))
|
||||
// {
|
||||
default = self.devShells.${system}.native-clangStdenvPackages;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
from typing import List, NamedTuple
|
||||
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'type',
|
||||
'constructorArgs',
|
||||
'implementation',
|
||||
'impure',
|
||||
'renameInGlobalScope',
|
||||
])
|
||||
|
||||
class BuiltinConstant(NamedTuple):
|
||||
name: str
|
||||
type: str
|
||||
implementation: str
|
||||
impure: bool
|
||||
rename_in_global_scope: bool
|
||||
documentation: str
|
||||
|
||||
def parse(datum):
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise Exception('unknown keys', unknown_keys)
|
||||
return BuiltinConstant(
|
||||
name = datum['name'],
|
||||
type = datum['type'],
|
||||
implementation = ('{' + ', '.join([f'NewValueAs::{datum["type"]}', *datum['constructorArgs']]) + '}') if 'constructorArgs' in datum else datum['implementation'],
|
||||
impure = datum.get('impure', False),
|
||||
rename_in_global_scope = datum.get('renameInGlobalScope', True),
|
||||
documentation = datum.content,
|
||||
)
|
||||
|
||||
VALUE_TYPES = {
|
||||
'attrs': 'nAttrs',
|
||||
'boolean': 'nBool',
|
||||
'integer': 'nInt',
|
||||
'list': 'nList',
|
||||
'null': 'nNull',
|
||||
'string': 'nString',
|
||||
}
|
||||
|
||||
HUMAN_TYPES = {
|
||||
'attrs': 'set',
|
||||
'boolean': 'Boolean',
|
||||
'integer': 'integer',
|
||||
'list': 'list',
|
||||
'null': 'null',
|
||||
'string': 'string',
|
||||
}
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('defs', help='Builtin definition files', nargs='+')
|
||||
args = ap.parse_args()
|
||||
|
||||
builtin_constants = load_data(args.defs, BuiltinConstant.parse)
|
||||
|
||||
generate_file(args.header, builtin_constants, lambda constant:
|
||||
# `builtins` is magic and must come first
|
||||
'' if constant.name == 'builtins' else constant.name,
|
||||
lambda constant:
|
||||
f'''{'if (!evalSettings.pureEval) ' if constant.impure else ''}{{
|
||||
addConstant({cxx_literal(('__' if constant.rename_in_global_scope else '') + constant.name)}, {constant.implementation}, {{
|
||||
.type = {VALUE_TYPES[constant.type]},
|
||||
.doc = {cxx_literal(constant.documentation)},
|
||||
.impureOnly = {cxx_literal(constant.impure)},
|
||||
}});
|
||||
}}
|
||||
''')
|
||||
generate_file(args.docs, builtin_constants, lambda constant: constant.name, lambda constant:
|
||||
f'''<dt id="builtins-{constant.name}">
|
||||
<a href="#builtins-{constant.name}"><code>{constant.name}</code></a> ({HUMAN_TYPES[constant.type]})
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
{constant.documentation}
|
||||
|
||||
''' + ('''> **Note**
|
||||
>
|
||||
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||
|
||||
''' if constant.impure else '') + '''</dd>
|
||||
|
||||
''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
from typing import List, NamedTuple, Optional
|
||||
|
||||
from build_experimental_features import ExperimentalFeature
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'implementation',
|
||||
'renameInGlobalScope',
|
||||
'args',
|
||||
'experimentalFeature',
|
||||
])
|
||||
|
||||
class Builtin(NamedTuple):
|
||||
name: str
|
||||
implementation: str
|
||||
rename_in_global_scope: bool
|
||||
args: List[str]
|
||||
experimental_feature: Optional[str]
|
||||
documentation: str
|
||||
|
||||
def parse(datum):
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise Exception('unknown keys', unknown_keys)
|
||||
return Builtin(
|
||||
name = datum['name'],
|
||||
implementation = datum['implementation'] if 'implementation' in datum else f'prim_{datum["name"]}',
|
||||
rename_in_global_scope = datum.get('renameInGlobalScope', True),
|
||||
args = datum['args'],
|
||||
experimental_feature = datum.get('experimentalFeature', None),
|
||||
documentation = datum.content,
|
||||
)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
|
||||
ap.add_argument('defs', help='Builtin definition files', nargs='+')
|
||||
args = ap.parse_args()
|
||||
|
||||
builtins = load_data(args.defs, Builtin.parse)
|
||||
|
||||
experimental_feature_names = set([builtin.experimental_feature for (_, builtin) in builtins])
|
||||
experimental_feature_names.discard(None)
|
||||
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
|
||||
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
|
||||
experimental_features = dict(map(lambda path_and_feature:
|
||||
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
|
||||
experimental_features[None] = 'std::nullopt'
|
||||
|
||||
generate_file(args.header, builtins, lambda builtin: builtin.name, lambda builtin:
|
||||
f'''{'' if builtin.experimental_feature is None else f'if (experimentalFeatureSettings.isEnabled({experimental_features[builtin.experimental_feature]})) '}{{
|
||||
addPrimOp({{
|
||||
.name = {cxx_literal(('__' if builtin.rename_in_global_scope else '') + builtin.name)},
|
||||
.args = {cxx_literal(builtin.args)},
|
||||
.arity = {len(builtin.args)},
|
||||
.doc = {cxx_literal(builtin.documentation)},
|
||||
.fun = {builtin.implementation},
|
||||
.experimentalFeature = {experimental_features[builtin.experimental_feature]},
|
||||
}});
|
||||
}}
|
||||
''')
|
||||
generate_file(args.docs, builtins, lambda builtin: builtin.name, lambda builtin:
|
||||
f'''<dt id="builtins-{builtin.name}">
|
||||
<a href="#builtins-{builtin.name}"><code>{builtin.name} {' '.join([f'<var>{arg}</var>' for arg in builtin.args])}</code></a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
{builtin.documentation}
|
||||
|
||||
''' + (f'''This function is only available if the [{builtin.experimental_feature}](@docroot@/contributing/experimental-features.md#xp-feature-{builtin.experimental_feature}) experimental feature is enabled.
|
||||
|
||||
''' if builtin.experimental_feature is not None else '') + '''</dd>
|
||||
|
||||
''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,58 @@
|
||||
from typing import NamedTuple
|
||||
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'internalName',
|
||||
])
|
||||
|
||||
class ExperimentalFeature(NamedTuple):
|
||||
name: str
|
||||
internal_name: str
|
||||
description: str
|
||||
|
||||
def parse(datum):
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise ValueError('unknown keys', unknown_keys)
|
||||
return ExperimentalFeature(
|
||||
name = datum['name'],
|
||||
internal_name = datum['internalName'],
|
||||
description = datum.content,
|
||||
)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--deprecated', action='store_true', help='Generate deprecated features')
|
||||
ap.add_argument('--header', help='Path of the declaration header to generate')
|
||||
ap.add_argument('--impl-header', help='Path of the implementation header to generate')
|
||||
ap.add_argument('--descriptions', help='Path of the description file to generate')
|
||||
ap.add_argument('--shortlist', help='Path of the shortlist file to generate')
|
||||
ap.add_argument('defs', help='Experimental feature definition files', nargs='+')
|
||||
args = ap.parse_args()
|
||||
|
||||
features = load_data(args.defs, ExperimentalFeature.parse)
|
||||
|
||||
generate_file(args.header, features, lambda feature: feature.name, lambda feature:
|
||||
f' {feature.internal_name},\n')
|
||||
generate_file(args.impl_header, features, lambda feature: feature.name, lambda feature:
|
||||
f''' {{
|
||||
.tag = {"Dep" if args.deprecated else "Xp"}::{feature.internal_name},
|
||||
.name = {cxx_literal(feature.name)},
|
||||
.description = {cxx_literal(feature.description)},
|
||||
}},
|
||||
''')
|
||||
generate_file(args.descriptions, features, lambda feature: feature.name, lambda feature:
|
||||
f'''## [`{feature.name}`]{{#{"dp" if args.deprecated else "xp"}-feature-{feature.name}}}
|
||||
|
||||
{feature.description}
|
||||
|
||||
''')
|
||||
generate_file(args.shortlist, features, lambda feature: feature.name, lambda feature:
|
||||
f' - [`{feature.name}`](@docroot@/contributing/{"deprecated" if args.deprecated else "experimental"}-features.md#{"dp" if args.deprecated else "xp"}-feature-{feature.name})\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,141 @@
|
||||
from typing import List, NamedTuple, Optional
|
||||
|
||||
from build_experimental_features import ExperimentalFeature
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'internalName',
|
||||
'platforms',
|
||||
'type',
|
||||
'settingType',
|
||||
'default',
|
||||
'defaultExpr',
|
||||
'defaultText',
|
||||
'aliases',
|
||||
'experimentalFeature',
|
||||
'deprecated',
|
||||
])
|
||||
|
||||
class Setting(NamedTuple):
|
||||
name: str
|
||||
internal_name: str
|
||||
description: str
|
||||
platforms: Optional[List[str]]
|
||||
setting_type: str
|
||||
default_expr: str
|
||||
default_text: str
|
||||
aliases: List[str]
|
||||
experimental_feature: Optional[str]
|
||||
deprecated: bool
|
||||
|
||||
def parse(datum):
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise ValueError('unknown keys', unknown_keys)
|
||||
default_text = f'`{nix_conf_literal(datum["default"])}`' if 'default' in datum else datum['defaultText']
|
||||
if default_text == '``':
|
||||
default_text = '*empty*'
|
||||
return Setting(
|
||||
name = datum['name'],
|
||||
internal_name = datum['internalName'],
|
||||
description = datum.content,
|
||||
platforms = datum.get('platforms', None),
|
||||
setting_type = f'Setting<{datum["type"]}>' if 'type' in datum else datum['settingType'],
|
||||
default_expr = cxx_literal(datum['default']) if 'default' in datum else datum['defaultExpr'],
|
||||
default_text = default_text,
|
||||
aliases = datum.get('aliases', []),
|
||||
experimental_feature = datum.get('experimentalFeature', None),
|
||||
deprecated = datum.get('deprecated', False),
|
||||
)
|
||||
|
||||
platform_names = {
|
||||
'darwin': 'Darwin',
|
||||
'linux': 'Linux',
|
||||
}
|
||||
|
||||
def nix_conf_literal(v):
|
||||
if v is None:
|
||||
return ''
|
||||
elif isinstance(v, bool) and v == False: # 0 == False
|
||||
return 'false'
|
||||
elif isinstance(v, bool) and v == True: # 1 == True
|
||||
return 'true'
|
||||
elif isinstance(v, int):
|
||||
return str(v)
|
||||
elif isinstance(v, str):
|
||||
return v
|
||||
elif isinstance(v, list):
|
||||
return ' '.join([nix_conf_literal(item) for item in v])
|
||||
else:
|
||||
raise NotImplementedError(f'Cannot represent {repr(v)} in nix.conf')
|
||||
|
||||
def indent(prefix, body):
|
||||
return ''.join(['\n' if line == '' else f'{prefix}{line}\n' for line in body.split('\n')])
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--kernel', help='Name of the kernel Lix will run on')
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
|
||||
ap.add_argument('defs', help='Setting definition files', nargs='+')
|
||||
args = ap.parse_args()
|
||||
|
||||
settings = load_data(args.defs, Setting.parse)
|
||||
|
||||
experimental_feature_names = set([setting.experimental_feature for (_, setting) in settings])
|
||||
experimental_feature_names.discard(None)
|
||||
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
|
||||
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
|
||||
experimental_features = dict(map(lambda path_and_feature:
|
||||
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
|
||||
experimental_features[None] = 'std::nullopt'
|
||||
|
||||
generate_file(args.header, settings, lambda setting: setting.name, lambda setting:
|
||||
f'''{setting.setting_type} {setting.internal_name} {{
|
||||
this,
|
||||
{setting.default_expr},
|
||||
{cxx_literal(setting.name)},
|
||||
{cxx_literal(setting.description)},
|
||||
{cxx_literal(setting.aliases)},
|
||||
true,
|
||||
{experimental_features[setting.experimental_feature]},
|
||||
{cxx_literal(setting.deprecated)}
|
||||
}};
|
||||
|
||||
''' if setting.platforms is None or args.kernel in setting.platforms else '')
|
||||
generate_file(args.docs, settings, lambda setting: setting.name, lambda setting:
|
||||
f'''- <span id="conf-{setting.name}">[`{setting.name}`](#conf-{setting.name})</span>
|
||||
|
||||
{indent(" ", setting.description)}
|
||||
''' + (f''' > **Note**
|
||||
> This setting is only available on {', '.join([platform_names[platform] for platform in setting.platforms])} systems.
|
||||
|
||||
''' if setting.platforms is not None else '') + (f''' > **Warning**
|
||||
> This setting is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
To change this setting, you need to make sure the corresponding experimental feature,
|
||||
[`{setting.experimental_feature}`](@docroot@/contributing/experimental-features.md#xp-feature-{setting.experimental_feature}),
|
||||
is enabled.
|
||||
For example, include the following in [`nix.conf`](#):
|
||||
|
||||
```
|
||||
extra-experimental-features = {setting.experimental_feature}
|
||||
{setting.name} = ...
|
||||
```
|
||||
|
||||
''' if setting.experimental_feature is not None else '') + (''' > **Warning**
|
||||
> This setting is deprecated and will be removed in a future version of Lix.
|
||||
|
||||
''' if setting.deprecated else '') + f''' **Default:** {setting.default_text}
|
||||
|
||||
''' + (f''' **Deprecated alias:** {', '.join([f'`{item}`' for item in setting.aliases])}
|
||||
|
||||
''' if setting.aliases != [] else ''))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,60 @@
|
||||
import frontmatter
|
||||
import pathlib
|
||||
from collections import defaultdict
|
||||
|
||||
def cxx_escape_character(c):
|
||||
if ord(c) >= 0x20 and ord(c) < 0x7f and c != '"' and c != '?' and c != '\\':
|
||||
return c
|
||||
elif c == '\t':
|
||||
return r'\t'
|
||||
elif c == '\n':
|
||||
return r'\n'
|
||||
elif c == '\r':
|
||||
return r'\r'
|
||||
elif c == '"':
|
||||
return r'\"'
|
||||
elif c == '?':
|
||||
return r'\?'
|
||||
elif c == '\\':
|
||||
return r'\\'
|
||||
elif ord(c) <= 0xffff:
|
||||
return str.format(r'\u{:04x}', ord(c))
|
||||
else:
|
||||
return str.format(r'\U{:08x}', ord(c))
|
||||
|
||||
def cxx_literal(v):
|
||||
if v is None:
|
||||
return 'std::nullopt'
|
||||
elif isinstance(v, bool) and v == False: # 0 == False
|
||||
return 'false'
|
||||
elif isinstance(v, bool) and v == True: # 1 == True
|
||||
return 'true'
|
||||
elif isinstance(v, int):
|
||||
return str(v)
|
||||
elif isinstance(v, str):
|
||||
return ''.join(['"', *(cxx_escape_character(c) for c in v), '"'])
|
||||
elif isinstance(v, list):
|
||||
return f'{{{", ".join([cxx_literal(item) for item in v])}}}'
|
||||
else:
|
||||
raise NotImplementedError(f'cannot represent {repr(v)} in C++')
|
||||
|
||||
def load_data(defs, parse_function):
|
||||
data = []
|
||||
for path in defs:
|
||||
try:
|
||||
datum = frontmatter.load(path)
|
||||
data.append((path, parse_function(datum)))
|
||||
except Exception as e:
|
||||
e.add_note(f'in {path}')
|
||||
raise
|
||||
return data
|
||||
|
||||
def generate_file(path, data, sort_key_function, generate_function):
|
||||
if path is not None:
|
||||
with open(path, 'w') as out:
|
||||
for path, datum in sorted(data, key=lambda pathAndDatum: sort_key_function(pathAndDatum[1])):
|
||||
try:
|
||||
out.write(generate_function(datum))
|
||||
except Exception as e:
|
||||
e.add_note(f'in {path}')
|
||||
raise
|
||||
@@ -6,21 +6,22 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "machines.hh"
|
||||
#include "shared.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "globals.hh"
|
||||
#include "serialise.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-api.hh"
|
||||
#include "derivations.hh"
|
||||
#include "strings.hh"
|
||||
#include "local-store.hh"
|
||||
#include "legacy.hh"
|
||||
#include "experimental-features.hh"
|
||||
#include "hash.hh"
|
||||
#include "lix/libstore/machines.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/pathlocks.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libutil/serialise.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libstore/local-store.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libutil/experimental-features.hh"
|
||||
#include "lix/libutil/hash.hh"
|
||||
#include "build-remote.hh"
|
||||
|
||||
using namespace nix;
|
||||
namespace nix {
|
||||
|
||||
static void handleAlarm(int sig) {
|
||||
}
|
||||
@@ -50,11 +51,11 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
|
||||
|
||||
static bool allSupportedLocally(Store & store, const std::set<std::string>& requiredFeatures) {
|
||||
for (auto & feature : requiredFeatures)
|
||||
if (!store.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(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
logger = makeJSONLogger(*logger);
|
||||
@@ -66,10 +67,10 @@ static int main_build_remote(int argc, char * * argv)
|
||||
/* If we ever use the common args framework, make sure to
|
||||
remove initPlugins below and initialize settings first.
|
||||
*/
|
||||
if (argc != 2)
|
||||
if (argv.size() != 1)
|
||||
throw UsageError("called without required arguments");
|
||||
|
||||
verbosity = (Verbosity) std::stoll(argv[1]);
|
||||
verbosity = (Verbosity) std::stoll(argv.front());
|
||||
|
||||
FdSource source(STDIN_FILENO);
|
||||
|
||||
@@ -91,7 +92,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->stateDir } + currentLoadName;
|
||||
currentLoad = std::string { localStore->config().stateDir } + currentLoadName;
|
||||
else
|
||||
currentLoad = settings.nixStateDir + currentLoadName;
|
||||
|
||||
@@ -308,7 +309,7 @@ connected:
|
||||
});
|
||||
|
||||
// See the very large comment in `case WorkerProto::Op::BuildDerivation:` in
|
||||
// `src/libstore/daemon.cc` that explains the trust model here.
|
||||
// `lix/libstore/daemon.cc` that explains the trust model here.
|
||||
//
|
||||
// This condition mirrors that: that code enforces the "rules" outlined there;
|
||||
// we do the best we can given those "rules".
|
||||
@@ -388,4 +389,8 @@ connected:
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_build_remote("build-remote", main_build_remote);
|
||||
void registerBuildRemote() {
|
||||
LegacyCommands::add("build-remote", main_build_remote);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerBuildRemote();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "dotgraph.hh"
|
||||
#include "store-api.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "store-api.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphml.hh"
|
||||
#include "store-api.hh"
|
||||
#include "derivations.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "store-api.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
legacy_include_directories = include_directories('.')
|
||||
|
||||
legacy_sources = files(
|
||||
# `build-remote` is not really legacy (it powers all remote builds), but it's
|
||||
# not a `nix3` command.
|
||||
'build-remote.cc',
|
||||
'dotgraph.cc',
|
||||
'graphml.cc',
|
||||
'nix-build.cc',
|
||||
'nix-channel.cc',
|
||||
'nix-collect-garbage.cc',
|
||||
'nix-copy-closure.cc',
|
||||
'nix-env.cc',
|
||||
'nix-env.hh',
|
||||
'nix-instantiate.cc',
|
||||
'nix-store.cc',
|
||||
'user-env.cc',
|
||||
)
|
||||
|
||||
legacy_headers = files(
|
||||
'build-remote.hh',
|
||||
'nix-build.hh',
|
||||
'nix-channel.hh',
|
||||
'nix-collect-garbage.hh',
|
||||
'nix-copy-closure.hh',
|
||||
'nix-instantiate.hh',
|
||||
'nix-store.hh',
|
||||
)
|
||||
|
||||
legacy_generated_headers = [
|
||||
gen_header.process('buildenv.nix', preserve_path_from: meson.current_source_dir()),
|
||||
gen_header.process('unpack-channel.nix', preserve_path_from: meson.current_source_dir()),
|
||||
]
|
||||
|
||||
fs.copyfile('unpack-channel.nix')
|
||||
@@ -9,31 +9,34 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "parsed-derivations.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "globals.hh"
|
||||
#include "current-process.hh"
|
||||
#include "derivations.hh"
|
||||
#include "shared.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "legacy.hh"
|
||||
#include "shlex.hh"
|
||||
#include "lix/libstore/parsed-derivations.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libutil/current-process.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/path-with-outputs.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/eval-inline.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libutil/shlex.hh"
|
||||
#include "nix-build.hh"
|
||||
#include "lix/libstore/temporary-dir.hh"
|
||||
|
||||
extern char * * environ __attribute__((weak)); // Man what even is this
|
||||
|
||||
namespace nix {
|
||||
|
||||
using namespace nix;
|
||||
using namespace std::string_literals;
|
||||
|
||||
extern char * * environ __attribute__((weak));
|
||||
|
||||
static void main_nix_build(int argc, char * * argv)
|
||||
static void main_nix_build(std::string programName, Strings argv)
|
||||
{
|
||||
auto dryRun = false;
|
||||
auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$"));
|
||||
auto runEnv = std::regex_search(programName, std::regex("nix-shell$"));
|
||||
auto pure = false;
|
||||
auto fromArgs = false;
|
||||
auto packages = false;
|
||||
@@ -53,8 +56,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||
std::string script;
|
||||
std::vector<std::string> savedArgs;
|
||||
|
||||
AutoDelete tmpDir(createTempDir("", myName));
|
||||
|
||||
std::string outLink = "./result";
|
||||
|
||||
// List of environment variables kept for --pure
|
||||
@@ -65,29 +66,24 @@ static void main_nix_build(int argc, char * * argv)
|
||||
"http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy"
|
||||
};
|
||||
|
||||
Strings args;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
args.push_back(argv[i]);
|
||||
|
||||
// Heuristic to see if we're invoked as a shebang script, namely,
|
||||
// if we have at least one argument, it's the name of an
|
||||
// executable file, and it starts with "#!".
|
||||
if (runEnv && argc > 1) {
|
||||
script = argv[1];
|
||||
if (runEnv && !argv.empty()) {
|
||||
script = argv.front();
|
||||
try {
|
||||
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
||||
if (std::regex_search(lines.front(), std::regex("^#!"))) {
|
||||
lines.pop_front();
|
||||
inShebang = true;
|
||||
for (int i = 2; i < argc; ++i)
|
||||
savedArgs.push_back(argv[i]);
|
||||
args.clear();
|
||||
savedArgs = {std::next(argv.begin()), argv.end()};
|
||||
argv.clear();
|
||||
for (auto line : lines) {
|
||||
line = chomp(line);
|
||||
std::smatch match;
|
||||
if (std::regex_match(line, match, std::regex("^#!\\s*nix-shell\\s+(.*)$")))
|
||||
for (const auto & word : shell_split(match[1].str()))
|
||||
args.push_back(word);
|
||||
argv.push_back(word);
|
||||
}
|
||||
}
|
||||
} catch (SysError &) { }
|
||||
@@ -100,7 +96,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||
|
||||
MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help") {
|
||||
deletePath(tmpDir);
|
||||
showManPage(myName);
|
||||
}
|
||||
|
||||
@@ -111,7 +106,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
; // obsolete
|
||||
|
||||
else if (*arg == "--no-out-link" || *arg == "--no-link")
|
||||
outLink = (Path) tmpDir + "/result";
|
||||
outLink = "";
|
||||
|
||||
else if (*arg == "--attr" || *arg == "-A")
|
||||
attrPaths.push_back(getArg(*arg, arg, end));
|
||||
@@ -191,23 +186,28 @@ static void main_nix_build(int argc, char * * argv)
|
||||
return true;
|
||||
});
|
||||
|
||||
myArgs.parseCmdline(args);
|
||||
myArgs.parseCmdline(argv);
|
||||
|
||||
if (packages && fromArgs)
|
||||
throw UsageError("'-p' and '-E' are mutually exclusive");
|
||||
|
||||
AutoDelete tmpDir(createTempDir("", myName));
|
||||
if (outLink.empty())
|
||||
outLink = (Path) tmpDir + "/result";
|
||||
|
||||
auto store = openStore();
|
||||
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
||||
|
||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, evalStore, store);
|
||||
state->repair = myArgs.repair;
|
||||
auto evaluator = std::make_unique<Evaluator>(myArgs.searchPath, evalStore, store);
|
||||
evaluator->repair = myArgs.repair;
|
||||
auto state = evaluator->begin();
|
||||
if (myArgs.repair) buildMode = bmRepair;
|
||||
|
||||
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||
auto autoArgs = myArgs.getAutoArgs(*evaluator);
|
||||
|
||||
auto autoArgsWithInNixShell = autoArgs;
|
||||
if (runEnv) {
|
||||
auto newArgs = state->buildBindings(autoArgsWithInNixShell->size() + 1);
|
||||
auto newArgs = evaluator->buildBindings(autoArgsWithInNixShell->size() + 1);
|
||||
newArgs.alloc("inNixShell").mkBool(true);
|
||||
for (auto & i : *autoArgs) newArgs.insert(i);
|
||||
autoArgsWithInNixShell = newArgs.finish();
|
||||
@@ -237,11 +237,11 @@ static void main_nix_build(int argc, char * * argv)
|
||||
std::vector<std::reference_wrapper<Expr>> exprs;
|
||||
|
||||
if (readStdin)
|
||||
exprs = {state->parseStdin()};
|
||||
exprs = {evaluator->parseStdin()};
|
||||
else
|
||||
for (auto i : left) {
|
||||
if (fromArgs)
|
||||
exprs.push_back(state->parseExprFromString(std::move(i), state->rootPath(CanonPath::fromCwd())));
|
||||
exprs.push_back(evaluator->parseExprFromString(std::move(i), CanonPath::fromCwd()));
|
||||
else {
|
||||
auto absolute = i;
|
||||
try {
|
||||
@@ -249,12 +249,16 @@ static void main_nix_build(int argc, char * * argv)
|
||||
} catch (Error & e) {};
|
||||
auto [path, outputNames] = parsePathWithOutputs(absolute);
|
||||
if (evalStore->isStorePath(path) && path.ends_with(".drv"))
|
||||
drvs.push_back(DrvInfo(*state, evalStore, absolute));
|
||||
drvs.push_back(DrvInfo(evalStore, absolute));
|
||||
else
|
||||
/* If we're in a #! script, interpret filenames
|
||||
relative to the script. */
|
||||
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
|
||||
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
||||
exprs.push_back(evaluator->parseExprFromFile(
|
||||
evaluator->paths.resolveExprPath(lookupFileArg(
|
||||
*evaluator,
|
||||
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +277,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
bool add = false;
|
||||
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
||||
for (auto & i : v.lambda.fun->formals->formals) {
|
||||
if (state->symbols[i.name] == "inNixShell") {
|
||||
if (evaluator->symbols[i.name] == "inNixShell") {
|
||||
add = true;
|
||||
break;
|
||||
}
|
||||
@@ -301,7 +305,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
}
|
||||
}
|
||||
|
||||
state->maybePrintStats();
|
||||
evaluator->maybePrintStats();
|
||||
|
||||
auto buildPaths = [&](const std::vector<DerivedPath> & paths) {
|
||||
/* Note: we do this even when !printMissing to efficiently
|
||||
@@ -323,7 +327,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
throw UsageError("nix-shell requires a single derivation");
|
||||
|
||||
auto & drvInfo = drvs.front();
|
||||
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath());
|
||||
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath(*state));
|
||||
|
||||
std::vector<DerivedPath> pathsToBuild;
|
||||
RealisedPath::Set pathsToCopy;
|
||||
@@ -337,9 +341,9 @@ static void main_nix_build(int argc, char * * argv)
|
||||
if (!shell) {
|
||||
|
||||
try {
|
||||
auto & expr = state->parseExprFromString(
|
||||
auto & expr = evaluator->parseExprFromString(
|
||||
"(import <nixpkgs> {}).bashInteractive",
|
||||
state->rootPath(CanonPath::fromCwd()));
|
||||
CanonPath::fromCwd());
|
||||
|
||||
Value v;
|
||||
state->eval(expr, v);
|
||||
@@ -348,7 +352,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
if (!drv)
|
||||
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
|
||||
|
||||
auto bashDrv = drv->requireDrvPath();
|
||||
auto bashDrv = drv->requireDrvPath(*state);
|
||||
pathsToBuild.push_back(DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePathRef(bashDrv),
|
||||
.outputs = OutputsSpec::Names {"out"},
|
||||
@@ -414,8 +418,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||
// Set the environment.
|
||||
auto env = getEnv();
|
||||
|
||||
auto tmp = defaultTempDir();
|
||||
|
||||
if (pure) {
|
||||
decltype(env) newEnv;
|
||||
for (auto & i : env)
|
||||
@@ -426,8 +428,9 @@ static void main_nix_build(int argc, char * * argv)
|
||||
env["__ETC_PROFILE_SOURCED"] = "1";
|
||||
}
|
||||
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
||||
env["NIX_STORE"] = store->storeDir;
|
||||
// Don't use defaultTempDir() here! We want to preserve the user's TMPDIR for the shell
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
env["NIX_STORE"] = store->config().storeDir;
|
||||
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
|
||||
|
||||
auto passAsFile = tokenizeString<StringSet>(getOr(drv.env, "passAsFile", ""));
|
||||
@@ -465,7 +468,7 @@ static void main_nix_build(int argc, char * * argv)
|
||||
for (const auto & [inputDrv, inputNode] : drv.inputDrvs.map)
|
||||
accumInputClosure(inputDrv, inputNode);
|
||||
|
||||
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(), drv);
|
||||
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(*state), drv);
|
||||
|
||||
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
|
||||
auto json = structAttrs.value();
|
||||
@@ -488,42 +491,51 @@ static void main_nix_build(int argc, char * * argv)
|
||||
environment variables and shell functions. Also don't
|
||||
lose the current $PATH directories. */
|
||||
auto rcfile = (Path) tmpDir + "/rc";
|
||||
auto tz = getEnv("TZ");
|
||||
std::string rc = fmt(
|
||||
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"s +
|
||||
(keepTmp ?
|
||||
"trap _nix_shell_clean_tmpdir EXIT; "
|
||||
"exitHooks+=(_nix_shell_clean_tmpdir); "
|
||||
"failureHooks+=(_nix_shell_clean_tmpdir); ":
|
||||
"_nix_shell_clean_tmpdir; ") +
|
||||
(pure ? "" : "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;") +
|
||||
"%2%"
|
||||
// always clear PATH.
|
||||
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
|
||||
"unset PATH;"
|
||||
"dontAddDisableDepTrack=1;\n"
|
||||
+ structuredAttrsRC +
|
||||
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
|
||||
"%3%"
|
||||
"PATH=%4%:\"$PATH\"; "
|
||||
"SHELL=%5%; "
|
||||
"BASH=%5%; "
|
||||
"set +e; "
|
||||
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && )s" +
|
||||
(getuid() == 0 ? R"s(PS1='\n\[\033[1;31m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
||||
: R"s(PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s") +
|
||||
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
||||
"unset NIX_ENFORCE_PURITY; "
|
||||
"shopt -u nullglob; "
|
||||
"unset TZ; %6%"
|
||||
"shopt -s execfail;"
|
||||
"%7%",
|
||||
shellEscape(tmpDir),
|
||||
(pure ? "" : "p=$PATH; "),
|
||||
(pure ? "" : "PATH=$PATH:$p; unset p; "),
|
||||
shellEscape(dirOf(*shell)),
|
||||
shellEscape(*shell),
|
||||
(getenv("TZ") ? (std::string("export TZ=") + shellEscape(getenv("TZ")) + "; ") : ""),
|
||||
envCommand);
|
||||
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"
|
||||
"%2%"
|
||||
"%3%"
|
||||
// always clear PATH.
|
||||
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
|
||||
"unset PATH;"
|
||||
"dontAddDisableDepTrack=1;\n",
|
||||
shellEscape(tmpDir),
|
||||
(keepTmp
|
||||
? "trap _nix_shell_clean_tmpdir EXIT; "
|
||||
"exitHooks+=(_nix_shell_clean_tmpdir); "
|
||||
"failureHooks+=(_nix_shell_clean_tmpdir); "
|
||||
: "_nix_shell_clean_tmpdir; "),
|
||||
(pure
|
||||
? ""
|
||||
: "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc; p=$PATH; ")
|
||||
);
|
||||
rc += structuredAttrsRC;
|
||||
rc += fmt(
|
||||
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
|
||||
"%1%"
|
||||
"PATH=%2%:\"$PATH\"; "
|
||||
"SHELL=%3%; "
|
||||
"BASH=%3%; "
|
||||
"set +e; "
|
||||
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && )s"
|
||||
"%4%"
|
||||
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
||||
"unset NIX_ENFORCE_PURITY; "
|
||||
"shopt -u nullglob; "
|
||||
"unset TZ; %5%"
|
||||
"shopt -s execfail;"
|
||||
"%6%",
|
||||
(pure ? "" : "PATH=$PATH:$p; unset p; "),
|
||||
shellEscape(dirOf(*shell)),
|
||||
shellEscape(*shell),
|
||||
(getuid() == 0 ? R"s(PS1='\n\[\033[1;31m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
||||
: R"s(PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s"),
|
||||
(tz.has_value()
|
||||
? (std::string("export TZ=") + shellEscape(*tz) + "; ")
|
||||
: ""),
|
||||
envCommand
|
||||
);
|
||||
vomit("Sourcing nix-shell with file %s and contents:\n%s", rcfile, rc);
|
||||
writeFile(rcfile, rc);
|
||||
|
||||
@@ -559,9 +571,9 @@ static void main_nix_build(int argc, char * * argv)
|
||||
std::map<StorePath, std::pair<size_t, StringSet>> drvMap;
|
||||
|
||||
for (auto & drvInfo : drvs) {
|
||||
auto drvPath = drvInfo.requireDrvPath();
|
||||
auto drvPath = drvInfo.requireDrvPath(*state);
|
||||
|
||||
auto outputName = drvInfo.queryOutputName();
|
||||
auto outputName = drvInfo.queryOutputName(*state);
|
||||
if (outputName == "")
|
||||
throw Error("derivation '%s' lacks an 'outputName' attribute", store->printStorePath(drvPath));
|
||||
|
||||
@@ -613,5 +625,9 @@ static void main_nix_build(int argc, char * * argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_build("nix-build", main_nix_build);
|
||||
static RegisterLegacyCommand r_nix_shell("nix-shell", main_nix_build);
|
||||
void registerNixBuildAndNixShell() {
|
||||
LegacyCommands::add("nix-build", main_nix_build);
|
||||
LegacyCommands::add("nix-shell", main_nix_build);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixBuildAndNixShell();
|
||||
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
#include "profiles.hh"
|
||||
#include "shared.hh"
|
||||
#include "globals.hh"
|
||||
#include "filetransfer.hh"
|
||||
#include "store-api.hh"
|
||||
#include "legacy.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "eval-settings.hh" // for defexpr
|
||||
#include "users.hh"
|
||||
#include "lix/libstore/profiles.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libstore/filetransfer.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libfetchers/fetchers.hh"
|
||||
#include "lix/libexpr/eval-settings.hh" // for defexpr
|
||||
#include "lix/libstore/temporary-dir.hh"
|
||||
#include "lix/libutil/users.hh"
|
||||
#include "nix-channel.hh"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <regex>
|
||||
#include <pwd.h>
|
||||
|
||||
using namespace nix;
|
||||
namespace nix {
|
||||
|
||||
typedef std::map<std::string, std::string> Channels;
|
||||
|
||||
@@ -160,7 +162,7 @@ static void update(const StringSet & channelNames)
|
||||
replaceSymlink(profile, channelLink);
|
||||
}
|
||||
|
||||
static int main_nix_channel(int argc, char ** argv)
|
||||
static int main_nix_channel(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
// Figure out the name of the `.nix-channels' file to use
|
||||
@@ -182,7 +184,7 @@ static int main_nix_channel(int argc, char ** argv)
|
||||
cRollback
|
||||
} cmd = cNone;
|
||||
std::vector<std::string> args;
|
||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help") {
|
||||
showManPage("nix-channel");
|
||||
} else if (*arg == "--version") {
|
||||
@@ -205,7 +207,7 @@ static int main_nix_channel(int argc, char ** argv)
|
||||
args.push_back(std::move(*arg));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}).parseCmdline(argv);
|
||||
|
||||
switch (cmd) {
|
||||
case cNone:
|
||||
@@ -264,4 +266,8 @@ static int main_nix_channel(int argc, char ** argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_channel("nix-channel", main_nix_channel);
|
||||
void registerNixChannel() {
|
||||
LegacyCommands::add("nix-channel", main_nix_channel);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixChannel();
|
||||
|
||||
}
|
||||
+19
-14
@@ -1,17 +1,18 @@
|
||||
#include "file-system.hh"
|
||||
#include "store-api.hh"
|
||||
#include "store-cast.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "profiles.hh"
|
||||
#include "shared.hh"
|
||||
#include "globals.hh"
|
||||
#include "legacy.hh"
|
||||
#include "signals.hh"
|
||||
#include "lix/libutil/file-system.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/store-cast.hh"
|
||||
#include "lix/libstore/gc-store.hh"
|
||||
#include "lix/libstore/profiles.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "nix-collect-garbage.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
|
||||
using namespace nix;
|
||||
namespace nix {
|
||||
|
||||
std::string deleteOlderThan;
|
||||
bool dryRun = false;
|
||||
@@ -55,14 +56,14 @@ void removeOldGenerations(std::string dir)
|
||||
}
|
||||
}
|
||||
|
||||
static int main_nix_collect_garbage(int argc, char * * argv)
|
||||
static int main_nix_collect_garbage(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
bool removeOld = false;
|
||||
|
||||
GCOptions options;
|
||||
|
||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help")
|
||||
showManPage("nix-collect-garbage");
|
||||
else if (*arg == "--version")
|
||||
@@ -78,7 +79,7 @@ static int main_nix_collect_garbage(int argc, char * * argv)
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}).parseCmdline(argv);
|
||||
|
||||
if (removeOld) {
|
||||
std::set<Path> dirsToClean = {
|
||||
@@ -110,4 +111,8 @@ static int main_nix_collect_garbage(int argc, char * * argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_collect_garbage("nix-collect-garbage", main_nix_collect_garbage);
|
||||
void registerNixCollectGarbage() {
|
||||
LegacyCommands::add("nix-collect-garbage", main_nix_collect_garbage);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixCollectGarbage();
|
||||
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "legacy.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "nix-copy-closure.hh"
|
||||
|
||||
using namespace nix;
|
||||
namespace nix {
|
||||
|
||||
static int main_nix_copy_closure(int argc, char ** argv)
|
||||
static int main_nix_copy_closure(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
auto gzip = false;
|
||||
@@ -15,7 +16,7 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||
std::string sshHost;
|
||||
PathSet storePaths;
|
||||
|
||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help")
|
||||
showManPage("nix-copy-closure");
|
||||
else if (*arg == "--version")
|
||||
@@ -41,7 +42,7 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||
else
|
||||
storePaths.insert(*arg);
|
||||
return true;
|
||||
});
|
||||
}).parseCmdline(argv);
|
||||
|
||||
if (sshHost.empty())
|
||||
throw UsageError("no host name specified");
|
||||
@@ -60,4 +61,8 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_copy_closure("nix-copy-closure", main_nix_copy_closure);
|
||||
void registerNixCopyClosure() {
|
||||
LegacyCommands::add("nix-copy-closure", main_nix_copy_closure);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixCopyClosure();
|
||||
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
#include "attr-path.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "derivations.hh"
|
||||
#include "terminal.hh"
|
||||
#include "eval.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "globals.hh"
|
||||
#include "names.hh"
|
||||
#include "profiles.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "lix/libcmd/cmd-profiles.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libutil/terminal.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libstore/names.hh"
|
||||
#include "lix/libstore/profiles.hh"
|
||||
#include "lix/libstore/path-with-outputs.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "user-env.hh"
|
||||
#include "users.hh"
|
||||
#include "value-to-json.hh"
|
||||
#include "xml-writer.hh"
|
||||
#include "legacy.hh"
|
||||
#include "eval-settings.hh" // for defexpr
|
||||
#include "lix/libutil/users.hh"
|
||||
#include "lix/libexpr/value-to-json.hh"
|
||||
#include "lix/libutil/xml-writer.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libexpr/eval-settings.hh" // for defexpr
|
||||
#include "nix-env.hh"
|
||||
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
@@ -28,9 +30,10 @@
|
||||
#include <unistd.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nix;
|
||||
using std::cout;
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
typedef enum {
|
||||
srcNixExprDrvs,
|
||||
@@ -56,7 +59,7 @@ struct Globals
|
||||
{
|
||||
InstallSourceInfo instSource;
|
||||
Path profile;
|
||||
std::shared_ptr<EvalState> state;
|
||||
std::shared_ptr<Evaluator> state;
|
||||
bool dryRun;
|
||||
bool preserveInstalled;
|
||||
bool removeAll;
|
||||
@@ -93,19 +96,24 @@ static bool parseInstallSourceOptions(Globals & globals,
|
||||
}
|
||||
|
||||
|
||||
static bool isNixExpr(const SourcePath & path, struct InputAccessor::Stat & st)
|
||||
static bool isNixExpr(EvalPaths & paths, const CheckedSourcePath & path, struct InputAccessor::Stat & st)
|
||||
{
|
||||
return
|
||||
st.type == InputAccessor::tRegular
|
||||
|| (st.type == InputAccessor::tDirectory && (path + "default.nix").pathExists());
|
||||
if (st.type == InputAccessor::tRegular) {
|
||||
return true;
|
||||
} else if (st.type != InputAccessor::tDirectory) {
|
||||
return false;
|
||||
} else {
|
||||
auto defaultNix = paths.checkSourcePath(path + "default.nix");
|
||||
return defaultNix.pathExists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static constexpr size_t maxAttrs = 1024;
|
||||
|
||||
|
||||
static void getAllExprs(EvalState & state,
|
||||
const SourcePath & path, StringSet & seen, BindingsBuilder & attrs)
|
||||
static void getAllExprs(Evaluator & state,
|
||||
const CheckedSourcePath & path, StringSet & seen, BindingsBuilder & attrs)
|
||||
{
|
||||
StringSet namesSorted;
|
||||
for (auto & [name, _] : path.readDirectory()) namesSorted.insert(name);
|
||||
@@ -116,16 +124,16 @@ static void getAllExprs(EvalState & state,
|
||||
are implemented using profiles). */
|
||||
if (i == "manifest.nix") continue;
|
||||
|
||||
SourcePath path2 = path + i;
|
||||
auto path2 = state.paths.checkSourcePath(path + i);
|
||||
|
||||
InputAccessor::Stat st;
|
||||
try {
|
||||
st = path2.resolveSymlinks().lstat();
|
||||
st = path2.stat();
|
||||
} catch (Error &) {
|
||||
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
||||
}
|
||||
|
||||
if (isNixExpr(path2, st) && (st.type != InputAccessor::tRegular || path2.baseName().ends_with(".nix"))) {
|
||||
if (isNixExpr(state.paths, path2, st) && (st.type != InputAccessor::tRegular || path2.baseName().ends_with(".nix"))) {
|
||||
/* Strip off the `.nix' filename suffix (if applicable),
|
||||
otherwise the attribute cannot be selected with the
|
||||
`-A' option. Useful if you want to stick a Nix
|
||||
@@ -135,18 +143,18 @@ static void getAllExprs(EvalState & state,
|
||||
attrName = std::string(attrName, 0, attrName.size() - 4);
|
||||
if (!seen.insert(attrName).second) {
|
||||
std::string suggestionMessage = "";
|
||||
if (path2.path.abs().find("channels") != std::string::npos && path.path.abs().find("channels") != std::string::npos)
|
||||
if (path2.to_string().find("channels") != std::string::npos && path.to_string().find("channels") != std::string::npos)
|
||||
suggestionMessage = fmt("\nsuggestion: remove '%s' from either the root channels or the user channels", attrName);
|
||||
printError("warning: name collision in input Nix expressions, skipping '%1%'"
|
||||
"%2%", path2, suggestionMessage);
|
||||
continue;
|
||||
}
|
||||
/* Load the expression on demand. */
|
||||
auto vArg = state.allocValue();
|
||||
vArg->mkString(path2.path.abs());
|
||||
auto vArg = state.mem.allocValue();
|
||||
vArg->mkString(path2.canonical().abs());
|
||||
if (seen.size() == maxAttrs)
|
||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
||||
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg);
|
||||
attrs.alloc(attrName).mkApp(&state.builtins.get("import"), vArg);
|
||||
}
|
||||
else if (st.type == InputAccessor::tDirectory)
|
||||
/* `path2' is a directory (with no default.nix in it);
|
||||
@@ -157,11 +165,12 @@ static void getAllExprs(EvalState & state,
|
||||
|
||||
|
||||
|
||||
static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v)
|
||||
static void loadSourceExpr(EvalState & state, const SourcePath & path_, Value & v)
|
||||
{
|
||||
auto st = path.resolveSymlinks().lstat();
|
||||
auto path = state.ctx.paths.checkSourcePath(path_);
|
||||
auto st = path.stat();
|
||||
|
||||
if (isNixExpr(path, st))
|
||||
if (isNixExpr(state.ctx.paths, path, st))
|
||||
state.evalFile(path, v);
|
||||
|
||||
/* The path is a directory. Put the Nix expressions in the
|
||||
@@ -171,10 +180,10 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v
|
||||
~/.nix-defexpr directory that includes some system-wide
|
||||
directory). */
|
||||
else if (st.type == InputAccessor::tDirectory) {
|
||||
auto attrs = state.buildBindings(maxAttrs);
|
||||
auto attrs = state.ctx.buildBindings(maxAttrs);
|
||||
attrs.alloc("_combineChannels").mkList(0);
|
||||
StringSet seen;
|
||||
getAllExprs(state, path, seen, attrs);
|
||||
getAllExprs(state.ctx, path, seen, attrs);
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
||||
@@ -197,7 +206,7 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
|
||||
system. */
|
||||
for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) {
|
||||
j = i; j++;
|
||||
if (systemFilter != "*" && i->querySystem() != systemFilter)
|
||||
if (systemFilter != "*" && i->querySystem(state) != systemFilter)
|
||||
elems.erase(i);
|
||||
}
|
||||
}
|
||||
@@ -205,7 +214,7 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
|
||||
|
||||
static NixInt getPriority(EvalState & state, DrvInfo & drv)
|
||||
{
|
||||
return drv.queryMetaInt("priority", NixInt(0));
|
||||
return drv.queryMetaInt(state, "priority", NixInt(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -219,9 +228,9 @@ static std::strong_ordering comparePriorities(EvalState & state, DrvInfo & drv1,
|
||||
// at a time.
|
||||
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
||||
{
|
||||
auto path = elem.queryOutPath();
|
||||
if (state.store->isValidPath(path)) return true;
|
||||
return state.store->querySubstitutablePaths({path}).count(path);
|
||||
auto path = elem.queryOutPath(state);
|
||||
if (state.ctx.store->isValidPath(path)) return true;
|
||||
return state.ctx.store->querySubstitutablePaths({path}).count(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -236,11 +245,11 @@ static void checkSelectorUse(DrvNames & selectors)
|
||||
|
||||
namespace {
|
||||
|
||||
std::set<std::string> searchByPrefix(DrvInfos & allElems, std::string_view prefix) {
|
||||
std::set<std::string> searchByPrefix(EvalState & state, DrvInfos & allElems, std::string_view prefix) {
|
||||
constexpr std::size_t maxResults = 3;
|
||||
std::set<std::string> result;
|
||||
for (auto & drvInfo : allElems) {
|
||||
const auto drvName = DrvName { drvInfo.queryName() };
|
||||
const auto drvName = DrvName { drvInfo.queryName(state) };
|
||||
if (drvName.name.starts_with(prefix)) {
|
||||
result.emplace(drvName.name);
|
||||
|
||||
@@ -278,7 +287,7 @@ std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches)
|
||||
for (auto & match : matches) {
|
||||
auto & oneDrv = match.drvInfo;
|
||||
|
||||
const auto drvName = DrvName { oneDrv.queryName() };
|
||||
const auto drvName = DrvName { oneDrv.queryName(state) };
|
||||
std::strong_ordering comparison = std::strong_ordering::greater;
|
||||
|
||||
const auto itOther = newest.find(drvName.name);
|
||||
@@ -287,13 +296,13 @@ std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches)
|
||||
auto & newestDrv = itOther->second.drvInfo;
|
||||
|
||||
comparison =
|
||||
oneDrv.querySystem() == newestDrv.querySystem() ? std::strong_ordering::equal :
|
||||
oneDrv.querySystem() == settings.thisSystem ? std::strong_ordering::greater :
|
||||
newestDrv.querySystem() == settings.thisSystem ? std::strong_ordering::less : std::strong_ordering::equal;
|
||||
oneDrv.querySystem(state) == newestDrv.querySystem(state) ? std::strong_ordering::equal :
|
||||
oneDrv.querySystem(state) == settings.thisSystem ? std::strong_ordering::greater :
|
||||
newestDrv.querySystem(state) == settings.thisSystem ? std::strong_ordering::less : std::strong_ordering::equal;
|
||||
if (comparison == 0)
|
||||
comparison = comparePriorities(state, oneDrv, newestDrv);
|
||||
if (comparison == 0)
|
||||
comparison = compareVersions(drvName.version, DrvName { newestDrv.queryName() }.version);
|
||||
comparison = compareVersions(drvName.version, DrvName{newestDrv.queryName(state)}.version);
|
||||
}
|
||||
|
||||
if (comparison > 0) {
|
||||
@@ -332,7 +341,7 @@ static DrvInfos filterBySelector(EvalState & state, DrvInfos & allElems,
|
||||
for (auto & selector : selectors) {
|
||||
std::vector<Match> matches;
|
||||
for (auto && [index, drvInfo] : enumerate(allElems)) {
|
||||
const auto drvName = DrvName { drvInfo.queryName() };
|
||||
const auto drvName = DrvName { drvInfo.queryName(state) };
|
||||
if (selector.matches(drvName)) {
|
||||
++selector.hits;
|
||||
matches.emplace_back(drvInfo, index);
|
||||
@@ -350,7 +359,7 @@ static DrvInfos filterBySelector(EvalState & state, DrvInfos & allElems,
|
||||
elems.push_back(match.drvInfo);
|
||||
|
||||
if (selector.hits == 0 && selector.fullName != "*") {
|
||||
const auto prefixHits = searchByPrefix(allElems, selector.name);
|
||||
const auto prefixHits = searchByPrefix(state, allElems, selector.name);
|
||||
|
||||
if (prefixHits.empty()) {
|
||||
throw Error("selector '%1%' matches no derivations", selector.fullName);
|
||||
@@ -413,7 +422,7 @@ static void queryInstSources(EvalState & state,
|
||||
loadSourceExpr(state, *instSource.nixExprPath, vArg);
|
||||
|
||||
for (auto & i : args) {
|
||||
Expr & eFun = state.parseExprFromString(i, state.rootPath(CanonPath::fromCwd()));
|
||||
Expr & eFun = state.ctx.parseExprFromString(i, CanonPath::fromCwd());
|
||||
Value vFun, vTmp;
|
||||
state.eval(eFun, vFun);
|
||||
vTmp.mkApp(&vFun, &vArg);
|
||||
@@ -429,16 +438,16 @@ static void queryInstSources(EvalState & state,
|
||||
case srcStorePaths: {
|
||||
|
||||
for (auto & i : args) {
|
||||
auto path = state.store->followLinksToStorePath(i);
|
||||
auto path = state.ctx.store->followLinksToStorePath(i);
|
||||
|
||||
std::string name(path.name());
|
||||
|
||||
DrvInfo elem(state, "", nullptr);
|
||||
DrvInfo elem("", nullptr);
|
||||
elem.setName(name);
|
||||
|
||||
if (path.isDerivation()) {
|
||||
elem.setDrvPath(path);
|
||||
auto outputs = state.store->queryDerivationOutputMap(path);
|
||||
auto outputs = state.ctx.store->queryDerivationOutputMap(path);
|
||||
elem.setOutPath(outputs.at("out"));
|
||||
if (name.size() >= drvExtension.size() &&
|
||||
std::string(name, name.size() - drvExtension.size()) == drvExtension)
|
||||
@@ -483,23 +492,23 @@ static void printMissing(EvalState & state, DrvInfos & elems)
|
||||
{
|
||||
std::vector<DerivedPath> targets;
|
||||
for (auto & i : elems)
|
||||
if (auto drvPath = i.queryDrvPath())
|
||||
if (auto drvPath = i.queryDrvPath(state))
|
||||
targets.emplace_back(DerivedPath::Built{
|
||||
.drvPath = makeConstantStorePathRef(*drvPath),
|
||||
.outputs = OutputsSpec::All { },
|
||||
});
|
||||
else
|
||||
targets.emplace_back(DerivedPath::Opaque{
|
||||
.path = i.queryOutPath(),
|
||||
.path = i.queryOutPath(state),
|
||||
});
|
||||
|
||||
printMissing(state.store, targets);
|
||||
printMissing(state.ctx.store, targets);
|
||||
}
|
||||
|
||||
|
||||
static bool keep(DrvInfo & drv)
|
||||
static bool keep(EvalState & state, DrvInfo & drv)
|
||||
{
|
||||
return drv.queryMetaBool("keep", false);
|
||||
return drv.queryMetaBool(state, "keep", false);
|
||||
}
|
||||
|
||||
|
||||
@@ -508,13 +517,15 @@ static void installDerivations(Globals & globals,
|
||||
{
|
||||
debug("installing derivations");
|
||||
|
||||
auto state = globals.state->begin();
|
||||
|
||||
/* Get the set of user environment elements to be installed. */
|
||||
DrvInfos newElems, newElemsTmp;
|
||||
queryInstSources(*globals.state, globals.instSource, args, newElemsTmp, true);
|
||||
queryInstSources(*state, globals.instSource, args, newElemsTmp, true);
|
||||
|
||||
/* If --prebuilt-only is given, filter out source-only packages. */
|
||||
for (auto & i : newElemsTmp)
|
||||
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, i))
|
||||
if (!globals.prebuiltOnly || isPrebuilt(*state, i))
|
||||
newElems.push_back(i);
|
||||
|
||||
StringSet newNames;
|
||||
@@ -525,7 +536,7 @@ static void installDerivations(Globals & globals,
|
||||
`java-front-0.9pre15899'). */
|
||||
if (globals.forceName != "")
|
||||
i.setName(globals.forceName);
|
||||
newNames.insert(DrvName(i.queryName()).name);
|
||||
newNames.insert(DrvName(i.queryName(*state)).name);
|
||||
}
|
||||
|
||||
|
||||
@@ -537,27 +548,27 @@ static void installDerivations(Globals & globals,
|
||||
/* Add in the already installed derivations, unless they have
|
||||
the same name as a to-be-installed element. */
|
||||
if (!globals.removeAll) {
|
||||
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
||||
DrvInfos installedElems = queryInstalled(*state, profile);
|
||||
|
||||
for (auto & i : installedElems) {
|
||||
DrvName drvName(i.queryName());
|
||||
DrvName drvName(i.queryName(*state));
|
||||
if (!globals.preserveInstalled &&
|
||||
newNames.find(drvName.name) != newNames.end() &&
|
||||
!keep(i))
|
||||
printInfo("replacing old '%s'", i.queryName());
|
||||
!keep(*state, i))
|
||||
printInfo("replacing old '%s'", i.queryName(*state));
|
||||
else
|
||||
allElems.push_back(i);
|
||||
}
|
||||
|
||||
for (auto & i : newElems)
|
||||
printInfo("installing '%s'", i.queryName());
|
||||
printInfo("installing '%s'", i.queryName(*state));
|
||||
}
|
||||
|
||||
printMissing(*globals.state, newElems);
|
||||
printMissing(*state, newElems);
|
||||
|
||||
if (globals.dryRun) return;
|
||||
|
||||
if (createUserEnv(*globals.state, allElems,
|
||||
if (createUserEnv(*state, allElems,
|
||||
profile, settings.envKeepDerivations, lockToken)) break;
|
||||
}
|
||||
}
|
||||
@@ -587,6 +598,8 @@ static void upgradeDerivations(Globals & globals,
|
||||
{
|
||||
debug("upgrading derivations");
|
||||
|
||||
auto state = globals.state->begin();
|
||||
|
||||
/* Upgrade works as follows: we take all currently installed
|
||||
derivations, and for any derivation matching any selector, look
|
||||
for a derivation in the input Nix expression that has the same
|
||||
@@ -595,20 +608,20 @@ static void upgradeDerivations(Globals & globals,
|
||||
while (true) {
|
||||
auto lockToken = optimisticLockProfile(globals.profile);
|
||||
|
||||
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
|
||||
DrvInfos installedElems = queryInstalled(*state, globals.profile);
|
||||
|
||||
/* Fetch all derivations from the input file. */
|
||||
DrvInfos availElems;
|
||||
queryInstSources(*globals.state, globals.instSource, args, availElems, false);
|
||||
queryInstSources(*state, globals.instSource, args, availElems, false);
|
||||
|
||||
/* Go through all installed derivations. */
|
||||
DrvInfos newElems;
|
||||
for (auto & i : installedElems) {
|
||||
DrvName drvName(i.queryName());
|
||||
DrvName drvName(i.queryName(*state));
|
||||
|
||||
try {
|
||||
|
||||
if (keep(i)) {
|
||||
if (keep(*state, i)) {
|
||||
newElems.push_back(i);
|
||||
continue;
|
||||
}
|
||||
@@ -623,9 +636,9 @@ static void upgradeDerivations(Globals & globals,
|
||||
DrvInfos::iterator bestElem = availElems.end();
|
||||
std::string bestVersion;
|
||||
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
|
||||
if (comparePriorities(*globals.state, i, *j) > 0)
|
||||
if (comparePriorities(*state, i, *j) > 0)
|
||||
continue;
|
||||
DrvName newName(j->queryName());
|
||||
DrvName newName(j->queryName(*state));
|
||||
if (newName.name == drvName.name) {
|
||||
std::strong_ordering d = compareVersions(drvName.version, newName.version);
|
||||
if ((upgradeType == utLt && d < 0) ||
|
||||
@@ -635,10 +648,10 @@ static void upgradeDerivations(Globals & globals,
|
||||
{
|
||||
std::strong_ordering d2 = std::strong_ordering::less;
|
||||
if (bestElem != availElems.end()) {
|
||||
d2 = comparePriorities(*globals.state, *bestElem, *j);
|
||||
d2 = comparePriorities(*state, *bestElem, *j);
|
||||
if (d2 == 0) d2 = compareVersions(bestVersion, newName.version);
|
||||
}
|
||||
if (d2 < 0 && (!globals.prebuiltOnly || isPrebuilt(*globals.state, *j))) {
|
||||
if (d2 < 0 && (!globals.prebuiltOnly || isPrebuilt(*state, *j))) {
|
||||
bestElem = j;
|
||||
bestVersion = newName.version;
|
||||
}
|
||||
@@ -647,27 +660,27 @@ static void upgradeDerivations(Globals & globals,
|
||||
}
|
||||
|
||||
if (bestElem != availElems.end() &&
|
||||
i.queryOutPath() !=
|
||||
bestElem->queryOutPath())
|
||||
i.queryOutPath(*state) !=
|
||||
bestElem->queryOutPath(*state))
|
||||
{
|
||||
const char * action = compareVersions(drvName.version, bestVersion) <= 0
|
||||
? "upgrading" : "downgrading";
|
||||
printInfo("%1% '%2%' to '%3%'",
|
||||
action, i.queryName(), bestElem->queryName());
|
||||
action, i.queryName(*state), bestElem->queryName(*state));
|
||||
newElems.push_back(*bestElem);
|
||||
} else newElems.push_back(i);
|
||||
|
||||
} catch (Error & e) {
|
||||
e.addTrace(nullptr, "while trying to find an upgrade for '%s'", i.queryName());
|
||||
e.addTrace(nullptr, "while trying to find an upgrade for '%s'", i.queryName(*state));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
printMissing(*globals.state, newElems);
|
||||
printMissing(*state, newElems);
|
||||
|
||||
if (globals.dryRun) return;
|
||||
|
||||
if (createUserEnv(*globals.state, newElems,
|
||||
if (createUserEnv(*state, newElems,
|
||||
globals.profile, settings.envKeepDerivations, lockToken)) break;
|
||||
}
|
||||
}
|
||||
@@ -693,9 +706,9 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
||||
const std::string & name, const std::string & value)
|
||||
{
|
||||
auto v = state.allocValue();
|
||||
auto v = state.ctx.mem.allocValue();
|
||||
v->mkString(value);
|
||||
drv.setMeta(name, v);
|
||||
drv.setMeta(state, name, v);
|
||||
}
|
||||
|
||||
|
||||
@@ -711,19 +724,21 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
std::string flagValue = *arg++;
|
||||
DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end()));
|
||||
|
||||
auto state = globals.state->begin();
|
||||
|
||||
while (true) {
|
||||
std::string lockToken = optimisticLockProfile(globals.profile);
|
||||
|
||||
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
|
||||
DrvInfos installedElems = queryInstalled(*state, globals.profile);
|
||||
|
||||
/* Update all matching derivations. */
|
||||
for (auto & i : installedElems) {
|
||||
DrvName drvName(i.queryName());
|
||||
DrvName drvName(i.queryName(*state));
|
||||
for (auto & j : selectors)
|
||||
if (j.matches(drvName)) {
|
||||
printInfo("setting flag on '%1%'", i.queryName());
|
||||
printInfo("setting flag on '%1%'", i.queryName(*state));
|
||||
j.hits++;
|
||||
setMetaFlag(*globals.state, i, flagName, flagValue);
|
||||
setMetaFlag(*state, i, flagName, flagValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -731,7 +746,7 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
checkSelectorUse(selectors);
|
||||
|
||||
/* Write the new user environment. */
|
||||
if (createUserEnv(*globals.state, installedElems,
|
||||
if (createUserEnv(*state, installedElems,
|
||||
globals.profile, settings.envKeepDerivations, lockToken)) break;
|
||||
}
|
||||
}
|
||||
@@ -739,6 +754,8 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
|
||||
static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
{
|
||||
auto state = globals.state->begin();
|
||||
|
||||
auto store2 = globals.state->store.dynamic_pointer_cast<LocalFSStore>();
|
||||
if (!store2) throw Error("--set is not supported for this Nix store");
|
||||
|
||||
@@ -749,7 +766,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
}
|
||||
|
||||
DrvInfos elems;
|
||||
queryInstSources(*globals.state, globals.instSource, opArgs, elems, true);
|
||||
queryInstSources(*state, globals.instSource, opArgs, elems, true);
|
||||
|
||||
if (elems.size() != 1)
|
||||
throw Error("--set requires exactly one derivation");
|
||||
@@ -759,7 +776,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
if (globals.forceName != "")
|
||||
drv.setName(globals.forceName);
|
||||
|
||||
auto drvPath = drv.queryDrvPath();
|
||||
auto drvPath = drv.queryDrvPath(*state);
|
||||
std::vector<DerivedPath> paths {
|
||||
drvPath
|
||||
? (DerivedPath) (DerivedPath::Built {
|
||||
@@ -767,7 +784,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
.outputs = OutputsSpec::All { },
|
||||
})
|
||||
: (DerivedPath) (DerivedPath::Opaque {
|
||||
.path = drv.queryOutPath(),
|
||||
.path = drv.queryOutPath(*state),
|
||||
}),
|
||||
};
|
||||
printMissing(globals.state->store, paths);
|
||||
@@ -778,7 +795,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
Path generation = createGeneration(
|
||||
*store2,
|
||||
globals.profile,
|
||||
drv.queryOutPath());
|
||||
drv.queryOutPath(*state));
|
||||
switchLink(globals.profile, generation);
|
||||
}
|
||||
|
||||
@@ -786,10 +803,12 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
static void uninstallDerivations(Globals & globals, Strings & selectors,
|
||||
Path & profile)
|
||||
{
|
||||
auto state = globals.state->begin();
|
||||
|
||||
while (true) {
|
||||
auto lockToken = optimisticLockProfile(profile);
|
||||
|
||||
DrvInfos workingElems = queryInstalled(*globals.state, profile);
|
||||
DrvInfos workingElems = queryInstalled(*state, profile);
|
||||
|
||||
for (auto & selector : selectors) {
|
||||
DrvInfos::iterator split = workingElems.begin();
|
||||
@@ -797,16 +816,16 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
||||
StorePath selectorStorePath = globals.state->store->followLinksToStorePath(selector);
|
||||
split = std::partition(
|
||||
workingElems.begin(), workingElems.end(),
|
||||
[&selectorStorePath, globals](auto &elem) {
|
||||
return selectorStorePath != elem.queryOutPath();
|
||||
[&selectorStorePath, &state](auto &elem) {
|
||||
return selectorStorePath != elem.queryOutPath(*state);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
DrvName selectorName(selector);
|
||||
split = std::partition(
|
||||
workingElems.begin(), workingElems.end(),
|
||||
[&selectorName](auto &elem){
|
||||
DrvName elemName(elem.queryName());
|
||||
[&selectorName, &state](auto &elem){
|
||||
DrvName elemName(elem.queryName(*state));
|
||||
return !selectorName.matches(elemName);
|
||||
}
|
||||
);
|
||||
@@ -814,14 +833,14 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
||||
if (split == workingElems.end())
|
||||
warn("selector '%s' matched no installed derivations", selector);
|
||||
for (auto removedElem = split; removedElem != workingElems.end(); removedElem++) {
|
||||
printInfo("uninstalling '%s'", removedElem->queryName());
|
||||
printInfo("uninstalling '%s'", removedElem->queryName(*state));
|
||||
}
|
||||
workingElems.erase(split, workingElems.end());
|
||||
}
|
||||
|
||||
if (globals.dryRun) return;
|
||||
|
||||
if (createUserEnv(*globals.state, workingElems,
|
||||
if (createUserEnv(*state, workingElems,
|
||||
profile, settings.envKeepDerivations, lockToken)) break;
|
||||
}
|
||||
}
|
||||
@@ -841,10 +860,10 @@ static bool cmpChars(char a, char b)
|
||||
}
|
||||
|
||||
|
||||
static bool cmpElemByName(DrvInfo & a, DrvInfo & b)
|
||||
static bool cmpElemByName(EvalState & state, DrvInfo & a, DrvInfo & b)
|
||||
{
|
||||
auto a_name = a.queryName();
|
||||
auto b_name = b.queryName();
|
||||
auto a_name = a.queryName(state);
|
||||
auto b_name = b.queryName(state);
|
||||
return lexicographical_compare(
|
||||
a_name.begin(), a_name.end(),
|
||||
b_name.begin(), b_name.end(), cmpChars);
|
||||
@@ -894,15 +913,15 @@ void printTable(Table & table)
|
||||
typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff;
|
||||
|
||||
static VersionDiff compareVersionAgainstSet(
|
||||
DrvInfo & elem, DrvInfos & elems, std::string & version)
|
||||
EvalState & state, DrvInfo & elem, DrvInfos & elems, std::string & version)
|
||||
{
|
||||
DrvName name(elem.queryName());
|
||||
DrvName name(elem.queryName(state));
|
||||
|
||||
VersionDiff diff = cvUnavail;
|
||||
version = "?";
|
||||
|
||||
for (auto & i : elems) {
|
||||
DrvName name2(i.queryName());
|
||||
DrvName name2(i.queryName(state));
|
||||
if (name.name == name2.name) {
|
||||
std::strong_ordering d = compareVersions(name.version, name2.version);
|
||||
if (d < 0) {
|
||||
@@ -925,7 +944,7 @@ static VersionDiff compareVersionAgainstSet(
|
||||
}
|
||||
|
||||
|
||||
static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printDrvPath, bool printMeta)
|
||||
static void queryJSON(EvalState & state, Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printDrvPath, bool printMeta)
|
||||
{
|
||||
using nlohmann::json;
|
||||
json topObj = json::object();
|
||||
@@ -934,18 +953,18 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
||||
if (i.hasFailed()) continue;
|
||||
|
||||
|
||||
auto drvName = DrvName(i.queryName());
|
||||
auto drvName = DrvName(i.queryName(state));
|
||||
json &pkgObj = topObj[i.attrPath];
|
||||
pkgObj = {
|
||||
{"name", drvName.fullName},
|
||||
{"pname", drvName.name},
|
||||
{"version", drvName.version},
|
||||
{"system", i.querySystem()},
|
||||
{"outputName", i.queryOutputName()},
|
||||
{"system", i.querySystem(state)},
|
||||
{"outputName", i.queryOutputName(state)},
|
||||
};
|
||||
|
||||
{
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(state, printOutPath);
|
||||
json &outputObj = pkgObj["outputs"];
|
||||
outputObj = json::object();
|
||||
for (auto & j : outputs) {
|
||||
@@ -957,29 +976,29 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
||||
}
|
||||
|
||||
if (printDrvPath) {
|
||||
auto drvPath = i.queryDrvPath();
|
||||
auto drvPath = i.queryDrvPath(state);
|
||||
if (drvPath) pkgObj["drvPath"] = globals.state->store->printStorePath(*drvPath);
|
||||
}
|
||||
|
||||
if (printMeta) {
|
||||
json &metaObj = pkgObj["meta"];
|
||||
metaObj = json::object();
|
||||
StringSet metaNames = i.queryMetaNames();
|
||||
StringSet metaNames = i.queryMetaNames(state);
|
||||
for (auto & j : metaNames) {
|
||||
Value * v = i.queryMeta(j);
|
||||
Value * v = i.queryMeta(state, j);
|
||||
if (!v) {
|
||||
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
|
||||
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(state), j);
|
||||
metaObj[j] = nullptr;
|
||||
} else {
|
||||
NixStringContext context;
|
||||
metaObj[j] = printValueAsJSON(*globals.state, true, *v, noPos, context);
|
||||
metaObj[j] = printValueAsJSON(state, true, *v, noPos, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (AssertionError & e) {
|
||||
printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName());
|
||||
printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName(state));
|
||||
} catch (Error & e) {
|
||||
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName());
|
||||
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName(state));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -990,6 +1009,7 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
||||
static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
{
|
||||
auto & store { *globals.state->store };
|
||||
auto state = globals.state->begin();
|
||||
|
||||
Strings remaining;
|
||||
std::string attrPath;
|
||||
@@ -1038,14 +1058,14 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
DrvInfos availElems, installedElems;
|
||||
|
||||
if (source == sInstalled || compareVersions || printStatus)
|
||||
installedElems = queryInstalled(*globals.state, globals.profile);
|
||||
installedElems = queryInstalled(*state, globals.profile);
|
||||
|
||||
if (source == sAvailable || compareVersions)
|
||||
loadDerivations(*globals.state, *globals.instSource.nixExprPath,
|
||||
loadDerivations(*state, *globals.instSource.nixExprPath,
|
||||
globals.instSource.systemFilter, *globals.instSource.autoArgs,
|
||||
attrPath, availElems);
|
||||
|
||||
DrvInfos elems_ = filterBySelector(*globals.state,
|
||||
DrvInfos elems_ = filterBySelector(*state,
|
||||
source == sInstalled ? installedElems : availElems,
|
||||
opArgs, false);
|
||||
|
||||
@@ -1056,8 +1076,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
/* !!! */
|
||||
std::vector<DrvInfo> elems;
|
||||
for (auto & i : elems_) elems.push_back(i);
|
||||
sort(elems.begin(), elems.end(), cmpElemByName);
|
||||
|
||||
sort(elems.begin(), elems.end(), [&] (auto& a, auto& b) { return cmpElemByName(*state, a, b); });
|
||||
|
||||
/* We only need to know the installed paths when we are querying
|
||||
the status of the derivation. */
|
||||
@@ -1065,7 +1084,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
|
||||
if (printStatus)
|
||||
for (auto & i : installedElems)
|
||||
installed.insert(i.queryOutPath());
|
||||
installed.insert(i.queryOutPath(*state));
|
||||
|
||||
|
||||
/* Query which paths have substitutes. */
|
||||
@@ -1075,9 +1094,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
StorePathSet paths;
|
||||
for (auto & i : elems)
|
||||
try {
|
||||
paths.insert(i.queryOutPath());
|
||||
paths.insert(i.queryOutPath(*state));
|
||||
} catch (AssertionError & e) {
|
||||
printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName());
|
||||
printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName(*state));
|
||||
i.setFailed();
|
||||
}
|
||||
validPaths = store.queryValidPaths(paths);
|
||||
@@ -1087,7 +1106,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
|
||||
/* Print the desired columns, or XML output. */
|
||||
if (jsonOutput) {
|
||||
queryJSON(globals, elems, printOutPath, printDrvPath, printMeta);
|
||||
queryJSON(*state, globals, elems, printOutPath, printDrvPath, printMeta);
|
||||
cout << '\n';
|
||||
return;
|
||||
}
|
||||
@@ -1106,8 +1125,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
//Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
|
||||
|
||||
if (globals.prebuiltOnly &&
|
||||
!validPaths.count(i.queryOutPath()) &&
|
||||
!substitutablePaths.count(i.queryOutPath()))
|
||||
!validPaths.count(i.queryOutPath(*state)) &&
|
||||
!substitutablePaths.count(i.queryOutPath(*state)))
|
||||
continue;
|
||||
|
||||
/* For table output. */
|
||||
@@ -1117,7 +1136,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
XMLAttrs attrs;
|
||||
|
||||
if (printStatus) {
|
||||
auto outPath = i.queryOutPath();
|
||||
auto outPath = i.queryOutPath(*state);
|
||||
bool hasSubs = substitutablePaths.count(outPath);
|
||||
bool isInstalled = installed.count(outPath);
|
||||
bool isValid = validPaths.count(outPath);
|
||||
@@ -1138,12 +1157,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
columns.push_back(i.attrPath);
|
||||
|
||||
if (xmlOutput) {
|
||||
auto drvName = DrvName(i.queryName());
|
||||
auto drvName = DrvName(i.queryName(*state));
|
||||
attrs["name"] = drvName.fullName;
|
||||
attrs["pname"] = drvName.name;
|
||||
attrs["version"] = drvName.version;
|
||||
} else if (printName) {
|
||||
columns.push_back(i.queryName());
|
||||
columns.push_back(i.queryName(*state));
|
||||
}
|
||||
|
||||
if (compareVersions) {
|
||||
@@ -1152,7 +1171,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
elements, or the set of installed elements. !!!
|
||||
This is O(N * M), should be O(N * lg M). */
|
||||
std::string version;
|
||||
VersionDiff diff = compareVersionAgainstSet(i, otherElems, version);
|
||||
VersionDiff diff = compareVersionAgainstSet(*state, i, otherElems, version);
|
||||
|
||||
char ch;
|
||||
switch (diff) {
|
||||
@@ -1177,13 +1196,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
}
|
||||
|
||||
if (xmlOutput) {
|
||||
if (i.querySystem() != "") attrs["system"] = i.querySystem();
|
||||
if (i.querySystem(*state) != "") attrs["system"] = i.querySystem(*state);
|
||||
}
|
||||
else if (printSystem)
|
||||
columns.push_back(i.querySystem());
|
||||
columns.push_back(i.querySystem(*state));
|
||||
|
||||
if (printDrvPath) {
|
||||
auto drvPath = i.queryDrvPath();
|
||||
auto drvPath = i.queryDrvPath(*state);
|
||||
if (xmlOutput) {
|
||||
if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
|
||||
} else
|
||||
@@ -1191,10 +1210,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
}
|
||||
|
||||
if (xmlOutput)
|
||||
attrs["outputName"] = i.queryOutputName();
|
||||
attrs["outputName"] = i.queryOutputName(*state);
|
||||
|
||||
if (printOutPath && !xmlOutput) {
|
||||
DrvInfo::Outputs outputs = i.queryOutputs();
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(*state);
|
||||
std::string s;
|
||||
for (auto & j : outputs) {
|
||||
if (!s.empty()) s += ';';
|
||||
@@ -1205,7 +1224,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
}
|
||||
|
||||
if (printDescription) {
|
||||
auto descr = i.queryMetaString("description");
|
||||
auto descr = i.queryMetaString(*state, "description");
|
||||
if (xmlOutput) {
|
||||
if (descr != "") attrs["description"] = descr;
|
||||
} else
|
||||
@@ -1214,7 +1233,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
|
||||
if (xmlOutput) {
|
||||
XMLOpenElement item(xml, "item", attrs);
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(*state, printOutPath);
|
||||
for (auto & j : outputs) {
|
||||
XMLAttrs attrs2;
|
||||
attrs2["name"] = j.first;
|
||||
@@ -1223,15 +1242,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
xml.writeEmptyElement("output", attrs2);
|
||||
}
|
||||
if (printMeta) {
|
||||
StringSet metaNames = i.queryMetaNames();
|
||||
StringSet metaNames = i.queryMetaNames(*state);
|
||||
for (auto & j : metaNames) {
|
||||
XMLAttrs attrs2;
|
||||
attrs2["name"] = j;
|
||||
Value * v = i.queryMeta(j);
|
||||
Value * v = i.queryMeta(*state, j);
|
||||
if (!v)
|
||||
printError(
|
||||
"derivation '%s' has invalid meta attribute '%s'",
|
||||
i.queryName(), j);
|
||||
i.queryName(*state), j);
|
||||
else {
|
||||
if (v->type() == nString) {
|
||||
attrs2["type"] = "string";
|
||||
@@ -1280,9 +1299,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
cout.flush();
|
||||
|
||||
} catch (AssertionError & e) {
|
||||
printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName());
|
||||
printMsg(lvlTalkative, "skipping derivation named '%1%' which gives an assertion failure", i.queryName(*state));
|
||||
} catch (Error & e) {
|
||||
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName());
|
||||
e.addTrace(nullptr, "while querying the derivation named '%1%'", i.queryName(*state));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -1313,7 +1332,7 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
|
||||
throw UsageError("exactly one argument expected");
|
||||
|
||||
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
||||
switchGeneration(globals.profile, *dstGen, globals.dryRun);
|
||||
switchGeneration(globals.profile, dstGen, globals.dryRun);
|
||||
else
|
||||
throw UsageError("expected a generation number");
|
||||
}
|
||||
@@ -1393,7 +1412,7 @@ static void opVersion(Globals & globals, Strings opFlags, Strings opArgs)
|
||||
}
|
||||
|
||||
|
||||
static int main_nix_env(int argc, char * * argv)
|
||||
static int main_nix_env(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
Strings opFlags, opArgs;
|
||||
@@ -1432,7 +1451,7 @@ static int main_nix_env(int argc, char * * argv)
|
||||
using LegacyArgs::LegacyArgs;
|
||||
};
|
||||
|
||||
MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
MyArgs myArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
Operation oldOp = op;
|
||||
|
||||
if (*arg == "--help")
|
||||
@@ -1513,20 +1532,20 @@ static int main_nix_env(int argc, char * * argv)
|
||||
return true;
|
||||
});
|
||||
|
||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
||||
myArgs.parseCmdline(argv);
|
||||
|
||||
if (showHelp) showManPage("nix-env" + opName);
|
||||
if (!op) throw UsageError("no operation specified");
|
||||
|
||||
auto store = openStore();
|
||||
|
||||
globals.state = std::shared_ptr<EvalState>(new EvalState(myArgs.searchPath, store));
|
||||
globals.state = std::make_shared<Evaluator>(myArgs.searchPath, store);
|
||||
globals.state->repair = myArgs.repair;
|
||||
|
||||
globals.instSource.nixExprPath = std::make_shared<SourcePath>(
|
||||
file != ""
|
||||
? lookupFileArg(*globals.state, file)
|
||||
: globals.state->rootPath(CanonPath(nixExprPath)));
|
||||
: CanonPath(nixExprPath));
|
||||
|
||||
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);
|
||||
|
||||
@@ -1544,4 +1563,8 @@ static int main_nix_env(int argc, char * * argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_env("nix-env", main_nix_env);
|
||||
void registerNixEnv() {
|
||||
LegacyCommands::add("nix-env", main_nix_env);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixEnv();
|
||||
|
||||
}
|
||||
@@ -1,22 +1,23 @@
|
||||
#include "globals.hh"
|
||||
#include "print-ambiguous.hh"
|
||||
#include "shared.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "value-to-xml.hh"
|
||||
#include "value-to-json.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "legacy.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libexpr/print-ambiguous.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/eval-inline.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libexpr/value-to-xml.hh"
|
||||
#include "lix/libexpr/value-to-json.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "nix-instantiate.hh"
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace nix;
|
||||
namespace nix {
|
||||
|
||||
|
||||
static Path gcRoot;
|
||||
@@ -30,7 +31,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||
bool evalOnly, OutputKind output, bool location, Expr & e)
|
||||
{
|
||||
if (parseOnly) {
|
||||
e.show(state.symbols, std::cout);
|
||||
e.show(state.ctx.symbols, std::cout);
|
||||
std::cout << "\n";
|
||||
return;
|
||||
}
|
||||
@@ -57,18 +58,18 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||
} else {
|
||||
if (strict) state.forceValueDeep(vRes);
|
||||
std::set<const void *> seen;
|
||||
printAmbiguous(vRes, state.symbols, std::cout, &seen, std::numeric_limits<int>::max());
|
||||
printAmbiguous(vRes, state.ctx.symbols, std::cout, &seen, std::numeric_limits<int>::max());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
} else {
|
||||
DrvInfos drvs;
|
||||
getDerivations(state, v, "", autoArgs, drvs, false);
|
||||
for (auto & i : drvs) {
|
||||
auto drvPath = i.requireDrvPath();
|
||||
auto drvPathS = state.store->printStorePath(drvPath);
|
||||
auto drvPath = i.requireDrvPath(state);
|
||||
auto drvPathS = state.ctx.store->printStorePath(drvPath);
|
||||
|
||||
/* What output do we want? */
|
||||
std::string outputName = i.queryOutputName();
|
||||
std::string outputName = i.queryOutputName(state);
|
||||
if (outputName == "")
|
||||
throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
|
||||
|
||||
@@ -77,7 +78,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||
else {
|
||||
Path rootName = absPath(gcRoot);
|
||||
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
||||
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
auto store2 = state.ctx.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
if (store2)
|
||||
drvPathS = store2->addPermRoot(drvPath, rootName);
|
||||
}
|
||||
@@ -88,7 +89,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||
}
|
||||
|
||||
|
||||
static int main_nix_instantiate(int argc, char * * argv)
|
||||
static int main_nix_instantiate(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
Strings files;
|
||||
@@ -108,7 +109,7 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||
using LegacyArgs::LegacyArgs;
|
||||
};
|
||||
|
||||
MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
MyArgs myArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help")
|
||||
showManPage("nix-instantiate");
|
||||
else if (*arg == "--version")
|
||||
@@ -148,7 +149,7 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||
return true;
|
||||
});
|
||||
|
||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
||||
myArgs.parseCmdline(argv);
|
||||
|
||||
if (evalOnly && !wantsReadWrite)
|
||||
settings.readOnlyMode = true;
|
||||
@@ -156,26 +157,24 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||
auto store = openStore();
|
||||
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
||||
|
||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, evalStore, store);
|
||||
state->repair = myArgs.repair;
|
||||
auto evaluator = std::make_unique<Evaluator>(myArgs.searchPath, evalStore, store);
|
||||
auto state = evaluator->begin();
|
||||
evaluator->repair = myArgs.repair;
|
||||
|
||||
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
|
||||
Bindings & autoArgs = *myArgs.getAutoArgs(*evaluator);
|
||||
|
||||
if (attrPaths.empty()) attrPaths = {""};
|
||||
|
||||
if (findFile) {
|
||||
for (auto & i : files) {
|
||||
auto p = state->findFile(i);
|
||||
if (auto fn = p.getPhysicalPath())
|
||||
std::cout << fn->abs() << std::endl;
|
||||
else
|
||||
throw Error("'%s' has no physical path", p);
|
||||
auto p = evaluator->paths.findFile(i);
|
||||
std::cout << p.canonical().abs() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (readStdin) {
|
||||
Expr & e = state->parseStdin();
|
||||
Expr & e = evaluator->parseStdin();
|
||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||
} else if (files.empty() && !fromArgs)
|
||||
@@ -183,16 +182,20 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||
|
||||
for (auto & i : files) {
|
||||
Expr & e = fromArgs
|
||||
? state->parseExprFromString(i, state->rootPath(CanonPath::fromCwd()))
|
||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
||||
? evaluator->parseExprFromString(i, CanonPath::fromCwd())
|
||||
: evaluator->parseExprFromFile(evaluator->paths.resolveExprPath(lookupFileArg(*evaluator, i)));
|
||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||
}
|
||||
|
||||
state->maybePrintStats();
|
||||
evaluator->maybePrintStats();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_instantiate("nix-instantiate", main_nix_instantiate);
|
||||
void registerNixInstantiate() {
|
||||
LegacyCommands::add("nix-instantiate", main_nix_instantiate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixInstantiate();
|
||||
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
#include "archive.hh"
|
||||
#include "derivations.hh"
|
||||
#include "lix/libutil/archive.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "dotgraph.hh"
|
||||
#include "exit.hh"
|
||||
#include "globals.hh"
|
||||
#include "build-result.hh"
|
||||
#include "store-cast.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "log-store.hh"
|
||||
#include "local-store.hh"
|
||||
#include "monitor-fd.hh"
|
||||
#include "serve-protocol.hh"
|
||||
#include "serve-protocol-impl.hh"
|
||||
#include "shared.hh"
|
||||
#include "lix/libutil/exit.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
#include "lix/libstore/store-cast.hh"
|
||||
#include "lix/libstore/gc-store.hh"
|
||||
#include "lix/libstore/log-store.hh"
|
||||
#include "lix/libstore/local-store.hh"
|
||||
#include "lix/libutil/monitor-fd.hh"
|
||||
#include "lix/libstore/serve-protocol.hh"
|
||||
#include "lix/libstore/serve-protocol-impl.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "graphml.hh"
|
||||
#include "legacy.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
#include "lix/libstore/path-with-outputs.hh"
|
||||
#include "nix-store.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -24,10 +25,9 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
namespace nix_store {
|
||||
namespace nix {
|
||||
|
||||
|
||||
using namespace nix;
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
|
||||
@@ -831,12 +831,12 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||
// FIXME: changing options here doesn't work if we're
|
||||
// building through the daemon.
|
||||
verbosity = lvlError;
|
||||
settings.keepLog = false;
|
||||
settings.useSubstitutes = false;
|
||||
settings.maxSilentTime = readInt(in);
|
||||
settings.buildTimeout = readInt(in);
|
||||
settings.keepLog.override(false);
|
||||
settings.useSubstitutes.override(false);
|
||||
settings.maxSilentTime.override(readInt(in));
|
||||
settings.buildTimeout.override(readInt(in));
|
||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
|
||||
settings.maxLogSize = readNum<unsigned long>(in);
|
||||
settings.maxLogSize.override(readNum<unsigned long>(in));
|
||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
|
||||
auto nrRepeats = readInt(in);
|
||||
if (nrRepeats != 0) {
|
||||
@@ -850,10 +850,10 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||
// asked for.
|
||||
readInt(in);
|
||||
|
||||
settings.runDiffHook = true;
|
||||
settings.runDiffHook.override(true);
|
||||
}
|
||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 7) {
|
||||
settings.keepFailed = (bool) readInt(in);
|
||||
settings.keepFailed.override((bool) readInt(in));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1031,7 +1031,7 @@ static void opVersion(Strings opFlags, Strings opArgs)
|
||||
/* Scan the arguments; find the operation, set global flags, put all
|
||||
other flags in a list, and put all other arguments in another
|
||||
list. */
|
||||
static int main_nix_store(int argc, char * * argv)
|
||||
static int main_nix_store(std::string programName, Strings argv)
|
||||
{
|
||||
{
|
||||
Strings opFlags, opArgs;
|
||||
@@ -1040,7 +1040,7 @@ static int main_nix_store(int argc, char * * argv)
|
||||
std::string opName;
|
||||
bool showHelp = false;
|
||||
|
||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
Operation oldOp = op;
|
||||
|
||||
if (*arg == "--help")
|
||||
@@ -1162,7 +1162,7 @@ static int main_nix_store(int argc, char * * argv)
|
||||
throw UsageError("only one operation may be specified");
|
||||
|
||||
return true;
|
||||
});
|
||||
}).parseCmdline(argv);
|
||||
|
||||
if (showHelp) showManPage("nix-store" + opName);
|
||||
if (!op) throw UsageError("no operation specified");
|
||||
@@ -1176,6 +1176,8 @@ static int main_nix_store(int argc, char * * argv)
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_store("nix-store", main_nix_store);
|
||||
void registerNixStore() {
|
||||
LegacyCommands::add("nix-store", main_nix_store);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
namespace nix {
|
||||
|
||||
void registerNixStore();
|
||||
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "user-env.hh"
|
||||
#include "derivations.hh"
|
||||
#include "store-api.hh"
|
||||
#include "path-with-outputs.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "globals.hh"
|
||||
#include "shared.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "profiles.hh"
|
||||
#include "print-ambiguous.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/path-with-outputs.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/eval-inline.hh"
|
||||
#include "lix/libstore/profiles.hh"
|
||||
#include "lix/libexpr/print-ambiguous.hh"
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
@@ -24,66 +24,65 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
exist already. */
|
||||
std::vector<StorePathWithOutputs> drvsToBuild;
|
||||
for (auto & i : elems)
|
||||
if (auto drvPath = i.queryDrvPath())
|
||||
if (auto drvPath = i.queryDrvPath(state))
|
||||
drvsToBuild.push_back({*drvPath});
|
||||
|
||||
debug("building user environment dependencies");
|
||||
state.store->buildPaths(
|
||||
state.ctx.store->buildPaths(
|
||||
toDerivedPaths(drvsToBuild),
|
||||
state.repair ? bmRepair : bmNormal);
|
||||
state.ctx.repair ? bmRepair : bmNormal);
|
||||
|
||||
/* Construct the whole top level derivation. */
|
||||
StorePathSet references;
|
||||
Value manifest;
|
||||
state.mkList(manifest, elems.size());
|
||||
Value manifest = state.ctx.mem.newList(elems.size());
|
||||
size_t n = 0;
|
||||
for (auto & i : elems) {
|
||||
/* Create a pseudo-derivation containing the name, system,
|
||||
output paths, and optionally the derivation path, as well
|
||||
as the meta attributes. */
|
||||
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt;
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(true, true);
|
||||
StringSet metaNames = i.queryMetaNames();
|
||||
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath(state) : std::nullopt;
|
||||
DrvInfo::Outputs outputs = i.queryOutputs(state, true, true);
|
||||
StringSet metaNames = i.queryMetaNames(state);
|
||||
|
||||
auto attrs = state.buildBindings(7 + outputs.size());
|
||||
auto attrs = state.ctx.buildBindings(7 + outputs.size());
|
||||
|
||||
attrs.alloc(state.sType).mkString("derivation");
|
||||
attrs.alloc(state.sName).mkString(i.queryName());
|
||||
auto system = i.querySystem();
|
||||
attrs.alloc(state.ctx.s.type).mkString("derivation");
|
||||
attrs.alloc(state.ctx.s.name).mkString(i.queryName(state));
|
||||
auto system = i.querySystem(state);
|
||||
if (!system.empty())
|
||||
attrs.alloc(state.sSystem).mkString(system);
|
||||
attrs.alloc(state.sOutPath).mkString(state.store->printStorePath(i.queryOutPath()));
|
||||
attrs.alloc(state.ctx.s.system).mkString(system);
|
||||
attrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(i.queryOutPath(state)));
|
||||
if (drvPath)
|
||||
attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
|
||||
attrs.alloc(state.ctx.s.drvPath).mkString(state.ctx.store->printStorePath(*drvPath));
|
||||
|
||||
// Copy each output meant for installation.
|
||||
auto & vOutputs = attrs.alloc(state.sOutputs);
|
||||
state.mkList(vOutputs, outputs.size());
|
||||
auto & vOutputs = attrs.alloc(state.ctx.s.outputs);
|
||||
vOutputs = state.ctx.mem.newList(outputs.size());
|
||||
for (const auto & [m, j] : enumerate(outputs)) {
|
||||
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
||||
auto outputAttrs = state.buildBindings(2);
|
||||
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
|
||||
(vOutputs.listElems()[m] = state.ctx.mem.allocValue())->mkString(j.first);
|
||||
auto outputAttrs = state.ctx.buildBindings(2);
|
||||
outputAttrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(*j.second));
|
||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||
|
||||
/* This is only necessary when installing store paths, e.g.,
|
||||
`nix-env -i /nix/store/abcd...-foo'. */
|
||||
state.store->addTempRoot(*j.second);
|
||||
state.store->ensurePath(*j.second);
|
||||
state.ctx.store->addTempRoot(*j.second);
|
||||
state.ctx.store->ensurePath(*j.second);
|
||||
|
||||
references.insert(*j.second);
|
||||
}
|
||||
|
||||
// Copy the meta attributes.
|
||||
auto meta = state.buildBindings(metaNames.size());
|
||||
auto meta = state.ctx.buildBindings(metaNames.size());
|
||||
for (auto & j : metaNames) {
|
||||
Value * v = i.queryMeta(j);
|
||||
Value * v = i.queryMeta(state, j);
|
||||
if (!v) continue;
|
||||
meta.insert(state.symbols.create(j), v);
|
||||
meta.insert(state.ctx.symbols.create(j), v);
|
||||
}
|
||||
|
||||
attrs.alloc(state.sMeta).mkAttrs(meta);
|
||||
attrs.alloc(state.ctx.s.meta).mkAttrs(meta);
|
||||
|
||||
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
||||
(manifest.listElems()[n++] = state.ctx.mem.allocValue())->mkAttrs(attrs);
|
||||
|
||||
if (drvPath) references.insert(*drvPath);
|
||||
}
|
||||
@@ -92,21 +91,21 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
the store; we need it for future modifications of the
|
||||
environment. */
|
||||
std::ostringstream str;
|
||||
printAmbiguous(manifest, state.symbols, str, nullptr, std::numeric_limits<int>::max());
|
||||
auto manifestFile = state.store->addTextToStore("env-manifest.nix",
|
||||
printAmbiguous(manifest, state.ctx.symbols, str, nullptr, std::numeric_limits<int>::max());
|
||||
auto manifestFile = state.ctx.store->addTextToStore("env-manifest.nix",
|
||||
str.str(), references);
|
||||
|
||||
/* Get the environment builder expression. */
|
||||
Value envBuilder;
|
||||
state.eval(state.parseExprFromString(
|
||||
state.eval(state.ctx.parseExprFromString(
|
||||
#include "buildenv.nix.gen.hh"
|
||||
, state.rootPath(CanonPath::root)), envBuilder);
|
||||
, CanonPath::root), envBuilder);
|
||||
|
||||
/* Construct a Nix expression that calls the user environment
|
||||
builder with the manifest as argument. */
|
||||
auto attrs = state.buildBindings(3);
|
||||
state.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||
auto attrs = state.ctx.buildBindings(3);
|
||||
state.ctx.paths.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||
attrs.insert(state.ctx.symbols.create("derivations"), &manifest);
|
||||
Value args;
|
||||
args.mkAttrs(attrs);
|
||||
|
||||
@@ -117,21 +116,21 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
debug("evaluating user environment builder");
|
||||
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
||||
NixStringContext context;
|
||||
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
|
||||
Attr & aDrvPath(*topLevel.attrs->find(state.ctx.s.drvPath));
|
||||
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
|
||||
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
|
||||
Attr & aOutPath(*topLevel.attrs->find(state.ctx.s.outPath));
|
||||
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
|
||||
|
||||
/* Realise the resulting store expression. */
|
||||
debug("building user environment");
|
||||
std::vector<StorePathWithOutputs> topLevelDrvs;
|
||||
topLevelDrvs.push_back({topLevelDrv});
|
||||
state.store->buildPaths(
|
||||
state.ctx.store->buildPaths(
|
||||
toDerivedPaths(topLevelDrvs),
|
||||
state.repair ? bmRepair : bmNormal);
|
||||
state.ctx.repair ? bmRepair : bmNormal);
|
||||
|
||||
/* Switch the current user environment to the output path. */
|
||||
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
auto store2 = state.ctx.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
|
||||
if (store2) {
|
||||
PathLocks lock;
|
||||
@@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "get-drvs.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
DrvInfos queryInstalled(EvalState & state, const Path & userEnv);
|
||||
|
||||
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||
const Path & profile, bool keepDerivations,
|
||||
const std::string & lockToken);
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "built-path.hh"
|
||||
#include "derivations.hh"
|
||||
#include "store-api.hh"
|
||||
#include "lix/libcmd/built-path.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
#include "derived-path.hh"
|
||||
#include "realisation.hh"
|
||||
#include "lix/libstore/derived-path.hh"
|
||||
#include "lix/libstore/realisation.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include <set>
|
||||
|
||||
#include "cmd-profiles.hh"
|
||||
#include "built-path.hh"
|
||||
#include "builtins/buildenv.hh"
|
||||
#include "logging.hh"
|
||||
#include "names.hh"
|
||||
#include "store-api.hh"
|
||||
#include "url-name.hh"
|
||||
#include "lix/libcmd/cmd-profiles.hh"
|
||||
#include "lix/libcmd/built-path.hh"
|
||||
#include "lix/libstore/builtins/buildenv.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libstore/names.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/temporary-dir.hh"
|
||||
#include "lix/libutil/url-name.hh"
|
||||
|
||||
namespace nix
|
||||
{
|
||||
@@ -19,8 +20,8 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||
auto manifestFile = userEnv + "/manifest.nix";
|
||||
if (pathExists(manifestFile)) {
|
||||
Value v;
|
||||
state.evalFile(state.rootPath(CanonPath(manifestFile)), v);
|
||||
Bindings & bindings(*state.allocBindings(0));
|
||||
state.evalFile(CanonPath(manifestFile), v);
|
||||
Bindings & bindings(*state.ctx.mem.allocBindings(0));
|
||||
getDerivations(state, v, "", bindings, elems, false);
|
||||
}
|
||||
return elems;
|
||||
@@ -135,7 +136,7 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile)
|
||||
auto & e = elem.value();
|
||||
ProfileElement element;
|
||||
for (auto & p : e["storePaths"]) {
|
||||
element.storePaths.insert(state.store->parseStorePath((std::string) p));
|
||||
element.storePaths.insert(state.ctx.store->parseStorePath((std::string) p));
|
||||
}
|
||||
element.active = e["active"];
|
||||
if (e.contains("priority")) {
|
||||
@@ -161,14 +162,14 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile)
|
||||
}
|
||||
} else if (pathExists(profile + "/manifest.nix")) {
|
||||
// FIXME: needed because of pure mode; ugly.
|
||||
state.allowPath(state.store->followLinksToStore(profile));
|
||||
state.allowPath(state.store->followLinksToStore(profile + "/manifest.nix"));
|
||||
state.ctx.paths.allowPath(state.ctx.store->followLinksToStore(profile));
|
||||
state.ctx.paths.allowPath(state.ctx.store->followLinksToStore(profile + "/manifest.nix"));
|
||||
|
||||
auto drvInfos = queryInstalled(state, state.store->followLinksToStore(profile));
|
||||
auto drvInfos = queryInstalled(state, state.ctx.store->followLinksToStore(profile));
|
||||
|
||||
for (auto & drvInfo : drvInfos) {
|
||||
ProfileElement element;
|
||||
element.storePaths = {drvInfo.queryOutPath()};
|
||||
element.storePaths = {drvInfo.queryOutPath(state)};
|
||||
addElement(std::move(element));
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "built-path.hh"
|
||||
#include "eval.hh"
|
||||
#include "flake/flakeref.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "types.hh"
|
||||
#include "url.hh"
|
||||
#include "url-name.hh"
|
||||
#include "lix/libcmd/built-path.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/flake/flakeref.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libutil/types.hh"
|
||||
#include "lix/libutil/url.hh"
|
||||
#include "lix/libutil/url-name.hh"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "command.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "derivations.hh"
|
||||
#include "nixexpr.hh"
|
||||
#include "profiles.hh"
|
||||
#include "repl.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libexpr/nixexpr.hh"
|
||||
#include "lix/libstore/profiles.hh"
|
||||
#include "lix/libcmd/repl.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -28,12 +28,6 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & p
|
||||
return res;
|
||||
}
|
||||
|
||||
nlohmann::json NixMultiCommand::toJSON()
|
||||
{
|
||||
// FIXME: use Command::toJSON() as well.
|
||||
return MultiCommand::toJSON();
|
||||
}
|
||||
|
||||
StoreCommand::StoreCommand()
|
||||
{
|
||||
}
|
||||
@@ -108,26 +102,17 @@ ref<Store> EvalCommand::getEvalStore()
|
||||
return ref<Store>(evalStore);
|
||||
}
|
||||
|
||||
ref<EvalState> EvalCommand::getEvalState()
|
||||
ref<eval_cache::CachingEvaluator> EvalCommand::getEvaluator()
|
||||
{
|
||||
if (!evalState) {
|
||||
evalState =
|
||||
#if HAVE_BOEHMGC
|
||||
std::allocate_shared<EvalState>(traceable_allocator<EvalState>(),
|
||||
searchPath, getEvalStore(), getStore())
|
||||
#else
|
||||
std::make_shared<EvalState>(
|
||||
searchPath, getEvalStore(), getStore())
|
||||
#endif
|
||||
;
|
||||
evalState = std::allocate_shared<eval_cache::CachingEvaluator>(
|
||||
TraceableAllocator<EvalState>(), searchPath, getEvalStore(), getStore(),
|
||||
startReplOnEvalErrors ? AbstractNixRepl::runSimple : nullptr
|
||||
);
|
||||
|
||||
evalState->repair = repair;
|
||||
|
||||
if (startReplOnEvalErrors) {
|
||||
evalState->debugRepl = &AbstractNixRepl::runSimple;
|
||||
};
|
||||
}
|
||||
return ref<EvalState>(evalState);
|
||||
return ref<eval_cache::CachingEvaluator>(evalState);
|
||||
}
|
||||
|
||||
MixOperateOnOptions::MixOperateOnOptions()
|
||||
@@ -177,7 +162,7 @@ void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
|
||||
for (auto & p : store->queryAllValidPaths())
|
||||
paths.emplace_back(BuiltPath::Opaque{p});
|
||||
} else {
|
||||
paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
paths = Installable::toBuiltPaths(*getEvaluator()->begin(), getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
if (recursive) {
|
||||
// XXX: This only computes the store path closure, ignoring
|
||||
// intermediate realisations
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "installable-value.hh"
|
||||
#include "args.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "path.hh"
|
||||
#include "flake/lockfile.hh"
|
||||
#include "lix/libcmd/installable-value.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libutil/args.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libstore/path.hh"
|
||||
#include "lix/libexpr/flake/lockfile.hh"
|
||||
|
||||
#include <optional>
|
||||
|
||||
@@ -26,11 +27,6 @@ static constexpr Command::Category catNixInstallation = 102;
|
||||
|
||||
static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
|
||||
|
||||
struct NixMultiCommand : virtual MultiCommand, virtual Command
|
||||
{
|
||||
nlohmann::json toJSON() override;
|
||||
};
|
||||
|
||||
// For the overloaded run methods
|
||||
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
|
||||
|
||||
@@ -81,12 +77,12 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
|
||||
|
||||
ref<Store> getEvalStore();
|
||||
|
||||
ref<EvalState> getEvalState();
|
||||
virtual ref<eval_cache::CachingEvaluator> getEvaluator();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Store> evalStore;
|
||||
|
||||
std::shared_ptr<EvalState> evalState;
|
||||
std::shared_ptr<eval_cache::CachingEvaluator> evalState;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -118,11 +114,13 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||
|
||||
SourceExprCommand();
|
||||
|
||||
ref<eval_cache::CachingEvaluator> getEvaluator() override;
|
||||
|
||||
Installables parseInstallables(
|
||||
ref<Store> store, std::vector<std::string> ss);
|
||||
EvalState & state, ref<Store> store, std::vector<std::string> ss);
|
||||
|
||||
ref<Installable> parseInstallable(
|
||||
ref<Store> store, const std::string & installable);
|
||||
EvalState & state, ref<Store> store, const std::string & installable);
|
||||
|
||||
virtual Strings getDefaultFlakeAttrPaths();
|
||||
|
||||
@@ -131,7 +129,7 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||
/**
|
||||
* Complete an installable from the given prefix.
|
||||
*/
|
||||
void completeInstallable(AddCompletions & completions, std::string_view prefix);
|
||||
void completeInstallable(EvalState & state, AddCompletions & completions, std::string_view prefix);
|
||||
|
||||
/**
|
||||
* Convenience wrapper around the underlying function to make setting the
|
||||
@@ -232,7 +230,7 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
BuiltPathsCommand(bool recursive = false);
|
||||
BuiltPathsCommand(bool recursive);
|
||||
|
||||
virtual void run(ref<Store> store, BuiltPaths && paths) = 0;
|
||||
|
||||
@@ -328,7 +326,7 @@ struct MixEnvironment : virtual Args {
|
||||
|
||||
void completeFlakeInputPath(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
EvalState & evalState,
|
||||
const std::vector<FlakeRef> & flakeRefs,
|
||||
std::string_view prefix);
|
||||
|
||||
@@ -336,7 +334,8 @@ void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::strin
|
||||
|
||||
void completeFlakeRefWithFragment(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
EvalState & evalState,
|
||||
ref<eval_cache::CachingEvaluator> evaluator,
|
||||
flake::LockFlags lockFlags,
|
||||
Strings attrPathPrefixes,
|
||||
const Strings & defaultFlakeAttrPaths,
|
||||
@@ -1,16 +1,32 @@
|
||||
#include "eval-settings.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "shared.hh"
|
||||
#include "filetransfer.hh"
|
||||
#include "eval.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "registry.hh"
|
||||
#include "flake/flakeref.hh"
|
||||
#include "store-api.hh"
|
||||
#include "command.hh"
|
||||
#include "lix/libexpr/eval-settings.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libstore/filetransfer.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libfetchers/fetchers.hh"
|
||||
#include "lix/libfetchers/registry.hh"
|
||||
#include "lix/libexpr/flake/flakeref.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace nix {
|
||||
|
||||
static std::regex const identifierRegex("^[A-Za-z_][A-Za-z0-9_'-]*$");
|
||||
static void warnInvalidNixIdentifier(const std::string & name)
|
||||
{
|
||||
std::smatch match;
|
||||
if (!std::regex_match(name, match, identifierRegex)) {
|
||||
warn("This Nix invocation specifies a value for argument '%s' which isn't a valid \
|
||||
Nix identifier. The project is considering to drop support for this \
|
||||
or to require quotes around args that aren't valid Nix identifiers. \
|
||||
If you depend on this behvior, please reach out in \
|
||||
https://git.lix.systems/lix-project/lix/issues/496 so we can discuss \
|
||||
your use-case.", name);
|
||||
}
|
||||
}
|
||||
|
||||
MixEvalArgs::MixEvalArgs()
|
||||
{
|
||||
addFlag({
|
||||
@@ -18,7 +34,10 @@ 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[name] = 'E' + expr; }}
|
||||
.handler = {[&](std::string name, std::string expr) {
|
||||
warnInvalidNixIdentifier(name);
|
||||
autoArgs[name] = 'E' + expr;
|
||||
}}
|
||||
});
|
||||
|
||||
addFlag({
|
||||
@@ -26,7 +45,10 @@ 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[name] = 'S' + s; }},
|
||||
.handler = {[&](std::string name, std::string s) {
|
||||
warnInvalidNixIdentifier(name);
|
||||
autoArgs[name] = 'S' + s;
|
||||
}},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
@@ -115,7 +137,7 @@ MixEvalArgs::MixEvalArgs()
|
||||
.description = "Allow access to mutable paths and repositories.",
|
||||
.category = category,
|
||||
.handler = {[&]() {
|
||||
evalSettings.pureEval = false;
|
||||
evalSettings.pureEval.override(false);
|
||||
}},
|
||||
});
|
||||
|
||||
@@ -149,13 +171,15 @@ MixEvalArgs::MixEvalArgs()
|
||||
});
|
||||
}
|
||||
|
||||
Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
||||
Bindings * MixEvalArgs::getAutoArgs(Evaluator & state)
|
||||
{
|
||||
auto res = state.buildBindings(autoArgs.size());
|
||||
for (auto & i : autoArgs) {
|
||||
auto v = state.allocValue();
|
||||
auto v = state.mem.allocValue();
|
||||
if (i.second[0] == 'E')
|
||||
state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), state.rootPath(CanonPath::fromCwd())));
|
||||
state.evalLazily(
|
||||
state.parseExprFromString(i.second.substr(1), CanonPath::fromCwd()), *v
|
||||
);
|
||||
else
|
||||
v->mkString(((std::string_view) i.second).substr(1));
|
||||
res.insert(state.symbols.create(i.first), v);
|
||||
@@ -163,7 +187,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
||||
return res.finish();
|
||||
}
|
||||
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
|
||||
SourcePath lookupFileArg(Evaluator & state, std::string_view fileArg)
|
||||
{
|
||||
if (EvalSettings::isPseudoUrl(fileArg)) {
|
||||
auto const url = EvalSettings::resolvePseudoUrl(fileArg);
|
||||
@@ -174,18 +198,18 @@ SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
|
||||
/* locked */ false
|
||||
);
|
||||
StorePath const storePath = downloaded.tree.storePath;
|
||||
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
|
||||
return CanonPath(state.store->toRealPath(storePath));
|
||||
} else if (fileArg.starts_with("flake:")) {
|
||||
experimentalFeatureSettings.require(Xp::Flakes);
|
||||
static constexpr size_t FLAKE_LEN = std::string_view("flake:").size();
|
||||
auto flakeRef = parseFlakeRef(std::string(fileArg.substr(FLAKE_LEN)), {}, true, false);
|
||||
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
|
||||
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
|
||||
return CanonPath(state.store->toRealPath(storePath));
|
||||
} else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
|
||||
Path p(fileArg.substr(1, fileArg.size() - 2));
|
||||
return state.findFile(p);
|
||||
return state.paths.findFile(p);
|
||||
} else {
|
||||
return state.rootPath(CanonPath::fromCwd(fileArg));
|
||||
return CanonPath::fromCwd(fileArg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "args.hh"
|
||||
#include "common-args.hh"
|
||||
#include "search-path.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libutil/args.hh"
|
||||
#include "lix/libmain/common-args.hh"
|
||||
#include "lix/libexpr/search-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -18,7 +19,7 @@ struct MixEvalArgs : virtual Args, virtual MixRepair
|
||||
|
||||
MixEvalArgs();
|
||||
|
||||
Bindings * getAutoArgs(EvalState & state);
|
||||
Bindings * getAutoArgs(Evaluator & state);
|
||||
|
||||
SearchPath searchPath;
|
||||
|
||||
@@ -48,6 +49,6 @@ private:
|
||||
*
|
||||
* @exception nix::ThrownError for failed search path lookup. Probably others.
|
||||
*/
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view fileArg);
|
||||
SourcePath lookupFileArg(Evaluator & state, std::string_view fileArg);
|
||||
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
#include "editor-for.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "source-path.hh"
|
||||
#include "strings.hh"
|
||||
#include "lix/libcmd/editor-for.hh"
|
||||
#include "lix/libutil/environment-variables.hh"
|
||||
#include "lix/libutil/source-path.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
Strings editorFor(const SourcePath & file, uint32_t line)
|
||||
{
|
||||
auto path = file.getPhysicalPath();
|
||||
if (!path)
|
||||
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 && (
|
||||
@@ -18,7 +15,7 @@ Strings editorFor(const SourcePath & file, uint32_t line)
|
||||
editor.find("vim") != std::string::npos ||
|
||||
editor.find("kak") != std::string::npos))
|
||||
args.push_back(fmt("+%d", line));
|
||||
args.push_back(path->abs());
|
||||
args.push_back(file.canonical().abs());
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "source-path.hh"
|
||||
#include "lix/libutil/types.hh"
|
||||
#include "lix/libutil/source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#include "installable-attr-path.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "command.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "eval.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "lix/libcmd/installable-attr-path.hh"
|
||||
#include "lix/libstore/outputs-spec.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libexpr/flake/flake.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
InstallableAttrPath::InstallableAttrPath(
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
SourceExprCommand & cmd,
|
||||
Value * v,
|
||||
const std::string & attrPath,
|
||||
@@ -26,41 +26,40 @@ InstallableAttrPath::InstallableAttrPath(
|
||||
|
||||
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
|
||||
{
|
||||
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
|
||||
auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(*evaluator), **v);
|
||||
state.forceValue(*vRes, pos);
|
||||
return {vRes, pos};
|
||||
}
|
||||
|
||||
DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
|
||||
DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths(EvalState & state)
|
||||
{
|
||||
auto [v, pos] = toValue(*state);
|
||||
auto [v, pos] = toValue(state);
|
||||
|
||||
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
|
||||
*v,
|
||||
pos,
|
||||
fmt("while evaluating the attribute '%s'", attrPath)))
|
||||
state, *v, pos, fmt("while evaluating the attribute '%s'", attrPath)
|
||||
))
|
||||
{
|
||||
return { *derivedPathWithInfo };
|
||||
}
|
||||
|
||||
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
||||
Bindings & autoArgs = *cmd.getAutoArgs(*evaluator);
|
||||
|
||||
DrvInfos drvInfos;
|
||||
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
||||
getDerivations(state, *v, "", autoArgs, drvInfos, false);
|
||||
|
||||
// Backward compatibility hack: group results by drvPath. This
|
||||
// helps keep .all output together.
|
||||
std::map<StorePath, OutputsSpec> byDrvPath;
|
||||
|
||||
for (auto & drvInfo : drvInfos) {
|
||||
auto drvPath = drvInfo.queryDrvPath();
|
||||
auto drvPath = drvInfo.queryDrvPath(state);
|
||||
if (!drvPath)
|
||||
throw Error("'%s' is not a derivation", what());
|
||||
|
||||
auto newOutputs = std::visit(overloaded {
|
||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||
std::set<std::string> outputsToInstall;
|
||||
for (auto & output : drvInfo.queryOutputs(false, true))
|
||||
for (auto & output : drvInfo.queryOutputs(state, false, true))
|
||||
outputsToInstall.insert(output.first);
|
||||
return OutputsSpec::Names { std::move(outputsToInstall) };
|
||||
},
|
||||
@@ -93,7 +92,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
|
||||
}
|
||||
|
||||
InstallableAttrPath InstallableAttrPath::parse(
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
SourceExprCommand & cmd,
|
||||
Value * v,
|
||||
std::string_view prefix,
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "installable-value.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "command.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "eval.hh"
|
||||
#include "lix/libcmd/installable-value.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libstore/outputs-spec.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -19,7 +20,7 @@ class InstallableAttrPath : public InstallableValue
|
||||
ExtendedOutputsSpec extendedOutputsSpec;
|
||||
|
||||
InstallableAttrPath(
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
SourceExprCommand & cmd,
|
||||
Value * v,
|
||||
const std::string & attrPath,
|
||||
@@ -29,12 +30,12 @@ class InstallableAttrPath : public InstallableValue
|
||||
|
||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||
|
||||
DerivedPathsWithInfo toDerivedPaths() override;
|
||||
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||
|
||||
public:
|
||||
|
||||
static InstallableAttrPath parse(
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
SourceExprCommand & cmd,
|
||||
Value * v,
|
||||
std::string_view prefix,
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "installable-derived-path.hh"
|
||||
#include "derivations.hh"
|
||||
#include "lix/libcmd/installable-derived-path.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -8,7 +8,7 @@ std::string InstallableDerivedPath::what() const
|
||||
return derivedPath.to_string(*store);
|
||||
}
|
||||
|
||||
DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths()
|
||||
DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths(EvalState & state)
|
||||
{
|
||||
return {{
|
||||
.path = derivedPath,
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "installables.hh"
|
||||
#include "lix/libcmd/installables.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -16,7 +16,7 @@ struct InstallableDerivedPath : Installable
|
||||
|
||||
std::string what() const override;
|
||||
|
||||
DerivedPathsWithInfo toDerivedPaths() override;
|
||||
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||
|
||||
std::optional<StorePath> getStorePath() override;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#include "globals.hh"
|
||||
#include "installable-flake.hh"
|
||||
#include "installable-derived-path.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "command.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "derivations.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "eval.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "store-api.hh"
|
||||
#include "shared.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "url.hh"
|
||||
#include "registry.hh"
|
||||
#include "build-result.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libcmd/installable-flake.hh"
|
||||
#include "lix/libcmd/installable-derived-path.hh"
|
||||
#include "lix/libstore/outputs-spec.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libexpr/eval-inline.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libexpr/flake/flake.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libutil/url.hh"
|
||||
#include "lix/libfetchers/registry.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
|
||||
#include <regex>
|
||||
#include <queue>
|
||||
@@ -41,20 +41,6 @@ std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
||||
return res;
|
||||
}
|
||||
|
||||
Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake)
|
||||
{
|
||||
auto vFlake = state.allocValue();
|
||||
|
||||
callFlake(state, lockedFlake, *vFlake);
|
||||
|
||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
||||
assert(aOutputs);
|
||||
|
||||
state.forceValue(*aOutputs->value, aOutputs->value->determinePos(noPos));
|
||||
|
||||
return aOutputs->value;
|
||||
}
|
||||
|
||||
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
||||
{
|
||||
std::string s;
|
||||
@@ -67,7 +53,7 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
|
||||
|
||||
InstallableFlake::InstallableFlake(
|
||||
SourceExprCommand * cmd,
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
FlakeRef && flakeRef,
|
||||
std::string_view fragment,
|
||||
ExtendedOutputsSpec extendedOutputsSpec,
|
||||
@@ -85,23 +71,22 @@ InstallableFlake::InstallableFlake(
|
||||
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
|
||||
}
|
||||
|
||||
DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
DerivedPathsWithInfo InstallableFlake::toDerivedPaths(EvalState & state)
|
||||
{
|
||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
|
||||
|
||||
auto attr = getCursor(*state);
|
||||
auto attr = getCursor(state);
|
||||
|
||||
auto attrPath = attr->getAttrPathStr();
|
||||
auto attrPath = attr->getAttrPathStr(state);
|
||||
|
||||
if (!attr->isDerivation()) {
|
||||
if (!attr->isDerivation(state)) {
|
||||
|
||||
// FIXME: use eval cache?
|
||||
auto v = attr->forceValue();
|
||||
auto v = attr->forceValue(state);
|
||||
|
||||
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
|
||||
v,
|
||||
noPos,
|
||||
fmt("while evaluating the flake output attribute '%s'", attrPath)))
|
||||
state, v, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath)
|
||||
))
|
||||
{
|
||||
return { *derivedPathWithInfo };
|
||||
} else {
|
||||
@@ -109,19 +94,19 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
"expected flake output attribute '%s' to be a derivation or path but found %s: %s",
|
||||
attrPath,
|
||||
showType(v),
|
||||
ValuePrinter(*this->state, v, errorPrintOptions)
|
||||
ValuePrinter(state, v, errorPrintOptions)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
auto drvPath = attr->forceDerivation();
|
||||
auto drvPath = attr->forceDerivation(state);
|
||||
|
||||
std::optional<NixInt::Inner> priority;
|
||||
|
||||
if (attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||
if (auto aPriority = aMeta->maybeGetAttr("priority"))
|
||||
priority = aPriority->getInt().value;
|
||||
if (attr->maybeGetAttr(state, "outputSpecified")) {
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state, "meta")) {
|
||||
if (auto aPriority = aMeta->maybeGetAttr(state, "priority"))
|
||||
priority = aPriority->getInt(state).value;
|
||||
}
|
||||
|
||||
return {{
|
||||
@@ -130,14 +115,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
.outputs = std::visit(overloaded {
|
||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||
std::set<std::string> outputsToInstall;
|
||||
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
|
||||
if (aOutputSpecified->getBool()) {
|
||||
if (auto aOutputName = attr->maybeGetAttr("outputName"))
|
||||
outputsToInstall = { aOutputName->getString() };
|
||||
if (auto aOutputSpecified = attr->maybeGetAttr(state, "outputSpecified")) {
|
||||
if (aOutputSpecified->getBool(state)) {
|
||||
if (auto aOutputName = attr->maybeGetAttr(state, "outputName"))
|
||||
outputsToInstall = { aOutputName->getString(state) };
|
||||
}
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
||||
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
|
||||
for (auto & s : aOutputsToInstall->getListOfStrings())
|
||||
} else if (auto aMeta = attr->maybeGetAttr(state, "meta")) {
|
||||
if (auto aOutputsToInstall = aMeta->maybeGetAttr(state, "outputsToInstall"))
|
||||
for (auto & s : aOutputsToInstall->getListOfStrings(state))
|
||||
outputsToInstall.insert(s);
|
||||
}
|
||||
|
||||
@@ -159,20 +144,20 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
||||
},
|
||||
ExtraPathInfoFlake::Flake {
|
||||
.originalRef = flakeRef,
|
||||
.lockedRef = getLockedFlake()->flake.lockedRef,
|
||||
.lockedRef = getLockedFlake(state)->flake.lockedRef,
|
||||
}),
|
||||
}};
|
||||
}
|
||||
|
||||
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
||||
{
|
||||
return {&getCursor(state)->forceValue(), noPos};
|
||||
return {&getCursor(state)->forceValue(state), noPos};
|
||||
}
|
||||
|
||||
std::vector<ref<eval_cache::AttrCursor>>
|
||||
InstallableFlake::getCursors(EvalState & state)
|
||||
{
|
||||
auto evalCache = openEvalCache(state, getLockedFlake());
|
||||
auto evalCache = openEvalCache(*evaluator, getLockedFlake(state));
|
||||
|
||||
auto root = evalCache->getRoot();
|
||||
|
||||
@@ -184,7 +169,7 @@ InstallableFlake::getCursors(EvalState & state)
|
||||
for (auto & attrPath : attrPaths) {
|
||||
debug("trying flake output attribute '%s'", attrPath);
|
||||
|
||||
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
||||
auto attr = root->findAlongAttrPath(state, parseAttrPath(attrPath));
|
||||
if (attr) {
|
||||
res.push_back(ref(*attr));
|
||||
} else {
|
||||
@@ -202,20 +187,20 @@ InstallableFlake::getCursors(EvalState & state)
|
||||
return res;
|
||||
}
|
||||
|
||||
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
||||
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake(EvalState & state) const
|
||||
{
|
||||
if (!_lockedFlake) {
|
||||
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
||||
// FIXME why this side effect?
|
||||
lockFlagsApplyConfig.applyNixConfig = true;
|
||||
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
|
||||
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlagsApplyConfig));
|
||||
}
|
||||
return _lockedFlake;
|
||||
}
|
||||
|
||||
FlakeRef InstallableFlake::nixpkgsFlakeRef() const
|
||||
FlakeRef InstallableFlake::nixpkgsFlakeRef(EvalState & state) const
|
||||
{
|
||||
auto lockedFlake = getLockedFlake();
|
||||
auto lockedFlake = getLockedFlake(state);
|
||||
|
||||
if (auto nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
|
||||
if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "installable-value.hh"
|
||||
#include "lix/libcmd/installable-value.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -40,7 +41,7 @@ struct InstallableFlake : InstallableValue
|
||||
|
||||
InstallableFlake(
|
||||
SourceExprCommand * cmd,
|
||||
ref<EvalState> state,
|
||||
ref<eval_cache::CachingEvaluator> state,
|
||||
FlakeRef && flakeRef,
|
||||
std::string_view fragment,
|
||||
ExtendedOutputsSpec extendedOutputsSpec,
|
||||
@@ -52,9 +53,7 @@ struct InstallableFlake : InstallableValue
|
||||
|
||||
std::vector<std::string> getActualAttrPaths();
|
||||
|
||||
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
||||
|
||||
DerivedPathsWithInfo toDerivedPaths() override;
|
||||
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||
|
||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||
|
||||
@@ -62,12 +61,11 @@ 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;
|
||||
std::shared_ptr<flake::LockedFlake> getLockedFlake(EvalState & state) const;
|
||||
|
||||
FlakeRef nixpkgsFlakeRef() const;
|
||||
FlakeRef nixpkgsFlakeRef(EvalState & state) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,7 +82,7 @@ static inline FlakeRef defaultNixpkgsFlakeRef()
|
||||
}
|
||||
|
||||
ref<eval_cache::EvalCache> openEvalCache(
|
||||
EvalState & state,
|
||||
eval_cache::CachingEvaluator & state,
|
||||
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "installable-value.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "fetch-to-store.hh"
|
||||
#include "lix/libcmd/installable-value.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libfetchers/fetch-to-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -8,8 +8,8 @@ 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,
|
||||
[&](EvalState & state) { return toValue(state).first; });
|
||||
return {evalCache->getRoot()};
|
||||
}
|
||||
|
||||
@@ -42,10 +42,12 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
|
||||
return ref { castedInstallable };
|
||||
}
|
||||
|
||||
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(
|
||||
EvalState & state, Value & v, const PosIdx pos, std::string_view errorCtx
|
||||
)
|
||||
{
|
||||
if (v.type() == nPath) {
|
||||
auto storePath = fetchToStore(*state->store, v.path());
|
||||
auto storePath = fetchToStore(*evaluator->store, state.ctx.paths.checkSourcePath(v.path()));
|
||||
return {{
|
||||
.path = DerivedPath::Opaque {
|
||||
.path = std::move(storePath),
|
||||
@@ -57,7 +59,7 @@ std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths
|
||||
else if (v.type() == nString) {
|
||||
return {{
|
||||
.path = DerivedPath::fromSingle(
|
||||
state->coerceToSingleDerivedPath(pos, v, errorCtx)),
|
||||
state.coerceToSingleDerivedPath(pos, v, errorCtx)),
|
||||
.info = make_ref<ExtraPathInfo>(),
|
||||
}};
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "installables.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "lix/libcmd/installables.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/flake/flake.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct DrvInfo;
|
||||
struct SourceExprCommand;
|
||||
|
||||
namespace eval_cache { class EvalCache; class AttrCursor; }
|
||||
|
||||
struct App
|
||||
{
|
||||
std::vector<DerivedPath> context;
|
||||
@@ -21,7 +21,7 @@ struct App
|
||||
struct UnresolvedApp
|
||||
{
|
||||
App unresolved;
|
||||
App resolve(ref<Store> evalStore, ref<Store> store);
|
||||
App resolve(EvalState & state, ref<Store> evalStore, ref<Store> store);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -71,9 +71,9 @@ struct ExtraPathInfoValue : ExtraPathInfo
|
||||
*/
|
||||
struct InstallableValue : Installable
|
||||
{
|
||||
ref<EvalState> state;
|
||||
ref<eval_cache::CachingEvaluator> evaluator;
|
||||
|
||||
InstallableValue(ref<EvalState> state) : state(state) {}
|
||||
InstallableValue(ref<eval_cache::CachingEvaluator> evaluator) : evaluator(evaluator) {}
|
||||
|
||||
virtual ~InstallableValue() { }
|
||||
|
||||
@@ -84,15 +84,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);
|
||||
|
||||
@@ -115,7 +113,9 @@ 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(
|
||||
EvalState & state, Value & v, const PosIdx pos, std::string_view errorCtx
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
#include "globals.hh"
|
||||
#include "installables.hh"
|
||||
#include "installable-derived-path.hh"
|
||||
#include "installable-attr-path.hh"
|
||||
#include "installable-flake.hh"
|
||||
#include "logging.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "command.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "derivations.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "store-api.hh"
|
||||
#include "shared.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "registry.hh"
|
||||
#include "build-result.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libcmd/installables.hh"
|
||||
#include "lix/libcmd/installable-derived-path.hh"
|
||||
#include "lix/libcmd/installable-attr-path.hh"
|
||||
#include "lix/libcmd/installable-flake.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libstore/outputs-spec.hh"
|
||||
#include "lix/libcmd/command.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/eval-settings.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libexpr/flake/flake.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libfetchers/registry.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -25,12 +25,12 @@ namespace nix {
|
||||
|
||||
void completeFlakeInputPath(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
EvalState & evalState,
|
||||
const std::vector<FlakeRef> & flakeRefs,
|
||||
std::string_view prefix)
|
||||
{
|
||||
for (auto & flakeRef : flakeRefs) {
|
||||
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
||||
auto flake = flake::getFlake(evalState, flakeRef, true);
|
||||
for (auto & input : flake.inputs)
|
||||
if (input.first.starts_with(prefix))
|
||||
completions.add(input.first);
|
||||
@@ -86,9 +86,9 @@ MixFlakeOptions::MixFlakeOptions()
|
||||
}},
|
||||
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
|
||||
if (n == 0) {
|
||||
completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
|
||||
completeFlakeInputPath(completions, *getEvaluator()->begin(), getFlakeRefsForCompletion(), prefix);
|
||||
} else if (n == 1) {
|
||||
completeFlakeRef(completions, getEvalState()->store, prefix);
|
||||
completeFlakeRef(completions, getEvaluator()->store, prefix);
|
||||
}
|
||||
}}
|
||||
});
|
||||
@@ -121,7 +121,7 @@ MixFlakeOptions::MixFlakeOptions()
|
||||
.category = category,
|
||||
.labels = {"flake-url"},
|
||||
.handler = {[&](std::string flakeRef) {
|
||||
auto evalState = getEvalState();
|
||||
auto evalState = getEvaluator()->begin();
|
||||
auto flake = flake::lockFlake(
|
||||
*evalState,
|
||||
parseFlakeRef(flakeRef, absPath(".")),
|
||||
@@ -137,7 +137,7 @@ MixFlakeOptions::MixFlakeOptions()
|
||||
}
|
||||
}},
|
||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||
completeFlakeRef(completions, getEvalState()->store, prefix);
|
||||
completeFlakeRef(completions, getEvaluator()->store, prefix);
|
||||
}}
|
||||
});
|
||||
}
|
||||
@@ -202,26 +202,26 @@ Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
|
||||
Args::CompleterClosure SourceExprCommand::getCompleteInstallable()
|
||||
{
|
||||
return [this](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||
completeInstallable(completions, prefix);
|
||||
completeInstallable(*getEvaluator()->begin(), completions, prefix);
|
||||
};
|
||||
}
|
||||
|
||||
void SourceExprCommand::completeInstallable(AddCompletions & completions, std::string_view prefix)
|
||||
void SourceExprCommand::completeInstallable(EvalState & state, AddCompletions & completions, std::string_view prefix)
|
||||
{
|
||||
try {
|
||||
if (file) {
|
||||
completions.setType(AddCompletions::Type::Attrs);
|
||||
|
||||
evalSettings.pureEval = false;
|
||||
auto state = getEvalState();
|
||||
Expr & e = state->parseExprFromFile(
|
||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
||||
);
|
||||
auto evaluator = getEvaluator();
|
||||
|
||||
Expr & e = evaluator->parseExprFromFile(
|
||||
state.ctx.paths.resolveExprPath(lookupFileArg(*evaluator, *file))
|
||||
);
|
||||
|
||||
Value root;
|
||||
state->eval(e, root);
|
||||
state.eval(e, root);
|
||||
|
||||
auto autoArgs = getAutoArgs(*state);
|
||||
auto autoArgs = getAutoArgs(*evaluator);
|
||||
|
||||
std::string prefix_ = std::string(prefix);
|
||||
auto sep = prefix_.rfind('.');
|
||||
@@ -234,15 +234,15 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||
prefix_ = "";
|
||||
}
|
||||
|
||||
auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root);
|
||||
auto [v, pos] = findAlongAttrPath(state, prefix_, *autoArgs, root);
|
||||
Value &v1(*v);
|
||||
state->forceValue(v1, pos);
|
||||
state.forceValue(v1, pos);
|
||||
Value v2;
|
||||
state->autoCallFunction(*autoArgs, v1, v2);
|
||||
state.autoCallFunction(*autoArgs, v1, v2);
|
||||
|
||||
if (v2.type() == nAttrs) {
|
||||
for (auto & i : *v2.attrs) {
|
||||
std::string name = state->symbols[i.name];
|
||||
std::string name = evaluator->symbols[i.name];
|
||||
if (name.find(searchWord) == 0) {
|
||||
if (prefix_ == "")
|
||||
completions.add(name);
|
||||
@@ -254,7 +254,8 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||
} else {
|
||||
completeFlakeRefWithFragment(
|
||||
completions,
|
||||
getEvalState(),
|
||||
state,
|
||||
getEvaluator(),
|
||||
lockFlags,
|
||||
getDefaultFlakeAttrPathPrefixes(),
|
||||
getDefaultFlakeAttrPaths(),
|
||||
@@ -267,7 +268,8 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
||||
|
||||
void completeFlakeRefWithFragment(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
EvalState & evalState,
|
||||
ref<eval_cache::CachingEvaluator> evaluator,
|
||||
flake::LockFlags lockFlags,
|
||||
Strings attrPathPrefixes,
|
||||
const Strings & defaultFlakeAttrPaths,
|
||||
@@ -278,7 +280,7 @@ void completeFlakeRefWithFragment(
|
||||
try {
|
||||
auto hash = prefix.find('#');
|
||||
if (hash == std::string::npos) {
|
||||
completeFlakeRef(completions, evalState->store, prefix);
|
||||
completeFlakeRef(completions, evaluator->store, prefix);
|
||||
} else {
|
||||
completions.setType(AddCompletions::Type::Attrs);
|
||||
|
||||
@@ -291,8 +293,10 @@ void completeFlakeRefWithFragment(
|
||||
auto flakeRefS = std::string(prefix.substr(0, hash));
|
||||
auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath("."));
|
||||
|
||||
auto evalCache = openEvalCache(*evalState,
|
||||
std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags)));
|
||||
auto evalCache = openEvalCache(
|
||||
*evaluator,
|
||||
std::make_shared<flake::LockedFlake>(lockFlake(evalState, flakeRef, lockFlags))
|
||||
);
|
||||
|
||||
auto root = evalCache->getRoot();
|
||||
|
||||
@@ -305,25 +309,25 @@ void completeFlakeRefWithFragment(
|
||||
attrPathPrefixes.push_back("");
|
||||
|
||||
for (auto & attrPathPrefixS : attrPathPrefixes) {
|
||||
auto attrPathPrefix = parseAttrPath(*evalState, attrPathPrefixS);
|
||||
auto attrPathPrefix = parseAttrPath(attrPathPrefixS);
|
||||
auto attrPathS = attrPathPrefixS + std::string(fragment);
|
||||
auto attrPath = parseAttrPath(*evalState, attrPathS);
|
||||
auto attrPath = parseAttrPath(attrPathS);
|
||||
|
||||
std::string lastAttr;
|
||||
if (!attrPath.empty() && !attrPathS.ends_with(".")) {
|
||||
lastAttr = evalState->symbols[attrPath.back()];
|
||||
lastAttr = attrPath.back();
|
||||
attrPath.pop_back();
|
||||
}
|
||||
|
||||
auto attr = root->findAlongAttrPath(attrPath);
|
||||
auto attr = root->findAlongAttrPath(evalState, attrPath);
|
||||
if (!attr) continue;
|
||||
|
||||
for (auto & attr2 : (*attr)->getAttrs()) {
|
||||
if (std::string_view(evalState->symbols[attr2]).starts_with(lastAttr)) {
|
||||
auto attrPath2 = (*attr)->getAttrPath(attr2);
|
||||
for (auto & attr2 : (*attr)->getAttrs(evalState)) {
|
||||
if (std::string_view attr2s = attr2; attr2s.starts_with(lastAttr)) {
|
||||
auto attrPath2 = (*attr)->getAttrPath(evalState, attr2s);
|
||||
/* Strip the attrpath prefix. */
|
||||
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
|
||||
completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", evalState->symbols.resolve(attrPath2)));
|
||||
completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", attrPath2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,7 +336,7 @@ void completeFlakeRefWithFragment(
|
||||
attrpaths. */
|
||||
if (fragment.empty()) {
|
||||
for (auto & attrPath : defaultFlakeAttrPaths) {
|
||||
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
|
||||
auto attr = root->findAlongAttrPath(evalState, parseAttrPath(attrPath));
|
||||
if (!attr) continue;
|
||||
completions.add(flakeRefS + "#" + prefixRoot);
|
||||
}
|
||||
@@ -369,9 +373,9 @@ void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::strin
|
||||
}
|
||||
}
|
||||
|
||||
DerivedPathWithInfo Installable::toDerivedPath()
|
||||
DerivedPathWithInfo Installable::toDerivedPath(EvalState & state)
|
||||
{
|
||||
auto buildables = toDerivedPaths();
|
||||
auto buildables = toDerivedPaths(state);
|
||||
if (buildables.size() != 1)
|
||||
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
|
||||
return std::move(buildables[0]);
|
||||
@@ -390,43 +394,49 @@ static StorePath getDeriver(
|
||||
}
|
||||
|
||||
ref<eval_cache::EvalCache> openEvalCache(
|
||||
EvalState & state,
|
||||
eval_cache::CachingEvaluator & state,
|
||||
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
||||
{
|
||||
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
||||
? std::make_optional(lockedFlake->getFingerprint())
|
||||
: std::nullopt;
|
||||
auto rootLoader = [&state, lockedFlake]()
|
||||
auto rootLoader = [lockedFlake](EvalState & state)
|
||||
{
|
||||
/* 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();
|
||||
auto vFlake = state.ctx.mem.allocValue();
|
||||
flake::callFlake(state, *lockedFlake, *vFlake);
|
||||
|
||||
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
||||
|
||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
||||
auto aOutputs = vFlake->attrs->get(state.ctx.symbols.create("outputs"));
|
||||
assert(aOutputs);
|
||||
|
||||
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;
|
||||
}
|
||||
return search->second;
|
||||
return state.getCacheFor(fingerprint.value(), rootLoader);
|
||||
} else {
|
||||
return make_ref<nix::eval_cache::EvalCache>(std::nullopt, state, rootLoader);
|
||||
return make_ref<nix::eval_cache::EvalCache>(std::nullopt, rootLoader);
|
||||
}
|
||||
}
|
||||
|
||||
ref<eval_cache::CachingEvaluator> SourceExprCommand::getEvaluator()
|
||||
{
|
||||
// FIXME: backward compatibility hack
|
||||
if (file) {
|
||||
evalSettings.pureEval.override(false);
|
||||
}
|
||||
|
||||
return EvalCommand::getEvaluator();
|
||||
}
|
||||
|
||||
Installables SourceExprCommand::parseInstallables(
|
||||
ref<Store> store, std::vector<std::string> ss)
|
||||
EvalState & state, ref<Store> store, std::vector<std::string> ss)
|
||||
{
|
||||
Installables result;
|
||||
|
||||
@@ -434,21 +444,18 @@ Installables SourceExprCommand::parseInstallables(
|
||||
if (file && expr)
|
||||
throw UsageError("'--file' and '--expr' are exclusive");
|
||||
|
||||
// FIXME: backward compatibility hack
|
||||
if (file) evalSettings.pureEval = false;
|
||||
|
||||
auto state = getEvalState();
|
||||
auto vFile = state->allocValue();
|
||||
auto evaluator = getEvaluator();
|
||||
auto vFile = evaluator->mem.allocValue();
|
||||
|
||||
if (file == "-") {
|
||||
auto & e = state->parseStdin();
|
||||
state->eval(e, *vFile);
|
||||
auto & e = evaluator->parseStdin();
|
||||
state.eval(e, *vFile);
|
||||
}
|
||||
else if (file)
|
||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||
state.evalFile(lookupFileArg(*evaluator, *file), *vFile);
|
||||
else {
|
||||
auto & e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
|
||||
state->eval(e, *vFile);
|
||||
auto & e = evaluator->parseExprFromString(*expr, CanonPath::fromCwd());
|
||||
state.eval(e, *vFile);
|
||||
}
|
||||
|
||||
for (auto & s : ss) {
|
||||
@@ -456,7 +463,7 @@ Installables SourceExprCommand::parseInstallables(
|
||||
result.push_back(
|
||||
make_ref<InstallableAttrPath>(
|
||||
InstallableAttrPath::parse(
|
||||
state, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
|
||||
evaluator, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -485,7 +492,7 @@ Installables SourceExprCommand::parseInstallables(
|
||||
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath("."));
|
||||
result.push_back(make_ref<InstallableFlake>(
|
||||
this,
|
||||
getEvalState(),
|
||||
getEvaluator(),
|
||||
std::move(flakeRef),
|
||||
fragment,
|
||||
std::move(extendedOutputsSpec),
|
||||
@@ -505,9 +512,9 @@ Installables SourceExprCommand::parseInstallables(
|
||||
}
|
||||
|
||||
ref<Installable> SourceExprCommand::parseInstallable(
|
||||
ref<Store> store, const std::string & installable)
|
||||
EvalState & state, ref<Store> store, const std::string & installable)
|
||||
{
|
||||
auto installables = parseInstallables(store, {installable});
|
||||
auto installables = parseInstallables(state, store, {installable});
|
||||
assert(installables.size() == 1);
|
||||
return installables.front();
|
||||
}
|
||||
@@ -537,6 +544,7 @@ static SingleBuiltPath getBuiltPath(ref<Store> evalStore, ref<Store> store, cons
|
||||
}
|
||||
|
||||
std::vector<BuiltPathWithResult> Installable::build(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -544,7 +552,7 @@ std::vector<BuiltPathWithResult> Installable::build(
|
||||
BuildMode bMode)
|
||||
{
|
||||
std::vector<BuiltPathWithResult> res;
|
||||
for (auto & [_, builtPathWithResult] : build2(evalStore, store, mode, installables, bMode))
|
||||
for (auto & [_, builtPathWithResult] : build2(state, evalStore, store, mode, installables, bMode))
|
||||
res.push_back(builtPathWithResult);
|
||||
return res;
|
||||
}
|
||||
@@ -581,6 +589,7 @@ static void throwBuildErrors(
|
||||
}
|
||||
|
||||
std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -600,7 +609,7 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
|
||||
std::map<DerivedPath, std::vector<Aux>> backmap;
|
||||
|
||||
for (auto & i : installables) {
|
||||
for (auto b : i->toDerivedPaths()) {
|
||||
for (auto b : i->toDerivedPaths(state)) {
|
||||
pathsToBuild.push_back(b.path);
|
||||
backmap[b.path].push_back({.info = b.info, .installable = i});
|
||||
}
|
||||
@@ -679,6 +688,7 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
|
||||
}
|
||||
|
||||
BuiltPaths Installable::toBuiltPaths(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -687,7 +697,7 @@ BuiltPaths Installable::toBuiltPaths(
|
||||
{
|
||||
if (operateOn == OperateOn::Output) {
|
||||
BuiltPaths res;
|
||||
for (auto & p : Installable::build(evalStore, store, mode, installables))
|
||||
for (auto & p : Installable::build(state, evalStore, store, mode, installables))
|
||||
res.push_back(p.path);
|
||||
return res;
|
||||
} else {
|
||||
@@ -695,20 +705,21 @@ BuiltPaths Installable::toBuiltPaths(
|
||||
settings.readOnlyMode = true;
|
||||
|
||||
BuiltPaths res;
|
||||
for (auto & drvPath : Installable::toDerivations(store, installables, true))
|
||||
for (auto & drvPath : Installable::toDerivations(state, store, installables, true))
|
||||
res.emplace_back(BuiltPath::Opaque{drvPath});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
StorePathSet Installable::toStorePathSet(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
const Installables & installables)
|
||||
{
|
||||
StorePathSet outPaths;
|
||||
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
|
||||
for (auto & path : toBuiltPaths(state, evalStore, store, mode, operateOn, installables)) {
|
||||
auto thisOutPaths = path.outPaths();
|
||||
outPaths.insert(thisOutPaths.begin(), thisOutPaths.end());
|
||||
}
|
||||
@@ -716,13 +727,14 @@ StorePathSet Installable::toStorePathSet(
|
||||
}
|
||||
|
||||
StorePaths Installable::toStorePaths(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
const Installables & installables)
|
||||
{
|
||||
StorePaths outPaths;
|
||||
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
|
||||
for (auto & path : toBuiltPaths(state, evalStore, store, mode, operateOn, installables)) {
|
||||
auto thisOutPaths = path.outPaths();
|
||||
outPaths.insert(outPaths.end(), thisOutPaths.begin(), thisOutPaths.end());
|
||||
}
|
||||
@@ -730,12 +742,13 @@ StorePaths Installable::toStorePaths(
|
||||
}
|
||||
|
||||
StorePath Installable::toStorePath(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode, OperateOn operateOn,
|
||||
ref<Installable> installable)
|
||||
{
|
||||
auto paths = toStorePathSet(evalStore, store, mode, operateOn, {installable});
|
||||
auto paths = toStorePathSet(state, evalStore, store, mode, operateOn, {installable});
|
||||
|
||||
if (paths.size() != 1)
|
||||
throw Error("argument '%s' should evaluate to one store path", installable->what());
|
||||
@@ -744,6 +757,7 @@ StorePath Installable::toStorePath(
|
||||
}
|
||||
|
||||
StorePathSet Installable::toDerivations(
|
||||
EvalState & state,
|
||||
ref<Store> store,
|
||||
const Installables & installables,
|
||||
bool useDeriver)
|
||||
@@ -751,7 +765,7 @@ StorePathSet Installable::toDerivations(
|
||||
StorePathSet drvPaths;
|
||||
|
||||
for (const auto & i : installables)
|
||||
for (const auto & b : i->toDerivedPaths())
|
||||
for (const auto & b : i->toDerivedPaths(state))
|
||||
std::visit(overloaded {
|
||||
[&](const DerivedPath::Opaque & bo) {
|
||||
drvPaths.insert(
|
||||
@@ -828,7 +842,7 @@ std::vector<FlakeRef> InstallableCommand::getFlakeRefsForCompletion()
|
||||
|
||||
void InstallablesCommand::run(ref<Store> store, std::vector<std::string> && rawInstallables)
|
||||
{
|
||||
auto installables = parseInstallables(store, rawInstallables);
|
||||
auto installables = parseInstallables(*getEvaluator()->begin(), store, rawInstallables);
|
||||
run(store, std::move(installables));
|
||||
}
|
||||
|
||||
@@ -845,7 +859,7 @@ InstallableCommand::InstallableCommand()
|
||||
|
||||
void InstallableCommand::run(ref<Store> store)
|
||||
{
|
||||
auto installable = parseInstallable(store, _installable);
|
||||
auto installable = parseInstallable(*getEvaluator()->begin(), store, _installable);
|
||||
run(store, std::move(installable));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "path.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "derived-path.hh"
|
||||
#include "built-path.hh"
|
||||
#include "store-api.hh"
|
||||
#include "build-result.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libstore/path.hh"
|
||||
#include "lix/libstore/outputs-spec.hh"
|
||||
#include "lix/libstore/derived-path.hh"
|
||||
#include "lix/libcmd/built-path.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
|
||||
#include <optional>
|
||||
|
||||
@@ -127,7 +128,7 @@ struct Installable
|
||||
*
|
||||
* This is the main method of this class
|
||||
*/
|
||||
virtual DerivedPathsWithInfo toDerivedPaths() = 0;
|
||||
virtual DerivedPathsWithInfo toDerivedPaths(EvalState & state) = 0;
|
||||
|
||||
/**
|
||||
* A convenience wrapper of the above for when we expect an
|
||||
@@ -137,7 +138,7 @@ struct Installable
|
||||
* If no or multiple \ref DerivedPath "derived paths" are produced,
|
||||
* and error is raised.
|
||||
*/
|
||||
DerivedPathWithInfo toDerivedPath();
|
||||
DerivedPathWithInfo toDerivedPath(EvalState & state);
|
||||
|
||||
/**
|
||||
* Return a value only if this installable is a store path or a
|
||||
@@ -152,6 +153,7 @@ struct Installable
|
||||
}
|
||||
|
||||
static std::vector<BuiltPathWithResult> build(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -159,6 +161,7 @@ struct Installable
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
static std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> build2(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -166,6 +169,7 @@ struct Installable
|
||||
BuildMode bMode = bmNormal);
|
||||
|
||||
static std::set<StorePath> toStorePathSet(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -173,6 +177,7 @@ struct Installable
|
||||
const Installables & installables);
|
||||
|
||||
static std::vector<StorePath> toStorePaths(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -180,6 +185,7 @@ struct Installable
|
||||
const Installables & installables);
|
||||
|
||||
static StorePath toStorePath(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -187,11 +193,13 @@ struct Installable
|
||||
ref<Installable> installable);
|
||||
|
||||
static std::set<StorePath> toDerivations(
|
||||
EvalState & state,
|
||||
ref<Store> store,
|
||||
const Installables & installables,
|
||||
bool useDeriver = false);
|
||||
|
||||
static BuiltPaths toBuiltPaths(
|
||||
EvalState & state,
|
||||
ref<Store> evalStore,
|
||||
ref<Store> store,
|
||||
Realise mode,
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "lix/libcmd/legacy.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
LegacyCommands::Commands * LegacyCommands::commands = 0;
|
||||
|
||||
}
|
||||
@@ -2,19 +2,20 @@
|
||||
///@file
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace nix {
|
||||
|
||||
typedef std::function<void(int, char * *)> MainFunction;
|
||||
typedef std::function<void(std::string, std::list<std::string>)> MainFunction;
|
||||
|
||||
struct RegisterLegacyCommand
|
||||
struct LegacyCommands
|
||||
{
|
||||
typedef std::map<std::string, MainFunction> Commands;
|
||||
static Commands * commands;
|
||||
|
||||
RegisterLegacyCommand(const std::string & name, MainFunction fun)
|
||||
static void add(const std::string & name, MainFunction fun)
|
||||
{
|
||||
if (!commands) commands = new Commands;
|
||||
(*commands)[name] = fun;
|
||||
@@ -7,4 +7,3 @@ Description: Lix Package Manager (libcmd)
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires: lix-base lix-util
|
||||
Libs: -L${libdir} -llixcmd
|
||||
Cflags: -I${includedir}/lix/libcmd
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "markdown.hh"
|
||||
#include "error.hh"
|
||||
#include "finally.hh"
|
||||
#include "terminal.hh"
|
||||
#include "lix/libcmd/markdown.hh"
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libutil/terminal.hh"
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <lowdown.h>
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "lix/libutil/types.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -47,11 +47,14 @@ libcmd = library(
|
||||
liblixfetchers,
|
||||
liblixmain,
|
||||
boehm,
|
||||
ncurses,
|
||||
editline,
|
||||
lowdown,
|
||||
nlohmann_json,
|
||||
liblix_doc,
|
||||
],
|
||||
# '../..' for self references like "lix/libcmd/*.hh"
|
||||
include_directories : [ '../..' ],
|
||||
cpp_pch : cpp_pch,
|
||||
install : true,
|
||||
# FIXME(Qyriad): is this right?
|
||||
@@ -68,7 +71,7 @@ custom_target(
|
||||
)
|
||||
|
||||
liblixcmd = declare_dependency(
|
||||
include_directories : '.',
|
||||
include_directories : include_directories('../..'),
|
||||
link_with : libcmd,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "error.hh"
|
||||
#include "file-system.hh"
|
||||
#include "logging.hh"
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/file-system.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
@@ -8,10 +8,6 @@
|
||||
#include <string_view>
|
||||
#include <cerrno>
|
||||
|
||||
#ifdef READLINE
|
||||
#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).
|
||||
// This results in linker errors due to to name-mangling of editline C symbols.
|
||||
@@ -20,10 +16,10 @@
|
||||
extern "C" {
|
||||
#include <editline.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "finally.hh"
|
||||
#include "repl-interacter.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libcmd/repl-interacter.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -35,52 +31,14 @@ void sigintHandler(int signo)
|
||||
{
|
||||
g_signal_received = signo;
|
||||
}
|
||||
};
|
||||
|
||||
static detail::ReplCompleterMixin * curRepl; // ugly
|
||||
|
||||
static char * completionCallback(char * s, int * match)
|
||||
/**
|
||||
* @return a null-terminated list of completions as expected by `el_print_columns`
|
||||
*/
|
||||
char ** copyCompletions(const StringSet& possible)
|
||||
{
|
||||
auto possible = curRepl->completePrefix(s);
|
||||
if (possible.size() == 1) {
|
||||
*match = 1;
|
||||
auto * res = strdup(possible.begin()->c_str() + strlen(s));
|
||||
if (!res)
|
||||
throw Error("allocation failure");
|
||||
return res;
|
||||
} else if (possible.size() > 1) {
|
||||
auto checkAllHaveSameAt = [&](size_t pos) {
|
||||
auto & first = *possible.begin();
|
||||
for (auto & p : possible) {
|
||||
if (p.size() <= pos || p[pos] != first[pos])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
size_t start = strlen(s);
|
||||
size_t len = 0;
|
||||
while (checkAllHaveSameAt(start + len))
|
||||
++len;
|
||||
if (len > 0) {
|
||||
*match = 1;
|
||||
auto * res = strdup(std::string(*possible.begin(), start, len).c_str());
|
||||
if (!res)
|
||||
throw Error("allocation failure");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
*match = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int listPossibleCallback(char * s, char *** avp)
|
||||
{
|
||||
auto possible = curRepl->completePrefix(s);
|
||||
|
||||
if (possible.size() > (INT_MAX / sizeof(char *)))
|
||||
throw Error("too many completions");
|
||||
|
||||
int ac = 0;
|
||||
char ** vp = nullptr;
|
||||
|
||||
@@ -95,15 +53,95 @@ static int listPossibleCallback(char * s, char *** avp)
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
vp = check(static_cast<char **>(malloc(possible.size() * sizeof(char *))));
|
||||
|
||||
for (auto & p : possible)
|
||||
vp[ac++] = check(strdup(p.c_str()));
|
||||
|
||||
*avp = vp;
|
||||
return vp;
|
||||
}
|
||||
|
||||
return ac;
|
||||
// Instead of using the readline-provided prefix, do our own tokenization
|
||||
// to avoid the default behavior of treating dots/quotes as word boundaries.
|
||||
// See the definition of SEPS for what it treats as a boundary:
|
||||
// https://github.com/troglobit/editline/blob/caf4b3c0ce3b0785791198b11de6f3134e9f05d8/src/editline.c
|
||||
std::string getLastTokenBeforeCursor()
|
||||
{
|
||||
std::string_view line{rl_line_buffer, static_cast<size_t>(rl_point)};
|
||||
|
||||
auto tokens = tokenizeString<std::vector<std::string>>(
|
||||
line,
|
||||
// Same as editline's SEPS, except for double and single quotes:
|
||||
"#$&()*:;<=>?[\\]^`{|}~\n\t "
|
||||
);
|
||||
|
||||
if (tokens.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return tokens.back();
|
||||
}
|
||||
|
||||
// Sometimes inserting text or listing possible completions has a side effect
|
||||
// of hiding the text after the cursor (even though it remains in the buffer).
|
||||
// This helper just refreshes the display while keeping the cursor in place.
|
||||
//
|
||||
// Inserting text also sometimes moves the whole buffer down one line, usually
|
||||
// if the cursor is inside a quoted attr name. I'm not sure why (vs unquoted)
|
||||
// but it still seems to work pretty well and is just a visual artifact.
|
||||
el_status_t redisplay()
|
||||
{
|
||||
int cursorPos = rl_point;
|
||||
rl_refresh_line(0, 0);
|
||||
rl_point = cursorPos;
|
||||
return (rl_point == rl_end) ? CSstay : CSmove;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
static el_status_t doCompletion() {
|
||||
auto s = getLastTokenBeforeCursor();
|
||||
auto possible = curRepl->completePrefix(s);
|
||||
|
||||
if (possible.empty()) {
|
||||
return el_ring_bell();
|
||||
}
|
||||
|
||||
if (possible.size() == 1) {
|
||||
const auto completion = *possible.cbegin();
|
||||
if (completion.size() > s.size()) {
|
||||
rl_insert_text(completion.c_str() + s.size());
|
||||
return redisplay();
|
||||
}
|
||||
|
||||
return el_ring_bell();
|
||||
}
|
||||
|
||||
auto checkAllHaveSameAt = [&](size_t pos) {
|
||||
auto & first = *possible.begin();
|
||||
for (auto & p : possible) {
|
||||
if (p.size() <= pos || p[pos] != first[pos]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
size_t start = s.size();
|
||||
size_t len = 0;
|
||||
while (checkAllHaveSameAt(start + len)) {
|
||||
++len;
|
||||
}
|
||||
if (len > 0) {
|
||||
auto commonPrefix = possible.begin()->substr(start, len);
|
||||
rl_insert_text(commonPrefix.c_str());
|
||||
el_ring_bell();
|
||||
return redisplay();
|
||||
}
|
||||
|
||||
char** columns = copyCompletions(possible);
|
||||
el_print_columns(possible.size(), columns);
|
||||
return redisplay();
|
||||
}
|
||||
|
||||
ReadlineLikeInteracter::Guard ReadlineLikeInteracter::init(detail::ReplCompleterMixin * repl)
|
||||
@@ -115,17 +153,15 @@ ReadlineLikeInteracter::Guard ReadlineLikeInteracter::init(detail::ReplCompleter
|
||||
} catch (SysError & e) {
|
||||
logWarning(e.info());
|
||||
}
|
||||
#ifndef READLINE
|
||||
el_hist_size = 1000;
|
||||
#endif
|
||||
read_history(historyFile.c_str());
|
||||
auto oldRepl = curRepl;
|
||||
curRepl = repl;
|
||||
Guard restoreRepl([oldRepl] { curRepl = oldRepl; });
|
||||
#ifndef READLINE
|
||||
rl_set_complete_func(completionCallback);
|
||||
rl_set_list_possib_func(listPossibleCallback);
|
||||
#endif
|
||||
// editline does its own escaping of completions, so we rebind tab
|
||||
// to our own completion function to skip that and do nix escaping
|
||||
// instead of shell escaping.
|
||||
el_bind_key(CTL('I'), doCompletion);
|
||||
return restoreRepl;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
#include "finally.hh"
|
||||
#include "types.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libutil/types.hh"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
virtual ~ReplInteracter(){};
|
||||
};
|
||||
|
||||
class ReadlineLikeInteracter : public virtual ReplInteracter
|
||||
class ReadlineLikeInteracter final : public ReplInteracter
|
||||
{
|
||||
std::string historyFile;
|
||||
public:
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
virtual ~ReadlineLikeInteracter() override;
|
||||
};
|
||||
|
||||
class AutomationInteracter : public virtual ReplInteracter
|
||||
class AutomationInteracter final : public ReplInteracter
|
||||
{
|
||||
public:
|
||||
AutomationInteracter() = default;
|
||||
@@ -6,34 +6,35 @@
|
||||
#include <climits>
|
||||
#include <string_view>
|
||||
|
||||
#include "box_ptr.hh"
|
||||
#include "repl-interacter.hh"
|
||||
#include "repl.hh"
|
||||
#include "lix/libutil/box_ptr.hh"
|
||||
#include "lix/libcmd/repl-interacter.hh"
|
||||
#include "lix/libcmd/repl.hh"
|
||||
|
||||
#include "ansicolor.hh"
|
||||
#include "shared.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "signals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "log-store.hh"
|
||||
#include "common-eval-args.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "derivations.hh"
|
||||
#include "globals.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "flake/lockfile.hh"
|
||||
#include "editor-for.hh"
|
||||
#include "finally.hh"
|
||||
#include "markdown.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "signals.hh"
|
||||
#include "print.hh"
|
||||
#include "gc-small-vector.hh"
|
||||
#include "users.hh"
|
||||
#include "lix/libutil/ansicolor.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
#include "lix/libutil/escape-string.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libexpr/eval-cache.hh"
|
||||
#include "lix/libexpr/eval-inline.hh"
|
||||
#include "lix/libexpr/eval-settings.hh"
|
||||
#include "lix/libexpr/attr-path.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/log-store.hh"
|
||||
#include "lix/libcmd/common-eval-args.hh"
|
||||
#include "lix/libexpr/get-drvs.hh"
|
||||
#include "lix/libstore/derivations.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libexpr/flake/flake.hh"
|
||||
#include "lix/libexpr/flake/lockfile.hh"
|
||||
#include "lix/libcmd/editor-for.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libcmd/markdown.hh"
|
||||
#include "lix/libstore/local-fs-store.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libexpr/print.hh"
|
||||
#include "lix/libexpr/gc-small-vector.hh"
|
||||
#include "lix/libutil/users.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
#define GC_INCLUDE_NEW
|
||||
@@ -119,6 +120,7 @@ struct NixRepl
|
||||
};
|
||||
/* clang-format: on */
|
||||
|
||||
Evaluator & evaluator;
|
||||
size_t debugTraceIndex;
|
||||
|
||||
Strings loadedFiles;
|
||||
@@ -133,7 +135,7 @@ struct NixRepl
|
||||
|
||||
box_ptr<ReplInteracter> interacter;
|
||||
|
||||
NixRepl(const SearchPath & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
||||
NixRepl(const SearchPath & searchPath, nix::ref<Store> store, EvalState & state,
|
||||
std::function<AnnotatedValues()> getValues);
|
||||
virtual ~NixRepl() = default;
|
||||
|
||||
@@ -157,7 +159,7 @@ struct NixRepl
|
||||
void addVarToScope(const Symbol name, Value & v);
|
||||
Expr & parseString(std::string s);
|
||||
void evalString(std::string s, Value & v);
|
||||
void loadDebugTraceEnv(DebugTrace & dt);
|
||||
void loadDebugTraceEnv(const DebugTrace & dt);
|
||||
|
||||
/**
|
||||
* Load the `repl-overlays` and add the resulting AttrSet to the top-level
|
||||
@@ -181,11 +183,7 @@ struct NixRepl
|
||||
* Note: This is `shared_ptr` to avoid garbage collection.
|
||||
*/
|
||||
std::shared_ptr<Value *> replOverlaysEvalFunction =
|
||||
#if HAVE_BOEHMGC
|
||||
std::allocate_shared<Value *>(traceable_allocator<Value *>(), nullptr);
|
||||
#else
|
||||
std::make_shared<Value *>(nullptr);
|
||||
#endif
|
||||
std::allocate_shared<Value *>(TraceableAllocator<Value *>(), nullptr);
|
||||
|
||||
/**
|
||||
* Get the `info` AttrSet that's passed as the first argument to each
|
||||
@@ -206,7 +204,7 @@ struct NixRepl
|
||||
Value & v,
|
||||
unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
|
||||
{
|
||||
::nix::printValue(*state, str, v, PrintOptions {
|
||||
::nix::printValue(state, str, v, PrintOptions {
|
||||
.ansiColors = true,
|
||||
.force = true,
|
||||
.derivationPaths = true,
|
||||
@@ -232,12 +230,13 @@ static box_ptr<ReplInteracter> makeInteracter() {
|
||||
return make_box_ptr<ReadlineLikeInteracter>(getDataDir() + "/nix/repl-history");
|
||||
}
|
||||
|
||||
NixRepl::NixRepl(const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||
NixRepl::NixRepl(const SearchPath & searchPath, nix::ref<Store> store, EvalState & state,
|
||||
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||
: AbstractNixRepl(state)
|
||||
, evaluator(state.ctx)
|
||||
, debugTraceIndex(0)
|
||||
, getValues(getValues)
|
||||
, staticEnv(new StaticEnv(nullptr, state->staticBaseEnv.get()))
|
||||
, staticEnv(new StaticEnv(nullptr, evaluator.builtins.staticEnv.get()))
|
||||
, interacter(makeInteracter())
|
||||
{
|
||||
}
|
||||
@@ -285,7 +284,7 @@ ReplExitStatus NixRepl::mainLoop()
|
||||
{
|
||||
if (isFirstRepl) {
|
||||
std::string_view debuggerNotice = "";
|
||||
if (state->debugRepl) {
|
||||
if (evaluator.debug && evaluator.debug->inDebugger) {
|
||||
debuggerNotice = " debugger";
|
||||
}
|
||||
notice("Lix %1%%2%\nType :? for help.", nixVersion, debuggerNotice);
|
||||
@@ -310,7 +309,9 @@ ReplExitStatus NixRepl::mainLoop()
|
||||
// number of chars as the prompt.
|
||||
if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
|
||||
// Ctrl-D should exit the debugger.
|
||||
state->debugStop = false;
|
||||
if (evaluator.debug) {
|
||||
evaluator.debug->stop = false;
|
||||
}
|
||||
logger->cout("");
|
||||
// TODO: Should Ctrl-D exit just the current debugger session or
|
||||
// the entire program?
|
||||
@@ -350,7 +351,7 @@ ReplExitStatus NixRepl::mainLoop()
|
||||
}
|
||||
}
|
||||
|
||||
StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||
StringSet NixRepl::completePrefix(const std::string &prefix)
|
||||
{
|
||||
StringSet completions;
|
||||
|
||||
@@ -366,7 +367,7 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (state->debugRepl) {
|
||||
if (evaluator.debug && evaluator.debug->inDebugger) {
|
||||
for (auto const & colonCmd : this->DEBUG_COMMANDS) {
|
||||
if (colonCmd.starts_with(prefix)) {
|
||||
completions.insert(std::string(colonCmd));
|
||||
@@ -415,10 +416,25 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
// To handle cases like `foo."bar.`, walk back the cursor
|
||||
// to the previous dot if there are an odd number of quotes.
|
||||
auto quoteCount =
|
||||
std::count_if(cur.begin(), cur.begin() + dot, [](char c) { return c == '"'; });
|
||||
if (quoteCount % 2 != 0) {
|
||||
// Find the last quote before the dot
|
||||
auto prevQuote = cur.rfind('"', dot - 1);
|
||||
if (prevQuote != std::string::npos) {
|
||||
// And the previous dot prior to that quote
|
||||
auto prevDot = cur.rfind('.', prevQuote);
|
||||
if (prevDot != std::string::npos) {
|
||||
dot = prevDot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable the debugger, to avoid re-entering readline. */
|
||||
auto debug_repl = state->debugRepl;
|
||||
state->debugRepl = nullptr;
|
||||
Finally restoreDebug([&]() { state->debugRepl = debug_repl; });
|
||||
auto debug = std::move(evaluator.debug);
|
||||
Finally restoreDebug([&]() { evaluator.debug = std::move(debug); });
|
||||
try {
|
||||
/* This is an expression that should evaluate to an
|
||||
attribute set. Evaluate it to get the names of the
|
||||
@@ -428,11 +444,14 @@ 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?)");
|
||||
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?)");
|
||||
|
||||
for (auto & i : *v.attrs) {
|
||||
std::string_view name = state->symbols[i.name];
|
||||
std::ostringstream output;
|
||||
printAttributeName(output, evaluator.symbols[i.name]);
|
||||
std::string name = output.str();
|
||||
|
||||
if (name.substr(0, cur2.size()) != cur2) continue;
|
||||
completions.insert(concatStrings(prev, expr, ".", name));
|
||||
}
|
||||
@@ -470,28 +489,28 @@ static bool isVarName(std::string_view s)
|
||||
|
||||
|
||||
StorePath NixRepl::getDerivationPath(Value & v) {
|
||||
auto drvInfo = getDerivation(*state, v, false);
|
||||
auto drvInfo = getDerivation(state, v, false);
|
||||
if (!drvInfo)
|
||||
throw Error("expression does not evaluate to a derivation, so I can't build it");
|
||||
auto drvPath = drvInfo->queryDrvPath();
|
||||
auto drvPath = drvInfo->queryDrvPath(state);
|
||||
if (!drvPath)
|
||||
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
|
||||
if (!state->store->isValidPath(*drvPath))
|
||||
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
|
||||
if (!evaluator.store->isValidPath(*drvPath))
|
||||
throw Error("expression evaluated to invalid derivation '%s'", evaluator.store->printStorePath(*drvPath));
|
||||
return *drvPath;
|
||||
}
|
||||
|
||||
void NixRepl::loadDebugTraceEnv(DebugTrace & dt)
|
||||
void NixRepl::loadDebugTraceEnv(const DebugTrace & dt)
|
||||
{
|
||||
initEnv();
|
||||
|
||||
auto se = state->getStaticEnv(dt.expr);
|
||||
auto se = evaluator.debug->staticEnvFor(dt.expr);
|
||||
if (se) {
|
||||
auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env);
|
||||
auto vm = mapStaticEnvBindings(evaluator.symbols, *se.get(), dt.env);
|
||||
|
||||
// add staticenv vars.
|
||||
for (auto & [name, value] : *(vm.get()))
|
||||
addVarToScope(state->symbols.create(name), *value);
|
||||
addVarToScope(evaluator.symbols.create(name), *value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,7 +560,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
<< " errors\n"
|
||||
<< " :?, :help Brings up this help menu\n"
|
||||
;
|
||||
if (state->debugRepl) {
|
||||
if (evaluator.debug && evaluator.debug->inDebugger) {
|
||||
std::cout
|
||||
<< "\n"
|
||||
<< " Debug mode commands\n"
|
||||
@@ -556,49 +575,52 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
|
||||
}
|
||||
|
||||
else if (state->debugRepl && (command == ":bt" || command == ":backtrace")) {
|
||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
||||
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":bt" || command == ":backtrace")) {
|
||||
auto traces = evaluator.debug->traces();
|
||||
for (const auto & [idx, i] : enumerate(traces)) {
|
||||
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
|
||||
showDebugTrace(std::cout, state->positions, i);
|
||||
showDebugTrace(std::cout, evaluator.positions, *i);
|
||||
}
|
||||
}
|
||||
|
||||
else if (state->debugRepl && (command == ":env")) {
|
||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
||||
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":env")) {
|
||||
auto traces = evaluator.debug->traces();
|
||||
for (const auto & [idx, i] : enumerate(traces)) {
|
||||
if (idx == debugTraceIndex) {
|
||||
printEnvBindings(*state, i.expr, i.env);
|
||||
printEnvBindings(state, i->expr, i->env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (state->debugRepl && (command == ":st")) {
|
||||
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":st")) {
|
||||
try {
|
||||
// change the DebugTrace index.
|
||||
debugTraceIndex = stoi(arg);
|
||||
} catch (...) { }
|
||||
|
||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
||||
auto traces = evaluator.debug->traces();
|
||||
for (const auto & [idx, i] : enumerate(traces)) {
|
||||
if (idx == debugTraceIndex) {
|
||||
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
|
||||
showDebugTrace(std::cout, state->positions, i);
|
||||
showDebugTrace(std::cout, evaluator.positions, *i);
|
||||
std::cout << std::endl;
|
||||
printEnvBindings(*state, i.expr, i.env);
|
||||
loadDebugTraceEnv(i);
|
||||
printEnvBindings(state, i->expr, i->env);
|
||||
loadDebugTraceEnv(*i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (state->debugRepl && (command == ":s" || command == ":step")) {
|
||||
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":s" || command == ":step")) {
|
||||
// set flag to stop at next DebugTrace; exit repl.
|
||||
state->debugStop = true;
|
||||
evaluator.debug->stop = true;
|
||||
return ProcessLineResult::Continue;
|
||||
}
|
||||
|
||||
else if (state->debugRepl && (command == ":c" || command == ":continue")) {
|
||||
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":c" || command == ":continue")) {
|
||||
// set flag to run to next breakpoint or end of program; exit repl.
|
||||
state->debugStop = false;
|
||||
evaluator.debug->stop = false;
|
||||
return ProcessLineResult::Continue;
|
||||
}
|
||||
|
||||
@@ -609,7 +631,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
}
|
||||
|
||||
else if (command == ":l" || command == ":load") {
|
||||
state->resetFileCache();
|
||||
state.resetFileCache();
|
||||
loadFile(arg);
|
||||
}
|
||||
|
||||
@@ -618,7 +640,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
}
|
||||
|
||||
else if (command == ":r" || command == ":reload") {
|
||||
state->resetFileCache();
|
||||
state.resetFileCache();
|
||||
reloadFiles();
|
||||
}
|
||||
|
||||
@@ -629,17 +651,17 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
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");
|
||||
auto path = state.coerceToPath(noPos, v, context, "while evaluating the filename to edit");
|
||||
return {path, 0};
|
||||
} else if (v.isLambda()) {
|
||||
auto pos = state->positions[v.lambda.fun->pos];
|
||||
if (auto path = std::get_if<SourcePath>(&pos.origin))
|
||||
auto pos = evaluator.positions[v.lambda.fun->pos];
|
||||
if (auto path = std::get_if<CheckedSourcePath>(&pos.origin))
|
||||
return {*path, pos.line};
|
||||
else
|
||||
throw Error("'%s' cannot be shown in an editor", pos);
|
||||
} else {
|
||||
// assume it's a derivation
|
||||
return findPackageFilename(*state, v, arg);
|
||||
return findPackageFilename(state, v, arg);
|
||||
}
|
||||
}();
|
||||
|
||||
@@ -654,8 +676,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
|
||||
// Reload right after exiting the editor if path is not in store
|
||||
// Store is immutable, so there could be no changes, so there's no need to reload
|
||||
if (!state->store->isInStore(path.resolveSymlinks().path.abs())) {
|
||||
state->resetFileCache();
|
||||
if (!evaluator.store->isInStore(canonPath(path.canonical().abs(), true))) {
|
||||
state.resetFileCache();
|
||||
reloadFiles();
|
||||
}
|
||||
}
|
||||
@@ -670,15 +692,15 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
Value v, f, result;
|
||||
evalString(arg, v);
|
||||
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
|
||||
state->callFunction(f, v, result, PosIdx());
|
||||
state.callFunction(f, v, result, PosIdx());
|
||||
|
||||
StorePath drvPath = getDerivationPath(result);
|
||||
runNix("nix-shell", {state->store->printStorePath(drvPath)});
|
||||
runNix("nix-shell", {evaluator.store->printStorePath(drvPath)});
|
||||
}
|
||||
|
||||
else if (command == ":log") {
|
||||
StorePath drvPath = ([&] {
|
||||
auto maybeDrvPath = state->store->maybeParseStorePath(arg);
|
||||
auto maybeDrvPath = evaluator.store->maybeParseStorePath(arg);
|
||||
if (maybeDrvPath && maybeDrvPath->isDerivation()) {
|
||||
return std::move(*maybeDrvPath);
|
||||
} else {
|
||||
@@ -687,7 +709,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
return getDerivationPath(v);
|
||||
}
|
||||
})();
|
||||
Path drvPathRaw = state->store->printStorePath(drvPath);
|
||||
Path drvPathRaw = evaluator.store->printStorePath(drvPath);
|
||||
|
||||
settings.readOnlyMode = true;
|
||||
Finally roModeReset([&]() {
|
||||
@@ -695,7 +717,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
});
|
||||
auto subs = getDefaultSubstituters();
|
||||
|
||||
subs.push_front(state->store);
|
||||
subs.push_front(evaluator.store);
|
||||
|
||||
bool foundLog = false;
|
||||
RunPager pager;
|
||||
@@ -722,7 +744,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
Value v;
|
||||
evalString(arg, v);
|
||||
StorePath drvPath = getDerivationPath(v);
|
||||
Path drvPathRaw = state->store->printStorePath(drvPath);
|
||||
Path drvPathRaw = evaluator.store->printStorePath(drvPath);
|
||||
|
||||
if (command == ":b" || command == ":bl") {
|
||||
// TODO: this only shows a progress bar for explicitly initiated builds,
|
||||
@@ -734,22 +756,22 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
logger->pause();
|
||||
});
|
||||
|
||||
state->store->buildPaths({
|
||||
evaluator.store->buildPaths({
|
||||
DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePathRef(drvPath),
|
||||
.outputs = OutputsSpec::All { },
|
||||
},
|
||||
});
|
||||
auto drv = state->store->readDerivation(drvPath);
|
||||
auto drv = evaluator.store->readDerivation(drvPath);
|
||||
logger->cout("\nThis derivation produced the following outputs:");
|
||||
for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) {
|
||||
auto localStore = state->store.dynamic_pointer_cast<LocalFSStore>();
|
||||
for (auto & [outputName, outputPath] : evaluator.store->queryDerivationOutputMap(drvPath)) {
|
||||
auto localStore = evaluator.store.dynamic_pointer_cast<LocalFSStore>();
|
||||
if (localStore && command == ":bl") {
|
||||
std::string symlink = "repl-result-" + outputName;
|
||||
localStore->addPermRoot(outputPath, absPath(symlink));
|
||||
logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath));
|
||||
logger->cout(" ./%s -> %s", symlink, evaluator.store->printStorePath(outputPath));
|
||||
} else {
|
||||
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
||||
logger->cout(" %s -> %s", outputName, evaluator.store->printStorePath(outputPath));
|
||||
}
|
||||
}
|
||||
} else if (command == ":i") {
|
||||
@@ -771,14 +793,16 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
}
|
||||
|
||||
else if (command == ":q" || command == ":quit") {
|
||||
state->debugStop = false;
|
||||
if (evaluator.debug) {
|
||||
evaluator.debug->stop = false;
|
||||
}
|
||||
return ProcessLineResult::Quit;
|
||||
}
|
||||
|
||||
else if (command == ":doc") {
|
||||
Value v;
|
||||
evalString(arg, v);
|
||||
if (auto doc = state->getDoc(v)) {
|
||||
if (auto doc = evaluator.builtins.getDoc(v)) {
|
||||
std::string markdown;
|
||||
|
||||
if (!doc->args.empty() && doc->name) {
|
||||
@@ -795,8 +819,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
|
||||
logger->cout(trim(renderMarkdownToTerminal(markdown)));
|
||||
} else if (v.isLambda()) {
|
||||
auto pos = state->positions[v.lambda.fun->pos];
|
||||
if (auto path = std::get_if<SourcePath>(&pos.origin)) {
|
||||
auto pos = evaluator.positions[v.lambda.fun->pos];
|
||||
if (auto path = std::get_if<CheckedSourcePath>(&pos.origin)) {
|
||||
// Path and position have now been obtained, feed to nix-doc library to get data.
|
||||
auto docComment = lambdaDocsForPos(*path, pos);
|
||||
if (!docComment) {
|
||||
@@ -817,10 +841,10 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
else if (command == ":te" || command == ":trace-enable") {
|
||||
if (arg == "false" || (arg == "" && loggerSettings.showTrace)) {
|
||||
std::cout << "not showing error traces\n";
|
||||
loggerSettings.showTrace = false;
|
||||
loggerSettings.showTrace.override(false);
|
||||
} else if (arg == "true" || (arg == "" && !loggerSettings.showTrace)) {
|
||||
std::cout << "showing error traces\n";
|
||||
loggerSettings.showTrace = true;
|
||||
loggerSettings.showTrace.override(true);
|
||||
} else {
|
||||
throw Error("unexpected argument '%s' to %s", arg, command);
|
||||
};
|
||||
@@ -838,9 +862,9 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
isVarName(name = removeWhitespace(line.substr(0, p))))
|
||||
{
|
||||
Expr & e = parseString(line.substr(p + 1));
|
||||
Value & v(*state->allocValue());
|
||||
Value & v(*evaluator.mem.allocValue());
|
||||
v.mkThunk(env, e);
|
||||
addVarToScope(state->symbols.create(name), v);
|
||||
addVarToScope(evaluator.symbols.create(name), v);
|
||||
} else {
|
||||
Value v;
|
||||
evalString(line, v);
|
||||
@@ -857,8 +881,8 @@ void NixRepl::loadFile(const Path & path)
|
||||
loadedFiles.remove(path);
|
||||
loadedFiles.push_back(path);
|
||||
Value v, v2;
|
||||
state->evalFile(lookupFileArg(*state, path), v);
|
||||
state->autoCallFunction(*autoArgs, v, v2);
|
||||
state.evalFile(lookupFileArg(evaluator, path), v);
|
||||
state.autoCallFunction(*autoArgs, v, v2);
|
||||
addAttrsToScope(v2);
|
||||
}
|
||||
|
||||
@@ -873,8 +897,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
|
||||
Value v;
|
||||
|
||||
flake::callFlake(*state,
|
||||
flake::lockFlake(*state, flakeRef,
|
||||
flake::callFlake(state,
|
||||
flake::lockFlake(state, flakeRef,
|
||||
flake::LockFlags {
|
||||
.updateLockFile = false,
|
||||
.useRegistries = !evalSettings.pureEval,
|
||||
@@ -887,14 +911,14 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
|
||||
void NixRepl::initEnv()
|
||||
{
|
||||
env = &state->allocEnv(envSize);
|
||||
env->up = &state->baseEnv;
|
||||
env = &evaluator.mem.allocEnv(envSize);
|
||||
env->up = &evaluator.builtins.env;
|
||||
displ = 0;
|
||||
staticEnv->vars.clear();
|
||||
|
||||
varNames.clear();
|
||||
for (auto & i : state->staticBaseEnv->vars)
|
||||
varNames.emplace(state->symbols[i.first]);
|
||||
for (auto & i : evaluator.builtins.staticEnv->vars)
|
||||
varNames.emplace(evaluator.symbols[i.first]);
|
||||
}
|
||||
|
||||
|
||||
@@ -933,9 +957,9 @@ void NixRepl::loadReplOverlays()
|
||||
notice("Loading '%1%'...", Magenta("repl-overlays"));
|
||||
auto replInitFilesFunction = getReplOverlaysEvalFunction();
|
||||
|
||||
Value &newAttrs(*state->allocValue());
|
||||
Value &newAttrs(*evaluator.mem.allocValue());
|
||||
SmallValueVector<3> args = {replInitInfo(), bindingsToAttrs(), replOverlays()};
|
||||
state->callFunction(
|
||||
state.callFunction(
|
||||
*replInitFilesFunction,
|
||||
args.size(),
|
||||
args.data(),
|
||||
@@ -958,25 +982,25 @@ Value * NixRepl::getReplOverlaysEvalFunction()
|
||||
}
|
||||
|
||||
auto evalReplInitFilesPath = CanonPath::root + "repl-overlays.nix";
|
||||
*replOverlaysEvalFunction = state->allocValue();
|
||||
*replOverlaysEvalFunction = evaluator.mem.allocValue();
|
||||
auto code =
|
||||
#include "repl-overlays.nix.gen.hh"
|
||||
;
|
||||
auto & expr = state->parseExprFromString(
|
||||
auto & expr = evaluator.parseExprFromString(
|
||||
code,
|
||||
SourcePath(evalReplInitFilesPath),
|
||||
state->staticBaseEnv
|
||||
evaluator.builtins.staticEnv
|
||||
);
|
||||
|
||||
state->eval(expr, **replOverlaysEvalFunction);
|
||||
state.eval(expr, **replOverlaysEvalFunction);
|
||||
|
||||
return *replOverlaysEvalFunction;
|
||||
}
|
||||
|
||||
Value * NixRepl::replOverlays()
|
||||
{
|
||||
Value * replInits(state->allocValue());
|
||||
state->mkList(*replInits, evalSettings.replOverlays.get().size());
|
||||
Value * replInits(evaluator.mem.allocValue());
|
||||
*replInits = evaluator.mem.newList(evalSettings.replOverlays.get().size());
|
||||
Value ** replInitElems = replInits->listElems();
|
||||
|
||||
size_t i = 0;
|
||||
@@ -986,10 +1010,10 @@ Value * NixRepl::replOverlays()
|
||||
auto replInit = evalFile(sourcePath);
|
||||
|
||||
if (!replInit->isLambda()) {
|
||||
state->error<TypeError>(
|
||||
evaluator.errors.make<TypeError>(
|
||||
"Expected `repl-overlays` to be a lambda but found %1%: %2%",
|
||||
showType(*replInit),
|
||||
ValuePrinter(*state, *replInit, errorPrintOptions)
|
||||
ValuePrinter(state, *replInit, errorPrintOptions)
|
||||
)
|
||||
.atPos(replInit->determinePos(noPos))
|
||||
.debugThrow();
|
||||
@@ -997,7 +1021,7 @@ Value * NixRepl::replOverlays()
|
||||
|
||||
if (replInit->lambda.fun->hasFormals()
|
||||
&& !replInit->lambda.fun->formals->ellipsis) {
|
||||
state->error<TypeError>(
|
||||
evaluator.errors.make<TypeError>(
|
||||
"Expected first argument of %1% to have %2% to allow future versions of Lix to add additional attributes to the argument",
|
||||
"repl-overlays",
|
||||
"..."
|
||||
@@ -1016,13 +1040,13 @@ Value * NixRepl::replOverlays()
|
||||
|
||||
Value * NixRepl::replInitInfo()
|
||||
{
|
||||
auto builder = state->buildBindings(2);
|
||||
auto builder = evaluator.buildBindings(2);
|
||||
|
||||
Value * currentSystem(state->allocValue());
|
||||
Value * currentSystem(evaluator.mem.allocValue());
|
||||
currentSystem->mkString(evalSettings.getCurrentSystem());
|
||||
builder.insert(state->symbols.create("currentSystem"), currentSystem);
|
||||
builder.insert(evaluator.symbols.create("currentSystem"), currentSystem);
|
||||
|
||||
Value * info(state->allocValue());
|
||||
Value * info(evaluator.mem.allocValue());
|
||||
info->mkAttrs(builder.finish());
|
||||
return info;
|
||||
}
|
||||
@@ -1030,14 +1054,14 @@ Value * NixRepl::replInitInfo()
|
||||
|
||||
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, 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");
|
||||
|
||||
for (auto & i : *attrs.attrs) {
|
||||
staticEnv->vars.emplace_back(i.name, displ);
|
||||
env->values[displ++] = i.value;
|
||||
varNames.emplace(state->symbols[i.name]);
|
||||
varNames.emplace(evaluator.symbols[i.name]);
|
||||
}
|
||||
staticEnv->sort();
|
||||
staticEnv->deduplicate();
|
||||
@@ -1054,17 +1078,17 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
|
||||
staticEnv->vars.emplace_back(name, displ);
|
||||
staticEnv->sort();
|
||||
env->values[displ++] = &v;
|
||||
varNames.emplace(state->symbols[name]);
|
||||
varNames.emplace(evaluator.symbols[name]);
|
||||
}
|
||||
|
||||
Value * NixRepl::bindingsToAttrs()
|
||||
{
|
||||
auto builder = state->buildBindings(staticEnv->vars.size());
|
||||
auto builder = evaluator.buildBindings(staticEnv->vars.size());
|
||||
for (auto & [symbol, displacement] : staticEnv->vars) {
|
||||
builder.insert(symbol, env->values[displacement]);
|
||||
}
|
||||
|
||||
Value * attrs(state->allocValue());
|
||||
Value * attrs(evaluator.mem.allocValue());
|
||||
attrs->mkAttrs(builder.finish());
|
||||
return attrs;
|
||||
}
|
||||
@@ -1072,63 +1096,50 @@ Value * NixRepl::bindingsToAttrs()
|
||||
|
||||
Expr & NixRepl::parseString(std::string s)
|
||||
{
|
||||
return state->parseExprFromString(std::move(s), state->rootPath(CanonPath::fromCwd()), staticEnv);
|
||||
return evaluator.parseExprFromString(std::move(s), CanonPath::fromCwd(), staticEnv);
|
||||
}
|
||||
|
||||
|
||||
void NixRepl::evalString(std::string s, Value & v)
|
||||
{
|
||||
Expr & e = parseString(s);
|
||||
e.eval(*state, *env, v);
|
||||
state->forceValue(v, v.determinePos(noPos));
|
||||
e.eval(state, *env, v);
|
||||
state.forceValue(v, v.determinePos(noPos));
|
||||
}
|
||||
|
||||
Value * NixRepl::evalFile(SourcePath & path)
|
||||
{
|
||||
auto & expr = state->parseExprFromFile(path, staticEnv);
|
||||
Value * result(state->allocValue());
|
||||
expr.eval(*state, *env, *result);
|
||||
state->forceValue(*result, result->determinePos(noPos));
|
||||
auto & expr = evaluator.parseExprFromFile(evaluator.paths.checkSourcePath(path), staticEnv);
|
||||
Value * result(evaluator.mem.allocValue());
|
||||
expr.eval(state, *env, *result);
|
||||
state.forceValue(*result, result->determinePos(noPos));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
||||
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||
std::function<AnnotatedValues()> getValues)
|
||||
ReplExitStatus AbstractNixRepl::run(
|
||||
const SearchPath & searchPath,
|
||||
nix::ref<Store> store,
|
||||
EvalState & state,
|
||||
std::function<AnnotatedValues()> getValues,
|
||||
const ValMap & extraEnv,
|
||||
Bindings * autoArgs
|
||||
)
|
||||
{
|
||||
return std::make_unique<NixRepl>(
|
||||
searchPath,
|
||||
openStore(),
|
||||
state,
|
||||
getValues
|
||||
NixRepl repl(searchPath, store, state, getValues);
|
||||
|
||||
repl.autoArgs = autoArgs;
|
||||
repl.initEnv();
|
||||
for (auto & [name, value] : extraEnv) {
|
||||
repl.addVarToScope(repl.evaluator.symbols.create(name), *value);
|
||||
}
|
||||
return repl.mainLoop();
|
||||
}
|
||||
|
||||
ReplExitStatus AbstractNixRepl::runSimple(EvalState & evalState, const ValMap & extraEnv)
|
||||
{
|
||||
return run(
|
||||
{}, openStore(), evalState, [] { return AnnotatedValues{}; }, extraEnv, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
ReplExitStatus AbstractNixRepl::runSimple(
|
||||
ref<EvalState> evalState,
|
||||
const ValMap & extraEnv)
|
||||
{
|
||||
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
||||
NixRepl::AnnotatedValues values;
|
||||
return values;
|
||||
};
|
||||
SearchPath searchPath = {};
|
||||
auto repl = std::make_unique<NixRepl>(
|
||||
searchPath,
|
||||
openStore(),
|
||||
evalState,
|
||||
getValues
|
||||
);
|
||||
|
||||
repl->initEnv();
|
||||
|
||||
// add 'extra' vars.
|
||||
for (auto & [name, value] : extraEnv)
|
||||
repl->addVarToScope(repl->state->symbols.create(name), *value);
|
||||
|
||||
return repl->mainLoop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +1,37 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "eval.hh"
|
||||
#include "lix/libexpr/eval.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct AbstractNixRepl
|
||||
{
|
||||
ref<EvalState> state;
|
||||
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||
|
||||
static ReplExitStatus
|
||||
run(const SearchPath & searchPath,
|
||||
nix::ref<Store> store,
|
||||
EvalState & state,
|
||||
std::function<AnnotatedValues()> getValues,
|
||||
const ValMap & extraEnv,
|
||||
Bindings * autoArgs);
|
||||
|
||||
static ReplExitStatus runSimple(
|
||||
EvalState & evalState,
|
||||
const ValMap & extraEnv);
|
||||
|
||||
protected:
|
||||
EvalState & state;
|
||||
Bindings * autoArgs;
|
||||
|
||||
AbstractNixRepl(ref<EvalState> state)
|
||||
AbstractNixRepl(EvalState & state)
|
||||
: state(state)
|
||||
{ }
|
||||
|
||||
virtual ~AbstractNixRepl()
|
||||
{ }
|
||||
|
||||
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||
|
||||
static std::unique_ptr<AbstractNixRepl> create(
|
||||
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||
std::function<AnnotatedValues()> getValues);
|
||||
|
||||
static ReplExitStatus runSimple(
|
||||
ref<EvalState> evalState,
|
||||
const ValMap & extraEnv);
|
||||
|
||||
virtual void initEnv() = 0;
|
||||
|
||||
virtual ReplExitStatus mainLoop() = 0;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user