Compare commits
546
Commits
release-2.91
...
2.92.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c5e1c8f63 | ||
|
|
fe090a7b9b | ||
|
|
4a3983906f | ||
|
|
bac0d67928 | ||
|
|
22a1d233bb | ||
|
|
4901a6cda9 | ||
|
|
8cbdc36a60 | ||
|
|
56b0b39465 | ||
|
|
438e1839f1 | ||
|
|
99456a0c7e | ||
|
|
1d36dd7596 | ||
|
|
21317ce965 | ||
|
|
b43a289c02 | ||
|
|
2138b0f7e9 | ||
|
|
2f32368136 | ||
|
|
a713c064af | ||
|
|
cba05329ee | ||
|
|
f5f2e1537d | ||
|
|
0ea8649445 | ||
|
|
d0678a57f9 | ||
|
|
1d4ddb7e3b | ||
|
|
c7867e89f9 | ||
|
|
deb5150c82 | ||
|
|
92eb418a59 | ||
|
|
7fceee3ce3 | ||
|
|
31f976dc19 | ||
|
|
d8db15010d | ||
|
|
253be7d2ba | ||
|
|
a34e583305 | ||
|
|
a8fb008106 | ||
|
|
32cbb66a69 | ||
|
|
9631e9a30f | ||
|
|
98772c4a3b | ||
|
|
a7fd5c3867 | ||
|
|
6f3a7bbeb0 | ||
|
|
0d1f794178 | ||
|
|
ef5689dc1b | ||
|
|
db55ca9a2e | ||
|
|
4cd618272a | ||
|
|
73f0213500 | ||
|
|
9c1db3cd8b | ||
|
|
5fa27057b2 | ||
|
|
d2b1af70ee | ||
|
|
50def3fa73 | ||
|
|
8e2ab5532c | ||
|
|
079528098f | ||
|
|
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 | ||
|
|
02eb07cfd5 | ||
|
|
d75df91f74 | ||
|
|
a385c5935a | ||
|
|
dc0cace604 | ||
|
|
e0fd0ba211 | ||
|
|
c2b90d235f | ||
|
|
e55ec75619 | ||
|
|
869666cb65 | ||
|
|
a5c1e73fa8 | ||
|
|
bb161a96cf | ||
|
|
a510d17484 | ||
|
|
04f8a14833 | ||
|
|
e6f2af06e6 | ||
|
|
4d89844207 | ||
|
|
422550fd68 | ||
|
|
5d31e889d7 | ||
|
|
4f02255c20 | ||
|
|
0dc486a5bf | ||
|
|
0cc285f87b | ||
|
|
ca08f1217d | ||
|
|
742303dc3a | ||
|
|
690f07272e | ||
|
|
5fc6fcb310 | ||
|
|
b6884388a1 | ||
|
|
0582999bd1 | ||
|
|
398894b856 | ||
|
|
30a87b4cd5 | ||
|
|
72f91767a8 | ||
|
|
3bf8819fa2 | ||
|
|
c300efc0e1 | ||
|
|
cae260a158 | ||
|
|
04b591dc1d | ||
|
|
686120ee4a | ||
|
|
fabc9f29b8 | ||
|
|
c5949bfe31 | ||
|
|
7e677d15a4 | ||
|
|
af546be205 | ||
|
|
9aacf425dc | ||
|
|
9845637359 | ||
|
|
87fd6e0095 | ||
|
|
9896d309cb | ||
|
|
f2e7f8bab8 | ||
|
|
447212fa65 | ||
|
|
651cc0e5b4 | ||
|
|
dba615098d | ||
|
|
e3c289dbe9 | ||
|
|
de552c42cb | ||
|
|
e38410799b | ||
|
|
0edfea450b | ||
|
|
3cbbe22fab | ||
|
|
0a8888d1c7 | ||
|
|
7210ed1b87 | ||
|
|
c25c43d8c8 | ||
|
|
ac6974777e | ||
|
|
736b5d5913 | ||
|
|
95863b258b | ||
|
|
f1533160aa | ||
|
|
df49d37b71 | ||
|
|
ae628d4af2 | ||
|
|
040e783232 | ||
|
|
e727dbc3a3 | ||
|
|
b40369942c | ||
|
|
fca523d661 | ||
|
|
5e9db09761 | ||
|
|
e513cd2beb | ||
|
|
fb8eb539fc | ||
|
|
3d14567d0b | ||
|
|
925e08b858 | ||
|
|
5cbca85535 | ||
|
|
ecfe9345cf | ||
|
|
84543b459c | ||
|
|
e2d330aeed | ||
|
|
007211e7a2 | ||
|
|
7506d680ac | ||
|
|
38f550708d | ||
|
|
176e1058f1 | ||
|
|
91a74ba82a | ||
|
|
b66fd9ff4b | ||
|
|
278fddc317 | ||
|
|
49d61b2e4b | ||
|
|
1c080a8239 | ||
|
|
41a0b08e64 | ||
|
|
b016eb0895 | ||
|
|
f9a3bf6ccc | ||
|
|
3058029fba |
@@ -16,6 +16,8 @@ Checks:
|
|||||||
- -bugprone-unchecked-optional-access
|
- -bugprone-unchecked-optional-access
|
||||||
# many warnings, seems like a questionable lint
|
# many warnings, seems like a questionable lint
|
||||||
- -bugprone-branch-clone
|
- -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
|
# all thrown exceptions must derive from std::exception
|
||||||
- hicpp-exception-baseclass
|
- hicpp-exception-baseclass
|
||||||
# capturing async lambdas are dangerous
|
# capturing async lambdas are dangerous
|
||||||
@@ -33,3 +35,4 @@ Checks:
|
|||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
bugprone-reserved-identifier.AllowedIdentifiers: '__asan_default_options'
|
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_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
max_line_length = 0
|
max_line_length = 0
|
||||||
|
|
||||||
|
[meson.build]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name: Missing or incorrect documentation
|
name: Missing or incorrect documentation
|
||||||
about: Help us improve the reference manual
|
about: Help us improve the reference manual
|
||||||
title: ''
|
title: ''
|
||||||
labels: documentation
|
labels: docs
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -19,10 +19,10 @@ assignees: ''
|
|||||||
|
|
||||||
<!-- make sure this issue is not redundant or obsolete -->
|
<!-- 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
|
- [ ] checked [documentation issues] and [recent documentation changes] for possible duplicates
|
||||||
|
|
||||||
[latest Nix manual]: https://docs.lix.systems/manual/lix/nightly
|
[latest Lix manual]: https://docs.lix.systems/manual/lix/nightly
|
||||||
[source]: https://git.lix.systems/lix-project/lix/src/main/doc/manual/src
|
[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
|
[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
|
[recent documentation changes]: https://gerrit.lix.systems/q/p:lix+path:%22%5Edoc/manual/.*%22
|
||||||
|
|||||||
+10
@@ -9,6 +9,10 @@ GTAGS
|
|||||||
# ccls
|
# ccls
|
||||||
/.ccls-cache
|
/.ccls-cache
|
||||||
|
|
||||||
|
# auto-generated compilation database
|
||||||
|
compile_commands.json
|
||||||
|
rust-project.json
|
||||||
|
|
||||||
result
|
result
|
||||||
result-*
|
result-*
|
||||||
|
|
||||||
@@ -29,3 +33,9 @@ buildtime.bin
|
|||||||
/.pre-commit-config.yaml
|
/.pre-commit-config.yaml
|
||||||
/.nocontribmsg
|
/.nocontribmsg
|
||||||
/release
|
/release
|
||||||
|
|
||||||
|
# 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>
|
||||||
Generated
+6
-22
@@ -2,12 +2,6 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "countme"
|
name = "countme"
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
@@ -16,15 +10,15 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dissimilar"
|
name = "dissimilar"
|
||||||
version = "1.0.7"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
|
checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "expect-test"
|
name = "expect-test"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
|
checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dissimilar",
|
"dissimilar",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -45,15 +39,6 @@ dependencies = [
|
|||||||
"rowan",
|
"rowan",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@@ -71,13 +56,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rowan"
|
name = "rowan"
|
||||||
version = "0.15.15"
|
version = "0.15.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49"
|
checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"countme",
|
"countme",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"memoffset",
|
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"text-size",
|
"text-size",
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
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
|
set -euo pipefail
|
||||||
shopt -s inherit_errexit
|
shopt -s inherit_errexit
|
||||||
@@ -21,16 +22,21 @@ fi
|
|||||||
_exit=""
|
_exit=""
|
||||||
trap "$_exit" EXIT
|
trap "$_exit" EXIT
|
||||||
|
|
||||||
# XXX: yes this is very silly. flakes~!!
|
flake_args=("--extra-experimental-features" "nix-command flakes")
|
||||||
nix build --impure --expr '(builtins.getFlake "git+file:.").inputs.nixpkgs.outPath' -o bench/nixpkgs
|
|
||||||
|
|
||||||
|
# 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)"
|
export NIX_REMOTE="$(mktemp -d)"
|
||||||
_exit='rm -rfv "$NIX_REMOTE"; $_exit'
|
_exit='rm -rfv "$NIX_REMOTE"; $_exit'
|
||||||
export NIX_PATH="nixpkgs=bench/nixpkgs:nixos-config=bench/configuration.nix"
|
export NIX_PATH="nixpkgs=bench/nixpkgs:nixos-config=bench/configuration.nix"
|
||||||
|
|
||||||
builds=("$@")
|
builds=("$@")
|
||||||
|
|
||||||
flake_args="--extra-experimental-features 'nix-command flakes'"
|
flake_args="${flake_args[*]@Q}"
|
||||||
|
|
||||||
hyperfineArgs=(
|
hyperfineArgs=(
|
||||||
--parameter-list BUILD "$(IFS=,; echo "${builds[*]}")"
|
--parameter-list BUILD "$(IFS=,; echo "${builds[*]}")"
|
||||||
|
|||||||
+10
-21
@@ -32,8 +32,8 @@
|
|||||||
hardware = {
|
hardware = {
|
||||||
enableRedistributableFirmware = true;
|
enableRedistributableFirmware = true;
|
||||||
cpu.intel.updateMicrocode = true;
|
cpu.intel.updateMicrocode = true;
|
||||||
opengl.driSupport32Bit = true;
|
graphics.enable32Bit = true;
|
||||||
opengl.extraPackages = with pkgs; [
|
graphics.extraPackages = with pkgs; [
|
||||||
vaapiIntel
|
vaapiIntel
|
||||||
intel-media-driver
|
intel-media-driver
|
||||||
intel-compute-runtime
|
intel-compute-runtime
|
||||||
@@ -93,16 +93,17 @@
|
|||||||
|
|
||||||
i18n = {
|
i18n = {
|
||||||
defaultLocale = "en_US.UTF-8";
|
defaultLocale = "en_US.UTF-8";
|
||||||
inputMethod.enabled = "ibus";
|
inputMethod.enable = true;
|
||||||
|
inputMethod.type = "ibus";
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
libinput.enable = true;
|
||||||
xserver = {
|
xserver = {
|
||||||
enable = true;
|
enable = true;
|
||||||
layout = "us";
|
xkb.layout = "us";
|
||||||
xkbVariant = "altgr-intl";
|
xkb.variant = "altgr-intl";
|
||||||
xkbOptions = "ctrl:nocaps";
|
xkb.options = "ctrl:nocaps";
|
||||||
libinput.enable = true;
|
|
||||||
wacom.enable = true;
|
wacom.enable = true;
|
||||||
videoDrivers = [ "modesetting" ];
|
videoDrivers = [ "modesetting" ];
|
||||||
modules = [ pkgs.xf86_input_wacom ];
|
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 = {
|
programs = {
|
||||||
light.enable = true;
|
light.enable = true;
|
||||||
wireshark = {
|
wireshark = {
|
||||||
@@ -146,7 +136,7 @@
|
|||||||
fonts.packages = with pkgs; [
|
fonts.packages = with pkgs; [
|
||||||
font-awesome
|
font-awesome
|
||||||
noto-fonts
|
noto-fonts
|
||||||
noto-fonts-cjk
|
noto-fonts-cjk-sans
|
||||||
noto-fonts-emoji
|
noto-fonts-emoji
|
||||||
noto-fonts-extra
|
noto-fonts-extra
|
||||||
dejavu_fonts
|
dejavu_fonts
|
||||||
@@ -239,7 +229,7 @@
|
|||||||
file
|
file
|
||||||
firefox
|
firefox
|
||||||
fluidsynth
|
fluidsynth
|
||||||
gnome3.adwaita-icon-theme
|
adwaita-icon-theme
|
||||||
gnuplot
|
gnuplot
|
||||||
graphviz
|
graphviz
|
||||||
helm
|
helm
|
||||||
@@ -252,7 +242,6 @@
|
|||||||
libqalculate
|
libqalculate
|
||||||
libreoffice
|
libreoffice
|
||||||
man-pages
|
man-pages
|
||||||
nheko
|
|
||||||
nix-diff
|
nix-diff
|
||||||
nix-index
|
nix-index
|
||||||
nix-output-monitor
|
nix-output-monitor
|
||||||
|
|||||||
@@ -33,32 +33,7 @@ GENERATE_LATEX = NO
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
# FIXME Make this list more maintainable somehow. We could maybe generate this
|
INPUT = @INPUT_PATHS@
|
||||||
# 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
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
|
# 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
|
# in the source code. If set to NO, only conditional compilation will be
|
||||||
@@ -97,3 +72,15 @@ EXPAND_AS_DEFINED = \
|
|||||||
DECLARE_WORKER_SERIALISER \
|
DECLARE_WORKER_SERIALISER \
|
||||||
DECLARE_SERVE_SERIALISER \
|
DECLARE_SERVE_SERIALISER \
|
||||||
LENGTH_PREFIXED_PROTO_HELPER
|
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(
|
doxygen_cfg = configure_file(
|
||||||
input : 'doxygen.cfg.in',
|
input : 'doxygen.cfg.in',
|
||||||
output : 'doxygen.cfg',
|
output : 'doxygen.cfg',
|
||||||
@@ -5,22 +37,16 @@ doxygen_cfg = configure_file(
|
|||||||
'PACKAGE_VERSION': meson.project_version(),
|
'PACKAGE_VERSION': meson.project_version(),
|
||||||
'RAPIDCHECK_HEADERS': rapidcheck_meson.get_variable('includedir'),
|
'RAPIDCHECK_HEADERS': rapidcheck_meson.get_variable('includedir'),
|
||||||
'docdir' : meson.current_build_dir(),
|
'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 = custom_target(
|
||||||
'internal-api-docs',
|
'internal-api-docs',
|
||||||
command : [
|
command : [
|
||||||
bash,
|
doxygen.full_path(),
|
||||||
# Meson can you please just give us a `workdir` argument to custom targets...
|
'@INPUT0@',
|
||||||
'-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(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
input : [
|
input : [
|
||||||
doxygen_cfg,
|
doxygen_cfg,
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ artemist:
|
|||||||
display_name: Artemis Tosini
|
display_name: Artemis Tosini
|
||||||
forgejo: artemist
|
forgejo: artemist
|
||||||
|
|
||||||
|
bb010g:
|
||||||
|
display_name: Dusk Banks
|
||||||
|
forgejo: bb010g
|
||||||
|
github: bb010g
|
||||||
|
|
||||||
cole-h:
|
cole-h:
|
||||||
display_name: Cole Helbling
|
display_name: Cole Helbling
|
||||||
github: cole-h
|
github: cole-h
|
||||||
@@ -57,6 +62,9 @@ ericson:
|
|||||||
display_name: John Ericson
|
display_name: John Ericson
|
||||||
github: ericson2314
|
github: ericson2314
|
||||||
|
|
||||||
|
gilice:
|
||||||
|
forgejo: gilice
|
||||||
|
|
||||||
goldstein:
|
goldstein:
|
||||||
display_name: goldstein
|
display_name: goldstein
|
||||||
forgejo: goldstein
|
forgejo: goldstein
|
||||||
@@ -70,6 +78,10 @@ horrors:
|
|||||||
iFreilicht:
|
iFreilicht:
|
||||||
github: iFreilicht
|
github: iFreilicht
|
||||||
|
|
||||||
|
ian-h-chamberlain:
|
||||||
|
forgejo: ian-h-chamberlain
|
||||||
|
github: ian-h-chamberlain
|
||||||
|
|
||||||
isabelroses:
|
isabelroses:
|
||||||
forgejo: isabelroses
|
forgejo: isabelroses
|
||||||
github: isabelroses
|
github: isabelroses
|
||||||
@@ -78,13 +90,28 @@ jade:
|
|||||||
forgejo: jade
|
forgejo: jade
|
||||||
github: lf-
|
github: lf-
|
||||||
|
|
||||||
|
just1602:
|
||||||
|
forgejo: just1602
|
||||||
|
|
||||||
|
kiara:
|
||||||
|
github: KiaraGrouwstra
|
||||||
|
|
||||||
kjeremy:
|
kjeremy:
|
||||||
github: kjeremy
|
github: kjeremy
|
||||||
|
|
||||||
kloenk:
|
kloenk:
|
||||||
|
display_name: Fiona Behrens
|
||||||
forgejo: kloenk
|
forgejo: kloenk
|
||||||
github: kloenk
|
github: kloenk
|
||||||
|
|
||||||
|
lheckemann:
|
||||||
|
forgejo: lheckemann
|
||||||
|
github: lheckemann
|
||||||
|
|
||||||
|
lilyball:
|
||||||
|
forgejo: lilyball
|
||||||
|
github: lilyball
|
||||||
|
|
||||||
lovesegfault:
|
lovesegfault:
|
||||||
github: lovesegfault
|
github: lovesegfault
|
||||||
|
|
||||||
@@ -141,9 +168,17 @@ valentin:
|
|||||||
display_name: Valentin Gagarin
|
display_name: Valentin Gagarin
|
||||||
github: fricklerhandwerk
|
github: fricklerhandwerk
|
||||||
|
|
||||||
|
vigress8:
|
||||||
|
display_name: Vigress
|
||||||
|
forgejo: vigress8
|
||||||
|
github: vigress8
|
||||||
|
|
||||||
winter:
|
winter:
|
||||||
forgejo: winter
|
forgejo: winter
|
||||||
github: winterqt
|
github: winterqt
|
||||||
|
|
||||||
yshui:
|
yshui:
|
||||||
github: 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))
|
|
||||||
+130
-22
@@ -1,26 +1,134 @@
|
|||||||
|
with builtins;
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (builtins)
|
splitLines = s: filter (x: !isList x) (split "\n" s);
|
||||||
attrNames
|
|
||||||
attrValues
|
concatStrings = concatStringsSep "";
|
||||||
fromJSON
|
|
||||||
listToAttrs
|
replaceStringsRec =
|
||||||
mapAttrs
|
from: to: string:
|
||||||
concatStringsSep
|
# recursively replace occurrences of `from` with `to` within `string`
|
||||||
concatMap
|
# example:
|
||||||
length
|
# replaceStringRec "--" "-" "hello-----world"
|
||||||
lessThan
|
# => "hello-world"
|
||||||
replaceStrings
|
let
|
||||||
sort
|
replaced = replaceStrings [ from ] [ to ] string;
|
||||||
;
|
in
|
||||||
inherit (import ./utils.nix)
|
if replaced == string then string else replaceStringsRec from to replaced;
|
||||||
concatStrings
|
|
||||||
optionalString
|
squash = replaceStringsRec "\n\n\n" "\n\n";
|
||||||
filterAttrs
|
|
||||||
trim
|
trim =
|
||||||
squash
|
string:
|
||||||
unique
|
# trim trailing spaces and squash non-leading spaces
|
||||||
showSettings
|
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
|
in
|
||||||
|
|
||||||
inlineHTML: commandDump:
|
inlineHTML: commandDump:
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
with builtins;
|
|
||||||
with import ./utils.nix;
|
|
||||||
|
|
||||||
let
|
|
||||||
showExperimentalFeature = name: doc: ''
|
|
||||||
- [`${name}`](@docroot@/contributing/experimental-features.md#xp-feature-${name})
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
xps: indent " " (concatStrings (attrValues (mapAttrs showExperimentalFeature xps)))
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
with builtins;
|
|
||||||
with import ./utils.nix;
|
|
||||||
|
|
||||||
let
|
|
||||||
showExperimentalFeature =
|
|
||||||
name: doc:
|
|
||||||
squash ''
|
|
||||||
## [`${name}`]{#xp-feature-${name}}
|
|
||||||
|
|
||||||
${doc}
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
xps: (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps)))
|
|
||||||
+10
-55
@@ -15,67 +15,21 @@ nix_eval_for_docs_common = nix_for_docs + [
|
|||||||
]
|
]
|
||||||
nix_eval_for_docs = nix_eval_for_docs_common + '--raw'
|
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
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',
|
|
||||||
)
|
|
||||||
|
|
||||||
language_json = custom_target(
|
|
||||||
command: [nix, '__dump-language'],
|
|
||||||
output : 'language.json',
|
|
||||||
capture : true,
|
|
||||||
env : nix_env_for_docs,
|
|
||||||
)
|
|
||||||
|
|
||||||
nix3_cli_json = custom_target(
|
nix3_cli_json = custom_target(
|
||||||
command : [ nix, '__dump-cli' ],
|
command : [ nix, '__dump-cli' ],
|
||||||
capture : true,
|
capture : true,
|
||||||
output : 'nix.json',
|
output : 'nix.json',
|
||||||
env : nix_env_for_docs,
|
env : nix_env_for_docs,
|
||||||
|
# FIXME: put the actual lib targets in here? meson have introspection challenge 2024 though.
|
||||||
|
build_always_stale : true,
|
||||||
)
|
)
|
||||||
|
|
||||||
generate_manual_deps = files(
|
generate_manual_deps = files(
|
||||||
'generate-deps.py',
|
'generate-deps.py',
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generates builtins.md and builtin-constants.md.
|
# Generates new-cli pages and conf-file.md.
|
||||||
subdir('src/language')
|
|
||||||
# Generates new-cli pages, experimental-features-shortlist.md, and conf-file.md.
|
|
||||||
subdir('src/command-ref')
|
subdir('src/command-ref')
|
||||||
# Generates experimental-feature-descriptions.md.
|
|
||||||
subdir('src/contributing')
|
|
||||||
# Generates rl-next-generated.md.
|
# Generates rl-next-generated.md.
|
||||||
subdir('src/release-notes')
|
subdir('src/release-notes')
|
||||||
|
|
||||||
@@ -106,6 +60,8 @@ manual = custom_target(
|
|||||||
nix3_cli_files,
|
nix3_cli_files,
|
||||||
experimental_features_shortlist_md,
|
experimental_features_shortlist_md,
|
||||||
experimental_feature_descriptions_md,
|
experimental_feature_descriptions_md,
|
||||||
|
deprecated_features_shortlist_md,
|
||||||
|
deprecated_feature_descriptions_md,
|
||||||
conf_file_md,
|
conf_file_md,
|
||||||
builtins_md,
|
builtins_md,
|
||||||
builtin_constants_md,
|
builtin_constants_md,
|
||||||
@@ -116,20 +72,19 @@ manual = custom_target(
|
|||||||
'manual',
|
'manual',
|
||||||
'markdown',
|
'markdown',
|
||||||
],
|
],
|
||||||
|
install : true,
|
||||||
|
install_dir : [
|
||||||
|
datadir / 'doc/nix',
|
||||||
|
false,
|
||||||
|
],
|
||||||
depfile : 'manual.d',
|
depfile : 'manual.d',
|
||||||
env : {
|
env : {
|
||||||
'RUST_LOG': 'info',
|
'RUST_LOG': 'info',
|
||||||
'MDBOOK_SUBSTITUTE_SEARCH': meson.current_build_dir() / 'src',
|
'MDBOOK_SUBSTITUTE_SEARCH': meson.current_build_dir() / 'src',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
manual_html = manual[0]
|
|
||||||
manual_md = manual[1]
|
manual_md = manual[1]
|
||||||
|
|
||||||
install_subdir(
|
|
||||||
manual_html.full_path(),
|
|
||||||
install_dir : datadir / 'doc/nix',
|
|
||||||
)
|
|
||||||
|
|
||||||
nix_nested_manpages = [
|
nix_nested_manpages = [
|
||||||
[ 'nix-env',
|
[ 'nix-env',
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -192,11 +192,13 @@
|
|||||||
- [Hacking](contributing/hacking.md)
|
- [Hacking](contributing/hacking.md)
|
||||||
- [Testing](contributing/testing.md)
|
- [Testing](contributing/testing.md)
|
||||||
- [Experimental Features](contributing/experimental-features.md)
|
- [Experimental Features](contributing/experimental-features.md)
|
||||||
|
- [Deprecated Features](contributing/deprecated-features.md)
|
||||||
- [CLI guideline](contributing/cli-guideline.md)
|
- [CLI guideline](contributing/cli-guideline.md)
|
||||||
- [C++ style guide](contributing/cxx.md)
|
- [C++ style guide](contributing/cxx.md)
|
||||||
- [Release Notes](release-notes/release-notes.md)
|
- [Release Notes](release-notes/release-notes.md)
|
||||||
- [Upcoming release](release-notes/rl-next.md)
|
- [Upcoming release](release-notes/rl-next.md)
|
||||||
<!-- RELENG-AUTO-INSERTION-MARKER (see releng/release_notes.py) -->
|
<!-- 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.91 (2024-08-12)](release-notes/rl-2.91.md)
|
||||||
- [Lix 2.90 (2024-07-10)](release-notes/rl-2.90.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)
|
- [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
|
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.
|
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.
|
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.
|
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,23 +1,3 @@
|
|||||||
xp_features_json = custom_target(
|
|
||||||
command : [nix, '__dump-xp-features'],
|
|
||||||
capture : true,
|
|
||||||
output : 'xp-features.json',
|
|
||||||
)
|
|
||||||
|
|
||||||
experimental_features_shortlist_md = custom_target(
|
|
||||||
command : nix_eval_for_docs + [
|
|
||||||
'--expr',
|
|
||||||
'import @INPUT0@ (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
|
||||||
],
|
|
||||||
input : [
|
|
||||||
'../../generate-xp-features-shortlist.nix',
|
|
||||||
xp_features_json,
|
|
||||||
],
|
|
||||||
capture : true,
|
|
||||||
output : 'experimental-features-shortlist.md',
|
|
||||||
env : nix_env_for_docs,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Intermediate step for manpage generation.
|
# Intermediate step for manpage generation.
|
||||||
# This splorks the output of generate-manpage.nix as JSON,
|
# This splorks the output of generate-manpage.nix as JSON,
|
||||||
# which gets written as a directory tree below.
|
# which gets written as a directory tree below.
|
||||||
@@ -51,16 +31,23 @@ nix3_cli_files = custom_target(
|
|||||||
|
|
||||||
conf_file_md = custom_target(
|
conf_file_md = custom_target(
|
||||||
command : [
|
command : [
|
||||||
nix_eval_for_docs,
|
python.full_path(),
|
||||||
'--expr',
|
'@SOURCE_ROOT@/lix/code-generation/build_settings.py',
|
||||||
'(import @INPUT0@).showSettings { inlineHTML = true; } (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
'--kernel', host_machine.system(),
|
||||||
|
'--docs', '@OUTPUT@',
|
||||||
|
'--experimental-features', '@SOURCE_ROOT@/lix/libutil/experimental-features',
|
||||||
|
'@INPUT@',
|
||||||
],
|
],
|
||||||
capture : true,
|
|
||||||
input : [
|
input : [
|
||||||
'../../utils.nix',
|
libexpr_setting_definitions,
|
||||||
conf_file_json,
|
libfetchers_setting_definitions,
|
||||||
experimental_features_shortlist_md,
|
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',
|
output : 'conf-file.md',
|
||||||
env : nix_env_for_docs,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
This section describes the notion of *deprecated features*, and how it fits into the big picture of the development of Lix.
|
||||||
|
|
||||||
|
# What are deprecated features?
|
||||||
|
|
||||||
|
Deprecated features are disabled by default, with the intent to eventually remove them.
|
||||||
|
Users must explicitly enable them to keep using them, by toggling the associated [deprecated feature flags](@docroot@/command-ref/conf-file.md#conf-deprecated-features).
|
||||||
|
This allows backwards compatibility and a graceful transition away from undesired features.
|
||||||
|
|
||||||
|
# Which features can be deprecated?
|
||||||
|
|
||||||
|
Undesired features should be soft-deprecated by yielding a warning when used for a significant amount of time before the can be deprecated.
|
||||||
|
Legacy obsolete feature with little to no usage may go through this process faster.
|
||||||
|
Deprecated features should have a migration path to a preferred alternative.
|
||||||
|
|
||||||
|
# Lifecycle of a deprecated feature
|
||||||
|
|
||||||
|
This description is not normative, but a feature removal may roughly happen like this:
|
||||||
|
|
||||||
|
1. Add a warning when the feature is being used.
|
||||||
|
2. Disable the feature by default, putting it behind a deprecated feature flag.
|
||||||
|
- If disabling the feature started out as an opt-in experimental feature, turn that experimental flag into a no-op or remove it entirely.
|
||||||
|
For example, `--extra-experimental-features=no-url-literals` becomes `--extra-deprecated-features=url-literals`.
|
||||||
|
3. Decide on a time frame for how long that feature will still be supported for backwards compatibility, and clearly communicate that in the error messages.
|
||||||
|
- Sometimes, automatic migration to alternatives is possible, and such should be provided if possible
|
||||||
|
- At least one NixOS release cycle should be the minimum
|
||||||
|
4. Finally remove the feature entirely, only keeping the error message for those still using it.
|
||||||
|
|
||||||
|
# Relation to language versioning
|
||||||
|
|
||||||
|
Obviously, removing anything breaks backwards compatibility.
|
||||||
|
In an ideal world, we'd have SemVer controls over the language and its features, cleanly allowing us to make breaking changes.
|
||||||
|
See https://wiki.lix.systems/books/lix-contributors/page/language-versioning and [RFC 137](https://github.com/nixos/rfcs/pull/137) for efforts on that.
|
||||||
|
However, we do not live in such an ideal world, and currently this goal is so far away, that "just disable it with some back-compat for a couple of years" is the most realistic solution, especially for comparatively minor changes.
|
||||||
|
|
||||||
|
# Currently available deprecated features
|
||||||
|
|
||||||
|
{{#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
|
# 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.:
|
All targets may be addressed as their output, relative to the build directory, e.g.:
|
||||||
|
|
||||||
```bash
|
```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.
|
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:
|
To build a specific object file, use Ninja directly and specify the output file relative to the build directory:
|
||||||
|
|
||||||
```bash
|
```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:
|
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`]:
|
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-linux`
|
||||||
- `x86_64-darwin`
|
- `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`.
|
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.
|
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,15 +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@ (builtins.fromJSON (builtins.readFile @INPUT1@))',
|
|
||||||
],
|
|
||||||
input : [
|
|
||||||
'../../generate-xp-features.nix',
|
|
||||||
xp_features_json,
|
|
||||||
],
|
|
||||||
capture : true,
|
|
||||||
output : 'experimental-feature-descriptions.md',
|
|
||||||
)
|
|
||||||
@@ -13,7 +13,7 @@ The unit tests are defined using the [googletest] and [rapidcheck] frameworks.
|
|||||||
>
|
>
|
||||||
> ```
|
> ```
|
||||||
> …
|
> …
|
||||||
> ├── src
|
> ├── lix
|
||||||
> │ ├── libexpr
|
> │ ├── libexpr
|
||||||
> │ │ ├── …
|
> │ │ ├── …
|
||||||
> │ │ ├── value
|
> │ │ ├── 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.
|
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`.
|
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
|
### 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
|
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
|
### 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.
|
- `_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`,
|
Used by `lix/libfetchers/git.cc`, `lix/libstore/http-binary-cache-store.cc`,
|
||||||
`src/libstore/local-binary-cache-store.cc`. Seems to be for forcing Git
|
`lix/libstore/local-binary-cache-store.cc`. Seems to be for forcing Git
|
||||||
clones of `git+file://` URLs, making the HTTP binary
|
clones of `git+file://` URLs, making the HTTP binary
|
||||||
cache store accept `file://` URLs (presumably passing them to curl?), and
|
cache store accept `file://` URLs (presumably passing them to curl?), and
|
||||||
unknown reasons for the local binary cache.
|
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.
|
`structuredAttrs` documentation.
|
||||||
- `NIX_BIN_DIR`, `NIX_STORE_DIR` (or its inconsistently-used old alias `NIX_STORE`), `NIX_DATA_DIR`,
|
- `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` -
|
`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
|
**Expected value**: a directory
|
||||||
- `NIX_DAEMON_SOCKET_PATH` (optional) - Overrides the daemon socket path from `$NIX_STATE_DIR/daemon-socket/socket`.
|
- `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
|
# Installing a Binary Distribution
|
||||||
|
|
||||||
See https://lix.systems/install/ for more details.
|
See <https://lix.systems/install/> for more details.
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,10 @@ All users of the Lix daemon may do the following to bring things into the Nix st
|
|||||||
- Input-addressed, so they are run in the sandbox with no network access, with the following exceptions:
|
- Input-addressed, so they are run in the sandbox with no network access, with the following exceptions:
|
||||||
|
|
||||||
- The (poorly named, since it is not *just* about chroot) property `__noChroot` is set on the derivation and `sandbox` is set to `relaxed`.
|
- The (poorly named, since it is not *just* about chroot) property `__noChroot` is set on the derivation and `sandbox` is set to `relaxed`.
|
||||||
- On macOS, the derivation property `__darwinAllowLocalNetworking` allows network access to localhost from input-addressed derivations regardless of the `sandbox` setting value. This property exists with such semantics because macOS has no network namespace equivalent to isolate individual processes' localhost networking.
|
- On macOS, the derivation property `__darwinAllowLocalNetworking` allows network access to localhost from input-addressed derivations regardless of the `sandbox` setting value.
|
||||||
|
This property exists with such semantics because macOS has no network namespace equivalent to isolate individual processes' localhost networking.
|
||||||
|
- On macOS, the derivation property `__sandboxProfile` accepts extra sandbox profile S-expressions, allowing derivations to bypass arbitrary parts of the sandbox without altogether disabling it.
|
||||||
|
This is only permitted when `sandbox` is set to `relaxed`.
|
||||||
- Output-addressed, so they are run with network access but their result must match an expected hash.
|
- Output-addressed, so they are run with network access but their result must match an expected hash.
|
||||||
|
|
||||||
Trusted users may set any setting, including `sandbox = false`, so the sandbox state can be different at runtime from what is described in `nix.conf` for builds invoked with such settings.
|
Trusted users may set any setting, including `sandbox = false`, so the sandbox state can be different at runtime from what is described in `nix.conf` for builds invoked with such settings.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ These constants are built into the Nix language evaluator:
|
|||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
|
||||||
{{#include @generated@/language/builtin-constants.md}}
|
{{#include @generated@/../../../lix/libexpr/builtin-constants.md}}
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ For convenience, some built-ins can be accessed directly:
|
|||||||
<dd><p><var>derivation</var> is described in
|
<dd><p><var>derivation</var> is described in
|
||||||
<a href="derivations.md">its own section</a>.</p></dd>
|
<a href="derivations.md">its own section</a>.</p></dd>
|
||||||
|
|
||||||
{{#include @generated@/language/builtins.md}}
|
{{#include @generated@/../../../lix/libexpr/builtins.md}}
|
||||||
|
|
||||||
</dl>
|
</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 conjunction (`AND`) | *bool* `&&` *bool* | left | 12 |
|
||||||
| Logical disjunction (`OR`) | *bool* <code>\|\|</code> *bool* | left | 13 |
|
| Logical disjunction (`OR`) | *bool* <code>\|\|</code> *bool* | left | 13 |
|
||||||
| [Logical implication] | *bool* `->` *bool* | none | 14 |
|
| [Logical implication] | *bool* `->` *bool* | none | 14 |
|
||||||
| \[Experimental\] [Function piping] | *expr* |> *func* | left | 15 |
|
| \[Experimental\] [Function piping] | *expr* `\|>` *func* | left | 15 |
|
||||||
| \[Experimental\] [Function piping] | *expr* <| *func* | right | 16 |
|
| \[Experimental\] [Function piping] | *expr* `<\|` *func* | right | 16 |
|
||||||
|
|
||||||
[string]: ./values.md#type-string
|
[string]: ./values.md#type-string
|
||||||
[path]: ./values.md#type-path
|
[path]: ./values.md#type-path
|
||||||
|
|||||||
@@ -77,12 +77,6 @@
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, as a convenience, *URIs* as defined in appendix B of
|
|
||||||
[RFC 2396](http://www.ietf.org/rfc/rfc2396.txt) can be written *as
|
|
||||||
is*, without quotes. For instance, the string
|
|
||||||
`"http://example.org/foo.tar.bz2"` can also be written as
|
|
||||||
`http://example.org/foo.tar.bz2`.
|
|
||||||
|
|
||||||
- <a id="type-number" href="#type-number">Number</a>
|
- <a id="type-number" href="#type-number">Number</a>
|
||||||
|
|
||||||
Numbers, which can be *integers* (like `123`) or *floating point*
|
Numbers, which can be *integers* (like `123`) or *floating point*
|
||||||
|
|||||||
@@ -0,0 +1,561 @@
|
|||||||
|
# Lix 2.92 "Bombe glacée" (2025-01-18)
|
||||||
|
# Lix 2.92.3 (2025-06-30)
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Revert CVE-2025-52992 failed mitigation [fj#883](https://git.lix.systems/lix-project/lix/issues/883) [fj#887](https://git.lix.systems/lix-project/lix/issues/887) [cl/3432](https://gerrit.lix.systems/c/lix/+/3432) [cl/3525](https://gerrit.lix.systems/c/lix/+/3525) [cl/3526](https://gerrit.lix.systems/c/lix/+/3526) [cl/3527](https://gerrit.lix.systems/c/lix/+/3527)
|
||||||
|
|
||||||
|
Following the initial mitigation of **CVE-2025-52992** in `cl/3432`, we
|
||||||
|
received reports of **unexpected deletion of in-use store paths**.
|
||||||
|
|
||||||
|
Upon investigation, we found that the patch did **not correctly cancel all
|
||||||
|
automatic deleters**, resulting in potentially critical path loss during normal
|
||||||
|
operation.
|
||||||
|
|
||||||
|
Given the severity and time-sensitive nature of the situation ([see incident
|
||||||
|
report](https://lix.systems/blog/2025-06-27-lix-critical-bug/)), we evaluated
|
||||||
|
possible options to repair the behavior safely. However, we concluded that a
|
||||||
|
rushed fix would either
|
||||||
|
|
||||||
|
* **Overdelete**, i.e. breaking running systems, or,
|
||||||
|
* **Underdelete**, effectively **reopening CVE-2025-52992** while leaving
|
||||||
|
orphaned paths behind.
|
||||||
|
|
||||||
|
As **CVE-2025-52992 has no known exploit vector**, and correctness is critical
|
||||||
|
in the Lix project, we have **fully reverted the previous mitigations**.
|
||||||
|
|
||||||
|
The affected patches (`cl/3432`) have been rolled back for the time being.
|
||||||
|
|
||||||
|
Moving forward, the Lix team will rework this code path in a **long-term,
|
||||||
|
correctness-first fix** on the main branch. We will explore backporting it to
|
||||||
|
stable channels once its safety is assured.
|
||||||
|
|
||||||
|
We are deeply sorry for the stability incident and the Lix team remain
|
||||||
|
available for assisting you in recovering your systems.
|
||||||
|
|
||||||
|
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||||
|
- Fallback to safe temp dir when build-dir is unwritable [fj#876](https://git.lix.systems/lix-project/lix/issues/876) [cl/3503](https://gerrit.lix.systems/c/lix/+/3503)
|
||||||
|
|
||||||
|
Non-daemon builds started failing with a permission error after introducing the `build-dir` option:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nix build --store ~/scratch nixpkgs#hello --rebuild
|
||||||
|
error: creating directory '/nix/var/nix/builds/nix-build-hello-2.12.2.drv-0': Permission denied
|
||||||
|
```
|
||||||
|
|
||||||
|
This happens because:
|
||||||
|
|
||||||
|
1. These builds are not run via the daemon, which owns `/nix/var/nix/builds`.
|
||||||
|
2. The user lacks permissions for that path.
|
||||||
|
|
||||||
|
We considered making `build-dir` a store-level option and defaulting it to `<chroot-root>/nix/var/nix/builds` for chroot stores, but opted instead for a fallback: if the default fails, Nix now creates a safe build directory under `/tmp`.
|
||||||
|
|
||||||
|
To avoid CVE-2025-52991, the fallback uses an extra path component between `/tmp` and the build dir.
|
||||||
|
|
||||||
|
**Note**: this fallback clutters `/tmp` with build directories that are not cleaned up. To prevent this, explicitly set `build-dir` to a path managed by Lix, even for local workloads.
|
||||||
|
|
||||||
|
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||||
|
|
||||||
|
|
||||||
|
# Lix 2.92.2 (2025-06-23)
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
- Fixed output derivations can be run using `pasta` network isolation [fj#285](https://git.lix.systems/lix-project/lix/issues/285) [cl/3430](https://gerrit.lix.systems/c/lix/+/3430)
|
||||||
|
|
||||||
|
Fixed output derivations traditionally run in the host network namespace.
|
||||||
|
On Linux this allows such derivations to communicate with other sandboxes
|
||||||
|
or the host using the abstract Unix domains socket namespace; this hasn't
|
||||||
|
been unproblematic in the past and has been used in two distinct exploits
|
||||||
|
to break out of the sandbox. For this reason fixed output derivations can
|
||||||
|
now run in a network namespace (provided by [`pasta`]), restricted to TCP
|
||||||
|
and UDP communication with the rest of the world. When enabled this could
|
||||||
|
be a breaking change and we classify it as such, even though we don't yet
|
||||||
|
enable or require such isolation by default. We may enforce this in later
|
||||||
|
releases of Lix once we have sufficient confidence that breakage is rare.
|
||||||
|
|
||||||
|
[`pasta`]: https://passt.top/
|
||||||
|
|
||||||
|
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) and [puck](https://git.lix.systems/puck) for this.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Always clean up scratch paths after derivations failed to build [cl/3432](https://gerrit.lix.systems/c/lix/+/3432)
|
||||||
|
|
||||||
|
Previously, scratch paths created during builds were not always cleaned up if
|
||||||
|
the derivation failed, potentially leaving behind unnecessary temporary files
|
||||||
|
or directories in the Nix store.
|
||||||
|
|
||||||
|
This fix ensures that such paths are consistently removed after a failed build,
|
||||||
|
improving Nix store hygiene, hardening Lix against mis-reuse of failed builds
|
||||||
|
scratch paths.
|
||||||
|
|
||||||
|
Many thanks to [Raito Bezarius](https://git.lix.systems/raito) and [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||||
|
- `build-dir` no longer defaults to `temp-dir` [cl/3431](https://gerrit.lix.systems/c/lix/+/3431)
|
||||||
|
|
||||||
|
The directory in which temporary build directories are created no longer defaults
|
||||||
|
to the value of the `temp-dir` setting to avoid builders making their directories
|
||||||
|
world-accessible. This behavior has been used to escape the build sandbox and can
|
||||||
|
cause build impurities even when not used maliciously. We now default to `builds`
|
||||||
|
in `NIX_STATE_DIR` (which is `/nix/var/nix/builds` in the default configuration).
|
||||||
|
|
||||||
|
Many thanks to [eldritch horrors](https://git.lix.systems/pennae) for this.
|
||||||
|
- Forbid impure path accesses in pure evaluation mode again [cl/2708](https://gerrit.lix.systems/c/lix/+/2708)
|
||||||
|
|
||||||
|
Lix 2.92.0 mistakenly started allowing the access to ancestors of allowed paths in pure evaluation mode.
|
||||||
|
This made it possible to bypass the purity restrictions, for example by copying arbitrary files to the store:
|
||||||
|
```nix
|
||||||
|
builtins.path {
|
||||||
|
path = "/";
|
||||||
|
filter = …;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Restore the previous behaviour of prohibiting such impure accesses.
|
||||||
|
|
||||||
|
Many thanks to [alois31](https://git.lix.systems/alois31) for this.
|
||||||
|
- Parsing failures in flake.lock no longer crash Lix [fj#559](https://git.lix.systems/lix-project/lix/issues/559) [cl/2401](https://gerrit.lix.systems/c/lix/+/2401)
|
||||||
|
|
||||||
|
Failure to parse `flake.lock` no longer hard-crashes Lix and instead produces a nice error message.
|
||||||
|
|
||||||
|
```
|
||||||
|
error:
|
||||||
|
… while updating the lock file of flake 'git+file:///Users/jade/lix/lix2'
|
||||||
|
|
||||||
|
… while parsing the lock file at /nix/store/mm5dqh8a729yazzj82cjffxl97n5c62s-source//flake.lock
|
||||||
|
|
||||||
|
error: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal;
|
||||||
|
last read: '#'
|
||||||
|
```
|
||||||
|
|
||||||
|
Many thanks to [gilice](https://git.lix.systems/gilice) for this.
|
||||||
|
- Fix `--debugger --ignore-try` [cl/2440](https://gerrit.lix.systems/c/lix/+/2440)
|
||||||
|
|
||||||
|
When in debug mode (e.g. from using the `--debugger` flag), enabling [`ignore-try`](@docroot@/command-ref/conf-file.md#conf-ignore-try) once again properly disables debug REPLs within [`builtins.tryEval`](@docroot@/language/builtins.md#builtins-tryEval) calls. Previously, a debug REPL would be started as if `ignore-try` was disabled, but that REPL wouldn't actually be in debug mode, and upon exiting the REPL the evaluating process would segfault.
|
||||||
|
|
||||||
|
Many thanks to [Dusk Banks](https://git.lix.systems/bb010g) for this.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Lix 2.92.0 (2025-01-18)
|
||||||
|
|
||||||
|
## 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": {
|
"nix2container": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720642556,
|
"lastModified": 1724996935,
|
||||||
"narHash": "sha256-qsnqk13UmREKmRT7c8hEnz26X3GFFyIQrqx4EaRc1Is=",
|
"narHash": "sha256-njRK9vvZ1JJsP8oV2OgkBrpJhgQezI03S7gzskCcHos=",
|
||||||
"owner": "nlewo",
|
"owner": "nlewo",
|
||||||
"repo": "nix2container",
|
"repo": "nix2container",
|
||||||
"rev": "3853e5caf9ad24103b13aa6e0e8bcebb47649fe4",
|
"rev": "fa6bb0a1159f55d071ba99331355955ae30b3401",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -34,16 +34,16 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721931987,
|
"lastModified": 1733348545,
|
||||||
"narHash": "sha256-1Zg8LY0T5EfXtv0Kf4M6SFnjH7Eto4VV+EKJ/YSnhiI=",
|
"narHash": "sha256-b4JrUmqT0vFNx42aEN9LTWOHomkTKL/ayLopflVf81U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e21630230c77140bc6478a21cd71e8bb73706fce",
|
"rev": "9ecb50d2fae8680be74c08bb0a995c5383747f89",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-24.05-small",
|
"ref": "nixos-24.11-small",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -67,11 +67,11 @@
|
|||||||
"pre-commit-hooks": {
|
"pre-commit-hooks": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721042469,
|
"lastModified": 1733318908,
|
||||||
"narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=",
|
"narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "f451c19376071a90d8c58ab1a953c6e9840527fd",
|
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
description = "Lix: A modern, delicious implementation of the Nix package manager";
|
description = "Lix: A modern, delicious implementation of the Nix package manager";
|
||||||
|
|
||||||
inputs = {
|
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";
|
nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||||
pre-commit-hooks = {
|
pre-commit-hooks = {
|
||||||
url = "github:cachix/git-hooks.nix";
|
url = "github:cachix/git-hooks.nix";
|
||||||
@@ -99,9 +99,10 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
stdenvs = [
|
stdenvs = [
|
||||||
"gccStdenv"
|
# see assertion in package.nix why these two are disabled
|
||||||
|
# "stdenv"
|
||||||
|
# "gccStdenv"
|
||||||
"clangStdenv"
|
"clangStdenv"
|
||||||
"stdenv"
|
|
||||||
"libcxxStdenv"
|
"libcxxStdenv"
|
||||||
"ccacheStdenv"
|
"ccacheStdenv"
|
||||||
];
|
];
|
||||||
@@ -121,7 +122,11 @@
|
|||||||
name = "${stdenvName}Packages";
|
name = "${stdenvName}Packages";
|
||||||
value = f stdenvName;
|
value = f stdenvName;
|
||||||
}) stdenvs
|
}) 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.
|
# Memoize nixpkgs for different platforms for efficiency.
|
||||||
nixpkgsFor = forAllSystems (
|
nixpkgsFor = forAllSystems (
|
||||||
@@ -133,14 +138,7 @@
|
|||||||
localSystem = {
|
localSystem = {
|
||||||
inherit system;
|
inherit system;
|
||||||
};
|
};
|
||||||
crossSystem =
|
crossSystem = if crossSystem == null then null else { system = crossSystem; };
|
||||||
if crossSystem == null then
|
|
||||||
null
|
|
||||||
else
|
|
||||||
{
|
|
||||||
system = crossSystem;
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (crossSystem == "x86_64-freebsd") { useLLVM = true; };
|
|
||||||
overlays = [ (overlayFor (p: p.${stdenv})) ];
|
overlays = [ (overlayFor (p: p.${stdenv})) ];
|
||||||
};
|
};
|
||||||
stdenvs = forAllStdenvs (make-pkgs null);
|
stdenvs = forAllStdenvs (make-pkgs null);
|
||||||
@@ -149,7 +147,7 @@
|
|||||||
{
|
{
|
||||||
inherit stdenvs native;
|
inherit stdenvs native;
|
||||||
static = native.pkgsStatic;
|
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
|
# A Nixpkgs overlay that overrides the 'nix' and
|
||||||
# 'nix.perl-bindings' packages.
|
# 'nix.perl-bindings' packages.
|
||||||
overlays.default = overlayFor (p: p.stdenv);
|
overlays.default = overlayFor (p: p.clangStdenv);
|
||||||
|
|
||||||
hydraJobs = {
|
hydraJobs = {
|
||||||
# Binary package for various platforms.
|
# Binary package for various platforms.
|
||||||
@@ -264,6 +262,8 @@
|
|||||||
nix = pkgs.callPackage ./package.nix {
|
nix = pkgs.callPackage ./package.nix {
|
||||||
inherit versionSuffix officialRelease buildUnreleasedNotes;
|
inherit versionSuffix officialRelease buildUnreleasedNotes;
|
||||||
inherit (pkgs) build-release-notes;
|
inherit (pkgs) build-release-notes;
|
||||||
|
# Required since we don't support gcc stdenv
|
||||||
|
stdenv = pkgs.clangStdenv;
|
||||||
internalApiDocs = true;
|
internalApiDocs = true;
|
||||||
busybox-sandbox-shell = pkgs.busybox-sandbox-shell;
|
busybox-sandbox-shell = pkgs.busybox-sandbox-shell;
|
||||||
};
|
};
|
||||||
@@ -321,6 +321,8 @@
|
|||||||
inherit (nixpkgs) pkgs;
|
inherit (nixpkgs) pkgs;
|
||||||
in
|
in
|
||||||
pkgs.callPackage ./package.nix {
|
pkgs.callPackage ./package.nix {
|
||||||
|
# Required since we don't support gcc stdenv
|
||||||
|
stdenv = pkgs.clangStdenv;
|
||||||
versionSuffix = "";
|
versionSuffix = "";
|
||||||
lintInsteadOfBuild = true;
|
lintInsteadOfBuild = true;
|
||||||
};
|
};
|
||||||
@@ -348,10 +350,10 @@
|
|||||||
name = "nixpkgs-lib-tests";
|
name = "nixpkgs-lib-tests";
|
||||||
paths =
|
paths =
|
||||||
[ testWithNix ]
|
[ testWithNix ]
|
||||||
# FIXME: This is disabled on darwin due to a nixpkgs bug https://github.com/NixOS/nixpkgs/issues/319147
|
# NOTE: nixpkgs 24.11 is being ... *creative*, and requires this dance to override
|
||||||
# After that is fixed, it should be restored to use lib/tests/release.nix as before, rather than this reimplementation.
|
# the evaluator used for the test. it will break again in the future, don't worry.
|
||||||
++ lib.optionals pkgs.stdenv.isLinux [
|
++ 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
|
let
|
||||||
pkgs = nixpkgsFor.${system}.cross.${crossSystem};
|
pkgs = nixpkgsFor.${system}.cross.${crossSystem};
|
||||||
in
|
in
|
||||||
makeShell pkgs pkgs.stdenv
|
makeShell pkgs pkgs.clangStdenv
|
||||||
))
|
))
|
||||||
// {
|
// {
|
||||||
default = self.devShells.${system}.native-clangStdenvPackages;
|
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
|
||||||
@@ -1,32 +1,28 @@
|
|||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <iomanip>
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "machines.hh"
|
#include "lix/libstore/machines.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "pathlocks.hh"
|
#include "lix/libstore/pathlocks.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "serialise.hh"
|
#include "lix/libutil/serialise.hh"
|
||||||
#include "build-result.hh"
|
#include "lix/libstore/build-result.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "local-store.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libstore/local-store.hh"
|
||||||
#include "experimental-features.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "hash.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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string escapeUri(std::string uri)
|
std::string escapeUri(std::string uri)
|
||||||
{
|
{
|
||||||
@@ -53,11 +49,11 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
|
|||||||
|
|
||||||
static bool allSupportedLocally(Store & store, const std::set<std::string>& requiredFeatures) {
|
static bool allSupportedLocally(Store & store, const std::set<std::string>& requiredFeatures) {
|
||||||
for (auto & feature : requiredFeatures)
|
for (auto & feature : requiredFeatures)
|
||||||
if (!store.systemFeatures.get().count(feature)) return false;
|
if (!store.config().systemFeatures.get().count(feature)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int main_build_remote(int argc, char * * argv)
|
static int main_build_remote(std::string programName, Strings argv)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
logger = makeJSONLogger(*logger);
|
logger = makeJSONLogger(*logger);
|
||||||
@@ -69,10 +65,10 @@ static int main_build_remote(int argc, char * * argv)
|
|||||||
/* If we ever use the common args framework, make sure to
|
/* If we ever use the common args framework, make sure to
|
||||||
remove initPlugins below and initialize settings first.
|
remove initPlugins below and initialize settings first.
|
||||||
*/
|
*/
|
||||||
if (argc != 2)
|
if (argv.size() != 1)
|
||||||
throw UsageError("called without required arguments");
|
throw UsageError("called without required arguments");
|
||||||
|
|
||||||
verbosity = (Verbosity) std::stoll(argv[1]);
|
verbosity = (Verbosity) std::stoll(argv.front());
|
||||||
|
|
||||||
FdSource source(STDIN_FILENO);
|
FdSource source(STDIN_FILENO);
|
||||||
|
|
||||||
@@ -94,7 +90,7 @@ static int main_build_remote(int argc, char * * argv)
|
|||||||
that gets cleared on reboot, but it wouldn't work on macOS. */
|
that gets cleared on reboot, but it wouldn't work on macOS. */
|
||||||
auto currentLoadName = "/current-load";
|
auto currentLoadName = "/current-load";
|
||||||
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
|
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
|
||||||
currentLoad = std::string { localStore->stateDir } + currentLoadName;
|
currentLoad = std::string { localStore->config().stateDir } + currentLoadName;
|
||||||
else
|
else
|
||||||
currentLoad = settings.nixStateDir + currentLoadName;
|
currentLoad = settings.nixStateDir + currentLoadName;
|
||||||
|
|
||||||
@@ -139,7 +135,7 @@ static int main_build_remote(int argc, char * * argv)
|
|||||||
while (true) {
|
while (true) {
|
||||||
bestSlotLock.reset();
|
bestSlotLock.reset();
|
||||||
AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
|
AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
|
||||||
lockFile(lock.get(), ltWrite, true);
|
lockFile(lock.get(), ltWrite);
|
||||||
|
|
||||||
bool rightType = false;
|
bool rightType = false;
|
||||||
|
|
||||||
@@ -158,7 +154,7 @@ static int main_build_remote(int argc, char * * argv)
|
|||||||
uint64_t load = 0;
|
uint64_t load = 0;
|
||||||
for (uint64_t slot = 0; slot < m.maxJobs; ++slot) {
|
for (uint64_t slot = 0; slot < m.maxJobs; ++slot) {
|
||||||
auto slotLock = openSlotLock(m, slot);
|
auto slotLock = openSlotLock(m, slot);
|
||||||
if (lockFile(slotLock.get(), ltWrite, false)) {
|
if (tryLockFile(slotLock.get(), ltWrite)) {
|
||||||
if (!free) {
|
if (!free) {
|
||||||
free = std::move(slotLock);
|
free = std::move(slotLock);
|
||||||
}
|
}
|
||||||
@@ -281,12 +277,8 @@ connected:
|
|||||||
{
|
{
|
||||||
Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));
|
Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));
|
||||||
|
|
||||||
auto old = signal(SIGALRM, handleAlarm);
|
if (!unsafeLockFileSingleThreaded(uploadLock.get(), ltWrite, std::chrono::minutes(15)))
|
||||||
alarm(15 * 60);
|
|
||||||
if (!lockFile(uploadLock.get(), ltWrite, true))
|
|
||||||
printError("somebody is hogging the upload lock for '%s', continuing...");
|
printError("somebody is hogging the upload lock for '%s', continuing...");
|
||||||
alarm(0);
|
|
||||||
signal(SIGALRM, old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;
|
auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;
|
||||||
@@ -311,7 +303,7 @@ connected:
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See the very large comment in `case WorkerProto::Op::BuildDerivation:` in
|
// 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;
|
// This condition mirrors that: that code enforces the "rules" outlined there;
|
||||||
// we do the best we can given those "rules".
|
// we do the best we can given those "rules".
|
||||||
@@ -391,4 +383,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 "dotgraph.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "graphml.hh"
|
#include "graphml.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
|
||||||
namespace nix {
|
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 <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "parsed-derivations.hh"
|
#include "lix/libstore/parsed-derivations.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "current-process.hh"
|
#include "lix/libutil/current-process.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "path-with-outputs.hh"
|
#include "lix/libstore/path-with-outputs.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "shlex.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;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
extern char * * environ __attribute__((weak));
|
static void main_nix_build(std::string programName, Strings argv)
|
||||||
|
|
||||||
static void main_nix_build(int argc, char * * argv)
|
|
||||||
{
|
{
|
||||||
auto dryRun = false;
|
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 pure = false;
|
||||||
auto fromArgs = false;
|
auto fromArgs = false;
|
||||||
auto packages = false;
|
auto packages = false;
|
||||||
@@ -53,8 +56,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
std::string script;
|
std::string script;
|
||||||
std::vector<std::string> savedArgs;
|
std::vector<std::string> savedArgs;
|
||||||
|
|
||||||
AutoDelete tmpDir(createTempDir("", myName));
|
|
||||||
|
|
||||||
std::string outLink = "./result";
|
std::string outLink = "./result";
|
||||||
|
|
||||||
// List of environment variables kept for --pure
|
// 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"
|
"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,
|
// 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
|
// if we have at least one argument, it's the name of an
|
||||||
// executable file, and it starts with "#!".
|
// executable file, and it starts with "#!".
|
||||||
if (runEnv && argc > 1) {
|
if (runEnv && !argv.empty()) {
|
||||||
script = argv[1];
|
script = argv.front();
|
||||||
try {
|
try {
|
||||||
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
||||||
if (std::regex_search(lines.front(), std::regex("^#!"))) {
|
if (std::regex_search(lines.front(), std::regex("^#!"))) {
|
||||||
lines.pop_front();
|
lines.pop_front();
|
||||||
inShebang = true;
|
inShebang = true;
|
||||||
for (int i = 2; i < argc; ++i)
|
savedArgs = {std::next(argv.begin()), argv.end()};
|
||||||
savedArgs.push_back(argv[i]);
|
argv.clear();
|
||||||
args.clear();
|
|
||||||
for (auto line : lines) {
|
for (auto line : lines) {
|
||||||
line = chomp(line);
|
line = chomp(line);
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
if (std::regex_match(line, match, std::regex("^#!\\s*nix-shell\\s+(.*)$")))
|
if (std::regex_match(line, match, std::regex("^#!\\s*nix-shell\\s+(.*)$")))
|
||||||
for (const auto & word : shell_split(match[1].str()))
|
for (const auto & word : shell_split(match[1].str()))
|
||||||
args.push_back(word);
|
argv.push_back(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SysError &) { }
|
} 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) {
|
MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||||
if (*arg == "--help") {
|
if (*arg == "--help") {
|
||||||
deletePath(tmpDir);
|
|
||||||
showManPage(myName);
|
showManPage(myName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +106,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
; // obsolete
|
; // obsolete
|
||||||
|
|
||||||
else if (*arg == "--no-out-link" || *arg == "--no-link")
|
else if (*arg == "--no-out-link" || *arg == "--no-link")
|
||||||
outLink = (Path) tmpDir + "/result";
|
outLink = "";
|
||||||
|
|
||||||
else if (*arg == "--attr" || *arg == "-A")
|
else if (*arg == "--attr" || *arg == "-A")
|
||||||
attrPaths.push_back(getArg(*arg, arg, end));
|
attrPaths.push_back(getArg(*arg, arg, end));
|
||||||
@@ -191,23 +186,28 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
myArgs.parseCmdline(args);
|
myArgs.parseCmdline(argv);
|
||||||
|
|
||||||
if (packages && fromArgs)
|
if (packages && fromArgs)
|
||||||
throw UsageError("'-p' and '-E' are mutually exclusive");
|
throw UsageError("'-p' and '-E' are mutually exclusive");
|
||||||
|
|
||||||
|
AutoDelete tmpDir(createTempDir("", myName));
|
||||||
|
if (outLink.empty())
|
||||||
|
outLink = (Path) tmpDir + "/result";
|
||||||
|
|
||||||
auto store = openStore();
|
auto store = openStore();
|
||||||
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
||||||
|
|
||||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, evalStore, store);
|
auto evaluator = std::make_unique<Evaluator>(myArgs.searchPath, evalStore, store);
|
||||||
state->repair = myArgs.repair;
|
evaluator->repair = myArgs.repair;
|
||||||
|
auto state = evaluator->begin();
|
||||||
if (myArgs.repair) buildMode = bmRepair;
|
if (myArgs.repair) buildMode = bmRepair;
|
||||||
|
|
||||||
auto autoArgs = myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*evaluator);
|
||||||
|
|
||||||
auto autoArgsWithInNixShell = autoArgs;
|
auto autoArgsWithInNixShell = autoArgs;
|
||||||
if (runEnv) {
|
if (runEnv) {
|
||||||
auto newArgs = state->buildBindings(autoArgsWithInNixShell->size() + 1);
|
auto newArgs = evaluator->buildBindings(autoArgsWithInNixShell->size() + 1);
|
||||||
newArgs.alloc("inNixShell").mkBool(true);
|
newArgs.alloc("inNixShell").mkBool(true);
|
||||||
for (auto & i : *autoArgs) newArgs.insert(i);
|
for (auto & i : *autoArgs) newArgs.insert(i);
|
||||||
autoArgsWithInNixShell = newArgs.finish();
|
autoArgsWithInNixShell = newArgs.finish();
|
||||||
@@ -237,11 +237,11 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
std::vector<std::reference_wrapper<Expr>> exprs;
|
std::vector<std::reference_wrapper<Expr>> exprs;
|
||||||
|
|
||||||
if (readStdin)
|
if (readStdin)
|
||||||
exprs = {state->parseStdin()};
|
exprs = {evaluator->parseStdin()};
|
||||||
else
|
else
|
||||||
for (auto i : left) {
|
for (auto i : left) {
|
||||||
if (fromArgs)
|
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 {
|
else {
|
||||||
auto absolute = i;
|
auto absolute = i;
|
||||||
try {
|
try {
|
||||||
@@ -249,12 +249,16 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
} catch (Error & e) {};
|
} catch (Error & e) {};
|
||||||
auto [path, outputNames] = parsePathWithOutputs(absolute);
|
auto [path, outputNames] = parsePathWithOutputs(absolute);
|
||||||
if (evalStore->isStorePath(path) && path.ends_with(".drv"))
|
if (evalStore->isStorePath(path) && path.ends_with(".drv"))
|
||||||
drvs.push_back(DrvInfo(*state, evalStore, absolute));
|
drvs.push_back(DrvInfo(evalStore, absolute));
|
||||||
else
|
else
|
||||||
/* If we're in a #! script, interpret filenames
|
/* If we're in a #! script, interpret filenames
|
||||||
relative to the script. */
|
relative to the script. */
|
||||||
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
|
exprs.push_back(evaluator->parseExprFromFile(
|
||||||
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
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;
|
bool add = false;
|
||||||
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
||||||
for (auto & i : v.lambda.fun->formals->formals) {
|
for (auto & i : v.lambda.fun->formals->formals) {
|
||||||
if (state->symbols[i.name] == "inNixShell") {
|
if (evaluator->symbols[i.name] == "inNixShell") {
|
||||||
add = true;
|
add = true;
|
||||||
break;
|
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) {
|
auto buildPaths = [&](const std::vector<DerivedPath> & paths) {
|
||||||
/* Note: we do this even when !printMissing to efficiently
|
/* 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");
|
throw UsageError("nix-shell requires a single derivation");
|
||||||
|
|
||||||
auto & drvInfo = drvs.front();
|
auto & drvInfo = drvs.front();
|
||||||
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath());
|
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath(*state));
|
||||||
|
|
||||||
std::vector<DerivedPath> pathsToBuild;
|
std::vector<DerivedPath> pathsToBuild;
|
||||||
RealisedPath::Set pathsToCopy;
|
RealisedPath::Set pathsToCopy;
|
||||||
@@ -337,9 +341,9 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
if (!shell) {
|
if (!shell) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto & expr = state->parseExprFromString(
|
auto & expr = evaluator->parseExprFromString(
|
||||||
"(import <nixpkgs> {}).bashInteractive",
|
"(import <nixpkgs> {}).bashInteractive",
|
||||||
state->rootPath(CanonPath::fromCwd()));
|
CanonPath::fromCwd());
|
||||||
|
|
||||||
Value v;
|
Value v;
|
||||||
state->eval(expr, v);
|
state->eval(expr, v);
|
||||||
@@ -348,7 +352,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
if (!drv)
|
if (!drv)
|
||||||
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
|
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 {
|
pathsToBuild.push_back(DerivedPath::Built {
|
||||||
.drvPath = makeConstantStorePathRef(bashDrv),
|
.drvPath = makeConstantStorePathRef(bashDrv),
|
||||||
.outputs = OutputsSpec::Names {"out"},
|
.outputs = OutputsSpec::Names {"out"},
|
||||||
@@ -414,8 +418,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
// Set the environment.
|
// Set the environment.
|
||||||
auto env = getEnv();
|
auto env = getEnv();
|
||||||
|
|
||||||
auto tmp = defaultTempDir();
|
|
||||||
|
|
||||||
if (pure) {
|
if (pure) {
|
||||||
decltype(env) newEnv;
|
decltype(env) newEnv;
|
||||||
for (auto & i : env)
|
for (auto & i : env)
|
||||||
@@ -426,8 +428,9 @@ static void main_nix_build(int argc, char * * argv)
|
|||||||
env["__ETC_PROFILE_SOURCED"] = "1";
|
env["__ETC_PROFILE_SOURCED"] = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
// Don't use defaultTempDir() here! We want to preserve the user's TMPDIR for the shell
|
||||||
env["NIX_STORE"] = store->storeDir;
|
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);
|
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
|
||||||
|
|
||||||
auto passAsFile = tokenizeString<StringSet>(getOr(drv.env, "passAsFile", ""));
|
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)
|
for (const auto & [inputDrv, inputNode] : drv.inputDrvs.map)
|
||||||
accumInputClosure(inputDrv, inputNode);
|
accumInputClosure(inputDrv, inputNode);
|
||||||
|
|
||||||
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(), drv);
|
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(*state), drv);
|
||||||
|
|
||||||
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
|
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
|
||||||
auto json = structAttrs.value();
|
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
|
environment variables and shell functions. Also don't
|
||||||
lose the current $PATH directories. */
|
lose the current $PATH directories. */
|
||||||
auto rcfile = (Path) tmpDir + "/rc";
|
auto rcfile = (Path) tmpDir + "/rc";
|
||||||
|
auto tz = getEnv("TZ");
|
||||||
std::string rc = fmt(
|
std::string rc = fmt(
|
||||||
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"s +
|
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"
|
||||||
(keepTmp ?
|
"%2%"
|
||||||
"trap _nix_shell_clean_tmpdir EXIT; "
|
"%3%"
|
||||||
"exitHooks+=(_nix_shell_clean_tmpdir); "
|
// always clear PATH.
|
||||||
"failureHooks+=(_nix_shell_clean_tmpdir); ":
|
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
|
||||||
"_nix_shell_clean_tmpdir; ") +
|
"unset PATH;"
|
||||||
(pure ? "" : "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;") +
|
"dontAddDisableDepTrack=1;\n",
|
||||||
"%2%"
|
shellEscape(tmpDir),
|
||||||
// always clear PATH.
|
(keepTmp
|
||||||
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
|
? "trap _nix_shell_clean_tmpdir EXIT; "
|
||||||
"unset PATH;"
|
"exitHooks+=(_nix_shell_clean_tmpdir); "
|
||||||
"dontAddDisableDepTrack=1;\n"
|
"failureHooks+=(_nix_shell_clean_tmpdir); "
|
||||||
+ structuredAttrsRC +
|
: "_nix_shell_clean_tmpdir; "),
|
||||||
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
|
(pure
|
||||||
"%3%"
|
? ""
|
||||||
"PATH=%4%:\"$PATH\"; "
|
: "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc; p=$PATH; ")
|
||||||
"SHELL=%5%; "
|
);
|
||||||
"BASH=%5%; "
|
rc += structuredAttrsRC;
|
||||||
"set +e; "
|
rc += fmt(
|
||||||
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && )s" +
|
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
|
||||||
(getuid() == 0 ? R"s(PS1='\n\[\033[1;31m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
"%1%"
|
||||||
: R"s(PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s") +
|
"PATH=%2%:\"$PATH\"; "
|
||||||
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
"SHELL=%3%; "
|
||||||
"unset NIX_ENFORCE_PURITY; "
|
"BASH=%3%; "
|
||||||
"shopt -u nullglob; "
|
"set +e; "
|
||||||
"unset TZ; %6%"
|
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && )s"
|
||||||
"shopt -s execfail;"
|
"%4%"
|
||||||
"%7%",
|
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
||||||
shellEscape(tmpDir),
|
"unset NIX_ENFORCE_PURITY; "
|
||||||
(pure ? "" : "p=$PATH; "),
|
"shopt -u nullglob; "
|
||||||
(pure ? "" : "PATH=$PATH:$p; unset p; "),
|
"unset TZ; %5%"
|
||||||
shellEscape(dirOf(*shell)),
|
"shopt -s execfail;"
|
||||||
shellEscape(*shell),
|
"%6%",
|
||||||
(getenv("TZ") ? (std::string("export TZ=") + shellEscape(getenv("TZ")) + "; ") : ""),
|
(pure ? "" : "PATH=$PATH:$p; unset p; "),
|
||||||
envCommand);
|
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);
|
vomit("Sourcing nix-shell with file %s and contents:\n%s", rcfile, rc);
|
||||||
writeFile(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;
|
std::map<StorePath, std::pair<size_t, StringSet>> drvMap;
|
||||||
|
|
||||||
for (auto & drvInfo : drvs) {
|
for (auto & drvInfo : drvs) {
|
||||||
auto drvPath = drvInfo.requireDrvPath();
|
auto drvPath = drvInfo.requireDrvPath(*state);
|
||||||
|
|
||||||
auto outputName = drvInfo.queryOutputName();
|
auto outputName = drvInfo.queryOutputName(*state);
|
||||||
if (outputName == "")
|
if (outputName == "")
|
||||||
throw Error("derivation '%s' lacks an 'outputName' attribute", store->printStorePath(drvPath));
|
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);
|
void registerNixBuildAndNixShell() {
|
||||||
static RegisterLegacyCommand r_nix_shell("nix-shell", main_nix_build);
|
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 "lix/libstore/profiles.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "fetchers.hh"
|
#include "lix/libfetchers/fetchers.hh"
|
||||||
#include "eval-settings.hh" // for defexpr
|
#include "lix/libexpr/eval-settings.hh" // for defexpr
|
||||||
#include "users.hh"
|
#include "lix/libstore/temporary-dir.hh"
|
||||||
|
#include "lix/libutil/users.hh"
|
||||||
|
#include "nix-channel.hh"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
||||||
using namespace nix;
|
namespace nix {
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> Channels;
|
typedef std::map<std::string, std::string> Channels;
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ static void update(const StringSet & channelNames)
|
|||||||
replaceSymlink(profile, channelLink);
|
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
|
// 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
|
cRollback
|
||||||
} cmd = cNone;
|
} cmd = cNone;
|
||||||
std::vector<std::string> args;
|
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") {
|
if (*arg == "--help") {
|
||||||
showManPage("nix-channel");
|
showManPage("nix-channel");
|
||||||
} else if (*arg == "--version") {
|
} else if (*arg == "--version") {
|
||||||
@@ -205,7 +207,7 @@ static int main_nix_channel(int argc, char ** argv)
|
|||||||
args.push_back(std::move(*arg));
|
args.push_back(std::move(*arg));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
}).parseCmdline(argv);
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case cNone:
|
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 "lix/libutil/file-system.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "store-cast.hh"
|
#include "lix/libstore/store-cast.hh"
|
||||||
#include "gc-store.hh"
|
#include "lix/libstore/gc-store.hh"
|
||||||
#include "profiles.hh"
|
#include "lix/libstore/profiles.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
|
#include "nix-collect-garbage.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
|
||||||
using namespace nix;
|
namespace nix {
|
||||||
|
|
||||||
std::string deleteOlderThan;
|
std::string deleteOlderThan;
|
||||||
bool dryRun = false;
|
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;
|
bool removeOld = false;
|
||||||
|
|
||||||
GCOptions options;
|
GCOptions options;
|
||||||
|
|
||||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
showManPage("nix-collect-garbage");
|
showManPage("nix-collect-garbage");
|
||||||
else if (*arg == "--version")
|
else if (*arg == "--version")
|
||||||
@@ -78,7 +79,7 @@ static int main_nix_collect_garbage(int argc, char * * argv)
|
|||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
}).parseCmdline(argv);
|
||||||
|
|
||||||
if (removeOld) {
|
if (removeOld) {
|
||||||
std::set<Path> dirsToClean = {
|
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 "lix/libmain/shared.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "legacy.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;
|
auto gzip = false;
|
||||||
@@ -15,7 +16,7 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
|||||||
std::string sshHost;
|
std::string sshHost;
|
||||||
PathSet storePaths;
|
PathSet storePaths;
|
||||||
|
|
||||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
LegacyArgs(programName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
showManPage("nix-copy-closure");
|
showManPage("nix-copy-closure");
|
||||||
else if (*arg == "--version")
|
else if (*arg == "--version")
|
||||||
@@ -41,7 +42,7 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
|||||||
else
|
else
|
||||||
storePaths.insert(*arg);
|
storePaths.insert(*arg);
|
||||||
return true;
|
return true;
|
||||||
});
|
}).parseCmdline(argv);
|
||||||
|
|
||||||
if (sshHost.empty())
|
if (sshHost.empty())
|
||||||
throw UsageError("no host name specified");
|
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 "lix/libcmd/cmd-profiles.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "terminal.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libutil/terminal.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "names.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "profiles.hh"
|
#include "lix/libstore/names.hh"
|
||||||
#include "path-with-outputs.hh"
|
#include "lix/libstore/profiles.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libstore/path-with-outputs.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "user-env.hh"
|
#include "user-env.hh"
|
||||||
#include "users.hh"
|
#include "lix/libutil/users.hh"
|
||||||
#include "value-to-json.hh"
|
#include "lix/libexpr/value-to-json.hh"
|
||||||
#include "xml-writer.hh"
|
#include "lix/libutil/xml-writer.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "eval-settings.hh" // for defexpr
|
#include "lix/libexpr/eval-settings.hh" // for defexpr
|
||||||
|
#include "nix-env.hh"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -28,9 +30,10 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
using namespace nix;
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
srcNixExprDrvs,
|
srcNixExprDrvs,
|
||||||
@@ -56,7 +59,7 @@ struct Globals
|
|||||||
{
|
{
|
||||||
InstallSourceInfo instSource;
|
InstallSourceInfo instSource;
|
||||||
Path profile;
|
Path profile;
|
||||||
std::shared_ptr<EvalState> state;
|
std::shared_ptr<Evaluator> state;
|
||||||
bool dryRun;
|
bool dryRun;
|
||||||
bool preserveInstalled;
|
bool preserveInstalled;
|
||||||
bool removeAll;
|
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
|
if (st.type == InputAccessor::tRegular) {
|
||||||
st.type == InputAccessor::tRegular
|
return true;
|
||||||
|| (st.type == InputAccessor::tDirectory && (path + "default.nix").pathExists());
|
} 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 constexpr size_t maxAttrs = 1024;
|
||||||
|
|
||||||
|
|
||||||
static void getAllExprs(EvalState & state,
|
static void getAllExprs(Evaluator & state,
|
||||||
const SourcePath & path, StringSet & seen, BindingsBuilder & attrs)
|
const CheckedSourcePath & path, StringSet & seen, BindingsBuilder & attrs)
|
||||||
{
|
{
|
||||||
StringSet namesSorted;
|
StringSet namesSorted;
|
||||||
for (auto & [name, _] : path.readDirectory()) namesSorted.insert(name);
|
for (auto & [name, _] : path.readDirectory()) namesSorted.insert(name);
|
||||||
@@ -116,16 +124,16 @@ static void getAllExprs(EvalState & state,
|
|||||||
are implemented using profiles). */
|
are implemented using profiles). */
|
||||||
if (i == "manifest.nix") continue;
|
if (i == "manifest.nix") continue;
|
||||||
|
|
||||||
SourcePath path2 = path + i;
|
auto path2 = state.paths.checkSourcePath(path + i);
|
||||||
|
|
||||||
InputAccessor::Stat st;
|
InputAccessor::Stat st;
|
||||||
try {
|
try {
|
||||||
st = path2.resolveSymlinks().lstat();
|
st = path2.stat();
|
||||||
} catch (Error &) {
|
} catch (Error &) {
|
||||||
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
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),
|
/* Strip off the `.nix' filename suffix (if applicable),
|
||||||
otherwise the attribute cannot be selected with the
|
otherwise the attribute cannot be selected with the
|
||||||
`-A' option. Useful if you want to stick a Nix
|
`-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);
|
attrName = std::string(attrName, 0, attrName.size() - 4);
|
||||||
if (!seen.insert(attrName).second) {
|
if (!seen.insert(attrName).second) {
|
||||||
std::string suggestionMessage = "";
|
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);
|
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%'"
|
printError("warning: name collision in input Nix expressions, skipping '%1%'"
|
||||||
"%2%", path2, suggestionMessage);
|
"%2%", path2, suggestionMessage);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Load the expression on demand. */
|
/* Load the expression on demand. */
|
||||||
auto vArg = state.allocValue();
|
auto vArg = state.mem.allocValue();
|
||||||
vArg->mkString(path2.path.abs());
|
vArg->mkString(path2.canonical().abs());
|
||||||
if (seen.size() == maxAttrs)
|
if (seen.size() == maxAttrs)
|
||||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
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)
|
else if (st.type == InputAccessor::tDirectory)
|
||||||
/* `path2' is a directory (with no default.nix in it);
|
/* `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);
|
state.evalFile(path, v);
|
||||||
|
|
||||||
/* The path is a directory. Put the Nix expressions in the
|
/* 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
|
~/.nix-defexpr directory that includes some system-wide
|
||||||
directory). */
|
directory). */
|
||||||
else if (st.type == InputAccessor::tDirectory) {
|
else if (st.type == InputAccessor::tDirectory) {
|
||||||
auto attrs = state.buildBindings(maxAttrs);
|
auto attrs = state.ctx.buildBindings(maxAttrs);
|
||||||
attrs.alloc("_combineChannels").mkList(0);
|
attrs.alloc("_combineChannels").mkList(0);
|
||||||
StringSet seen;
|
StringSet seen;
|
||||||
getAllExprs(state, path, seen, attrs);
|
getAllExprs(state.ctx, path, seen, attrs);
|
||||||
v.mkAttrs(attrs);
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +206,7 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
|
|||||||
system. */
|
system. */
|
||||||
for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) {
|
for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) {
|
||||||
j = i; j++;
|
j = i; j++;
|
||||||
if (systemFilter != "*" && i->querySystem() != systemFilter)
|
if (systemFilter != "*" && i->querySystem(state) != systemFilter)
|
||||||
elems.erase(i);
|
elems.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +214,7 @@ static void loadDerivations(EvalState & state, const SourcePath & nixExprPath,
|
|||||||
|
|
||||||
static NixInt getPriority(EvalState & state, DrvInfo & drv)
|
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.
|
// at a time.
|
||||||
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
||||||
{
|
{
|
||||||
auto path = elem.queryOutPath();
|
auto path = elem.queryOutPath(state);
|
||||||
if (state.store->isValidPath(path)) return true;
|
if (state.ctx.store->isValidPath(path)) return true;
|
||||||
return state.store->querySubstitutablePaths({path}).count(path);
|
return state.ctx.store->querySubstitutablePaths({path}).count(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -236,11 +245,11 @@ static void checkSelectorUse(DrvNames & selectors)
|
|||||||
|
|
||||||
namespace {
|
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;
|
constexpr std::size_t maxResults = 3;
|
||||||
std::set<std::string> result;
|
std::set<std::string> result;
|
||||||
for (auto & drvInfo : allElems) {
|
for (auto & drvInfo : allElems) {
|
||||||
const auto drvName = DrvName { drvInfo.queryName() };
|
const auto drvName = DrvName { drvInfo.queryName(state) };
|
||||||
if (drvName.name.starts_with(prefix)) {
|
if (drvName.name.starts_with(prefix)) {
|
||||||
result.emplace(drvName.name);
|
result.emplace(drvName.name);
|
||||||
|
|
||||||
@@ -278,7 +287,7 @@ std::vector<Match> pickNewestOnly(EvalState & state, std::vector<Match> matches)
|
|||||||
for (auto & match : matches) {
|
for (auto & match : matches) {
|
||||||
auto & oneDrv = match.drvInfo;
|
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;
|
std::strong_ordering comparison = std::strong_ordering::greater;
|
||||||
|
|
||||||
const auto itOther = newest.find(drvName.name);
|
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;
|
auto & newestDrv = itOther->second.drvInfo;
|
||||||
|
|
||||||
comparison =
|
comparison =
|
||||||
oneDrv.querySystem() == newestDrv.querySystem() ? std::strong_ordering::equal :
|
oneDrv.querySystem(state) == newestDrv.querySystem(state) ? std::strong_ordering::equal :
|
||||||
oneDrv.querySystem() == settings.thisSystem ? std::strong_ordering::greater :
|
oneDrv.querySystem(state) == settings.thisSystem ? std::strong_ordering::greater :
|
||||||
newestDrv.querySystem() == settings.thisSystem ? std::strong_ordering::less : std::strong_ordering::equal;
|
newestDrv.querySystem(state) == settings.thisSystem ? std::strong_ordering::less : std::strong_ordering::equal;
|
||||||
if (comparison == 0)
|
if (comparison == 0)
|
||||||
comparison = comparePriorities(state, oneDrv, newestDrv);
|
comparison = comparePriorities(state, oneDrv, newestDrv);
|
||||||
if (comparison == 0)
|
if (comparison == 0)
|
||||||
comparison = compareVersions(drvName.version, DrvName { newestDrv.queryName() }.version);
|
comparison = compareVersions(drvName.version, DrvName{newestDrv.queryName(state)}.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comparison > 0) {
|
if (comparison > 0) {
|
||||||
@@ -332,7 +341,7 @@ static DrvInfos filterBySelector(EvalState & state, DrvInfos & allElems,
|
|||||||
for (auto & selector : selectors) {
|
for (auto & selector : selectors) {
|
||||||
std::vector<Match> matches;
|
std::vector<Match> matches;
|
||||||
for (auto && [index, drvInfo] : enumerate(allElems)) {
|
for (auto && [index, drvInfo] : enumerate(allElems)) {
|
||||||
const auto drvName = DrvName { drvInfo.queryName() };
|
const auto drvName = DrvName { drvInfo.queryName(state) };
|
||||||
if (selector.matches(drvName)) {
|
if (selector.matches(drvName)) {
|
||||||
++selector.hits;
|
++selector.hits;
|
||||||
matches.emplace_back(drvInfo, index);
|
matches.emplace_back(drvInfo, index);
|
||||||
@@ -350,7 +359,7 @@ static DrvInfos filterBySelector(EvalState & state, DrvInfos & allElems,
|
|||||||
elems.push_back(match.drvInfo);
|
elems.push_back(match.drvInfo);
|
||||||
|
|
||||||
if (selector.hits == 0 && selector.fullName != "*") {
|
if (selector.hits == 0 && selector.fullName != "*") {
|
||||||
const auto prefixHits = searchByPrefix(allElems, selector.name);
|
const auto prefixHits = searchByPrefix(state, allElems, selector.name);
|
||||||
|
|
||||||
if (prefixHits.empty()) {
|
if (prefixHits.empty()) {
|
||||||
throw Error("selector '%1%' matches no derivations", selector.fullName);
|
throw Error("selector '%1%' matches no derivations", selector.fullName);
|
||||||
@@ -413,7 +422,7 @@ static void queryInstSources(EvalState & state,
|
|||||||
loadSourceExpr(state, *instSource.nixExprPath, vArg);
|
loadSourceExpr(state, *instSource.nixExprPath, vArg);
|
||||||
|
|
||||||
for (auto & i : args) {
|
for (auto & i : args) {
|
||||||
Expr & eFun = state.parseExprFromString(i, state.rootPath(CanonPath::fromCwd()));
|
Expr & eFun = state.ctx.parseExprFromString(i, CanonPath::fromCwd());
|
||||||
Value vFun, vTmp;
|
Value vFun, vTmp;
|
||||||
state.eval(eFun, vFun);
|
state.eval(eFun, vFun);
|
||||||
vTmp.mkApp(&vFun, &vArg);
|
vTmp.mkApp(&vFun, &vArg);
|
||||||
@@ -429,16 +438,16 @@ static void queryInstSources(EvalState & state,
|
|||||||
case srcStorePaths: {
|
case srcStorePaths: {
|
||||||
|
|
||||||
for (auto & i : args) {
|
for (auto & i : args) {
|
||||||
auto path = state.store->followLinksToStorePath(i);
|
auto path = state.ctx.store->followLinksToStorePath(i);
|
||||||
|
|
||||||
std::string name(path.name());
|
std::string name(path.name());
|
||||||
|
|
||||||
DrvInfo elem(state, "", nullptr);
|
DrvInfo elem("", nullptr);
|
||||||
elem.setName(name);
|
elem.setName(name);
|
||||||
|
|
||||||
if (path.isDerivation()) {
|
if (path.isDerivation()) {
|
||||||
elem.setDrvPath(path);
|
elem.setDrvPath(path);
|
||||||
auto outputs = state.store->queryDerivationOutputMap(path);
|
auto outputs = state.ctx.store->queryDerivationOutputMap(path);
|
||||||
elem.setOutPath(outputs.at("out"));
|
elem.setOutPath(outputs.at("out"));
|
||||||
if (name.size() >= drvExtension.size() &&
|
if (name.size() >= drvExtension.size() &&
|
||||||
std::string(name, name.size() - drvExtension.size()) == drvExtension)
|
std::string(name, name.size() - drvExtension.size()) == drvExtension)
|
||||||
@@ -483,23 +492,23 @@ static void printMissing(EvalState & state, DrvInfos & elems)
|
|||||||
{
|
{
|
||||||
std::vector<DerivedPath> targets;
|
std::vector<DerivedPath> targets;
|
||||||
for (auto & i : elems)
|
for (auto & i : elems)
|
||||||
if (auto drvPath = i.queryDrvPath())
|
if (auto drvPath = i.queryDrvPath(state))
|
||||||
targets.emplace_back(DerivedPath::Built{
|
targets.emplace_back(DerivedPath::Built{
|
||||||
.drvPath = makeConstantStorePathRef(*drvPath),
|
.drvPath = makeConstantStorePathRef(*drvPath),
|
||||||
.outputs = OutputsSpec::All { },
|
.outputs = OutputsSpec::All { },
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
targets.emplace_back(DerivedPath::Opaque{
|
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");
|
debug("installing derivations");
|
||||||
|
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
/* Get the set of user environment elements to be installed. */
|
/* Get the set of user environment elements to be installed. */
|
||||||
DrvInfos newElems, newElemsTmp;
|
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. */
|
/* If --prebuilt-only is given, filter out source-only packages. */
|
||||||
for (auto & i : newElemsTmp)
|
for (auto & i : newElemsTmp)
|
||||||
if (!globals.prebuiltOnly || isPrebuilt(*globals.state, i))
|
if (!globals.prebuiltOnly || isPrebuilt(*state, i))
|
||||||
newElems.push_back(i);
|
newElems.push_back(i);
|
||||||
|
|
||||||
StringSet newNames;
|
StringSet newNames;
|
||||||
@@ -525,7 +536,7 @@ static void installDerivations(Globals & globals,
|
|||||||
`java-front-0.9pre15899'). */
|
`java-front-0.9pre15899'). */
|
||||||
if (globals.forceName != "")
|
if (globals.forceName != "")
|
||||||
i.setName(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
|
/* Add in the already installed derivations, unless they have
|
||||||
the same name as a to-be-installed element. */
|
the same name as a to-be-installed element. */
|
||||||
if (!globals.removeAll) {
|
if (!globals.removeAll) {
|
||||||
DrvInfos installedElems = queryInstalled(*globals.state, profile);
|
DrvInfos installedElems = queryInstalled(*state, profile);
|
||||||
|
|
||||||
for (auto & i : installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i.queryName());
|
DrvName drvName(i.queryName(*state));
|
||||||
if (!globals.preserveInstalled &&
|
if (!globals.preserveInstalled &&
|
||||||
newNames.find(drvName.name) != newNames.end() &&
|
newNames.find(drvName.name) != newNames.end() &&
|
||||||
!keep(i))
|
!keep(*state, i))
|
||||||
printInfo("replacing old '%s'", i.queryName());
|
printInfo("replacing old '%s'", i.queryName(*state));
|
||||||
else
|
else
|
||||||
allElems.push_back(i);
|
allElems.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : newElems)
|
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 (globals.dryRun) return;
|
||||||
|
|
||||||
if (createUserEnv(*globals.state, allElems,
|
if (createUserEnv(*state, allElems,
|
||||||
profile, settings.envKeepDerivations, lockToken)) break;
|
profile, settings.envKeepDerivations, lockToken)) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -587,6 +598,8 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
{
|
{
|
||||||
debug("upgrading derivations");
|
debug("upgrading derivations");
|
||||||
|
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
/* Upgrade works as follows: we take all currently installed
|
/* Upgrade works as follows: we take all currently installed
|
||||||
derivations, and for any derivation matching any selector, look
|
derivations, and for any derivation matching any selector, look
|
||||||
for a derivation in the input Nix expression that has the same
|
for a derivation in the input Nix expression that has the same
|
||||||
@@ -595,20 +608,20 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
while (true) {
|
while (true) {
|
||||||
auto lockToken = optimisticLockProfile(globals.profile);
|
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. */
|
/* Fetch all derivations from the input file. */
|
||||||
DrvInfos availElems;
|
DrvInfos availElems;
|
||||||
queryInstSources(*globals.state, globals.instSource, args, availElems, false);
|
queryInstSources(*state, globals.instSource, args, availElems, false);
|
||||||
|
|
||||||
/* Go through all installed derivations. */
|
/* Go through all installed derivations. */
|
||||||
DrvInfos newElems;
|
DrvInfos newElems;
|
||||||
for (auto & i : installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i.queryName());
|
DrvName drvName(i.queryName(*state));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (keep(i)) {
|
if (keep(*state, i)) {
|
||||||
newElems.push_back(i);
|
newElems.push_back(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -623,9 +636,9 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
DrvInfos::iterator bestElem = availElems.end();
|
DrvInfos::iterator bestElem = availElems.end();
|
||||||
std::string bestVersion;
|
std::string bestVersion;
|
||||||
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
|
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
|
||||||
if (comparePriorities(*globals.state, i, *j) > 0)
|
if (comparePriorities(*state, i, *j) > 0)
|
||||||
continue;
|
continue;
|
||||||
DrvName newName(j->queryName());
|
DrvName newName(j->queryName(*state));
|
||||||
if (newName.name == drvName.name) {
|
if (newName.name == drvName.name) {
|
||||||
std::strong_ordering d = compareVersions(drvName.version, newName.version);
|
std::strong_ordering d = compareVersions(drvName.version, newName.version);
|
||||||
if ((upgradeType == utLt && d < 0) ||
|
if ((upgradeType == utLt && d < 0) ||
|
||||||
@@ -635,10 +648,10 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
{
|
{
|
||||||
std::strong_ordering d2 = std::strong_ordering::less;
|
std::strong_ordering d2 = std::strong_ordering::less;
|
||||||
if (bestElem != availElems.end()) {
|
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) d2 = compareVersions(bestVersion, newName.version);
|
||||||
}
|
}
|
||||||
if (d2 < 0 && (!globals.prebuiltOnly || isPrebuilt(*globals.state, *j))) {
|
if (d2 < 0 && (!globals.prebuiltOnly || isPrebuilt(*state, *j))) {
|
||||||
bestElem = j;
|
bestElem = j;
|
||||||
bestVersion = newName.version;
|
bestVersion = newName.version;
|
||||||
}
|
}
|
||||||
@@ -647,27 +660,27 @@ static void upgradeDerivations(Globals & globals,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bestElem != availElems.end() &&
|
if (bestElem != availElems.end() &&
|
||||||
i.queryOutPath() !=
|
i.queryOutPath(*state) !=
|
||||||
bestElem->queryOutPath())
|
bestElem->queryOutPath(*state))
|
||||||
{
|
{
|
||||||
const char * action = compareVersions(drvName.version, bestVersion) <= 0
|
const char * action = compareVersions(drvName.version, bestVersion) <= 0
|
||||||
? "upgrading" : "downgrading";
|
? "upgrading" : "downgrading";
|
||||||
printInfo("%1% '%2%' to '%3%'",
|
printInfo("%1% '%2%' to '%3%'",
|
||||||
action, i.queryName(), bestElem->queryName());
|
action, i.queryName(*state), bestElem->queryName(*state));
|
||||||
newElems.push_back(*bestElem);
|
newElems.push_back(*bestElem);
|
||||||
} else newElems.push_back(i);
|
} else newElems.push_back(i);
|
||||||
|
|
||||||
} catch (Error & e) {
|
} 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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printMissing(*globals.state, newElems);
|
printMissing(*state, newElems);
|
||||||
|
|
||||||
if (globals.dryRun) return;
|
if (globals.dryRun) return;
|
||||||
|
|
||||||
if (createUserEnv(*globals.state, newElems,
|
if (createUserEnv(*state, newElems,
|
||||||
globals.profile, settings.envKeepDerivations, lockToken)) break;
|
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,
|
static void setMetaFlag(EvalState & state, DrvInfo & drv,
|
||||||
const std::string & name, const std::string & value)
|
const std::string & name, const std::string & value)
|
||||||
{
|
{
|
||||||
auto v = state.allocValue();
|
auto v = state.ctx.mem.allocValue();
|
||||||
v->mkString(value);
|
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++;
|
std::string flagValue = *arg++;
|
||||||
DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end()));
|
DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end()));
|
||||||
|
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::string lockToken = optimisticLockProfile(globals.profile);
|
std::string lockToken = optimisticLockProfile(globals.profile);
|
||||||
|
|
||||||
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
|
DrvInfos installedElems = queryInstalled(*state, globals.profile);
|
||||||
|
|
||||||
/* Update all matching derivations. */
|
/* Update all matching derivations. */
|
||||||
for (auto & i : installedElems) {
|
for (auto & i : installedElems) {
|
||||||
DrvName drvName(i.queryName());
|
DrvName drvName(i.queryName(*state));
|
||||||
for (auto & j : selectors)
|
for (auto & j : selectors)
|
||||||
if (j.matches(drvName)) {
|
if (j.matches(drvName)) {
|
||||||
printInfo("setting flag on '%1%'", i.queryName());
|
printInfo("setting flag on '%1%'", i.queryName(*state));
|
||||||
j.hits++;
|
j.hits++;
|
||||||
setMetaFlag(*globals.state, i, flagName, flagValue);
|
setMetaFlag(*state, i, flagName, flagValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -731,7 +746,7 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
checkSelectorUse(selectors);
|
checkSelectorUse(selectors);
|
||||||
|
|
||||||
/* Write the new user environment. */
|
/* Write the new user environment. */
|
||||||
if (createUserEnv(*globals.state, installedElems,
|
if (createUserEnv(*state, installedElems,
|
||||||
globals.profile, settings.envKeepDerivations, lockToken)) break;
|
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)
|
static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
auto store2 = globals.state->store.dynamic_pointer_cast<LocalFSStore>();
|
auto store2 = globals.state->store.dynamic_pointer_cast<LocalFSStore>();
|
||||||
if (!store2) throw Error("--set is not supported for this Nix store");
|
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;
|
DrvInfos elems;
|
||||||
queryInstSources(*globals.state, globals.instSource, opArgs, elems, true);
|
queryInstSources(*state, globals.instSource, opArgs, elems, true);
|
||||||
|
|
||||||
if (elems.size() != 1)
|
if (elems.size() != 1)
|
||||||
throw Error("--set requires exactly one derivation");
|
throw Error("--set requires exactly one derivation");
|
||||||
@@ -759,7 +776,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
if (globals.forceName != "")
|
if (globals.forceName != "")
|
||||||
drv.setName(globals.forceName);
|
drv.setName(globals.forceName);
|
||||||
|
|
||||||
auto drvPath = drv.queryDrvPath();
|
auto drvPath = drv.queryDrvPath(*state);
|
||||||
std::vector<DerivedPath> paths {
|
std::vector<DerivedPath> paths {
|
||||||
drvPath
|
drvPath
|
||||||
? (DerivedPath) (DerivedPath::Built {
|
? (DerivedPath) (DerivedPath::Built {
|
||||||
@@ -767,7 +784,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
.outputs = OutputsSpec::All { },
|
.outputs = OutputsSpec::All { },
|
||||||
})
|
})
|
||||||
: (DerivedPath) (DerivedPath::Opaque {
|
: (DerivedPath) (DerivedPath::Opaque {
|
||||||
.path = drv.queryOutPath(),
|
.path = drv.queryOutPath(*state),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
printMissing(globals.state->store, paths);
|
printMissing(globals.state->store, paths);
|
||||||
@@ -778,7 +795,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
Path generation = createGeneration(
|
Path generation = createGeneration(
|
||||||
*store2,
|
*store2,
|
||||||
globals.profile,
|
globals.profile,
|
||||||
drv.queryOutPath());
|
drv.queryOutPath(*state));
|
||||||
switchLink(globals.profile, generation);
|
switchLink(globals.profile, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -786,10 +803,12 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
static void uninstallDerivations(Globals & globals, Strings & selectors,
|
static void uninstallDerivations(Globals & globals, Strings & selectors,
|
||||||
Path & profile)
|
Path & profile)
|
||||||
{
|
{
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto lockToken = optimisticLockProfile(profile);
|
auto lockToken = optimisticLockProfile(profile);
|
||||||
|
|
||||||
DrvInfos workingElems = queryInstalled(*globals.state, profile);
|
DrvInfos workingElems = queryInstalled(*state, profile);
|
||||||
|
|
||||||
for (auto & selector : selectors) {
|
for (auto & selector : selectors) {
|
||||||
DrvInfos::iterator split = workingElems.begin();
|
DrvInfos::iterator split = workingElems.begin();
|
||||||
@@ -797,16 +816,16 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
|||||||
StorePath selectorStorePath = globals.state->store->followLinksToStorePath(selector);
|
StorePath selectorStorePath = globals.state->store->followLinksToStorePath(selector);
|
||||||
split = std::partition(
|
split = std::partition(
|
||||||
workingElems.begin(), workingElems.end(),
|
workingElems.begin(), workingElems.end(),
|
||||||
[&selectorStorePath, globals](auto &elem) {
|
[&selectorStorePath, &state](auto &elem) {
|
||||||
return selectorStorePath != elem.queryOutPath();
|
return selectorStorePath != elem.queryOutPath(*state);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
DrvName selectorName(selector);
|
DrvName selectorName(selector);
|
||||||
split = std::partition(
|
split = std::partition(
|
||||||
workingElems.begin(), workingElems.end(),
|
workingElems.begin(), workingElems.end(),
|
||||||
[&selectorName](auto &elem){
|
[&selectorName, &state](auto &elem){
|
||||||
DrvName elemName(elem.queryName());
|
DrvName elemName(elem.queryName(*state));
|
||||||
return !selectorName.matches(elemName);
|
return !selectorName.matches(elemName);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -814,14 +833,14 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
|
|||||||
if (split == workingElems.end())
|
if (split == workingElems.end())
|
||||||
warn("selector '%s' matched no installed derivations", selector);
|
warn("selector '%s' matched no installed derivations", selector);
|
||||||
for (auto removedElem = split; removedElem != workingElems.end(); removedElem++) {
|
for (auto removedElem = split; removedElem != workingElems.end(); removedElem++) {
|
||||||
printInfo("uninstalling '%s'", removedElem->queryName());
|
printInfo("uninstalling '%s'", removedElem->queryName(*state));
|
||||||
}
|
}
|
||||||
workingElems.erase(split, workingElems.end());
|
workingElems.erase(split, workingElems.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globals.dryRun) return;
|
if (globals.dryRun) return;
|
||||||
|
|
||||||
if (createUserEnv(*globals.state, workingElems,
|
if (createUserEnv(*state, workingElems,
|
||||||
profile, settings.envKeepDerivations, lockToken)) break;
|
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 a_name = a.queryName(state);
|
||||||
auto b_name = b.queryName();
|
auto b_name = b.queryName(state);
|
||||||
return lexicographical_compare(
|
return lexicographical_compare(
|
||||||
a_name.begin(), a_name.end(),
|
a_name.begin(), a_name.end(),
|
||||||
b_name.begin(), b_name.end(), cmpChars);
|
b_name.begin(), b_name.end(), cmpChars);
|
||||||
@@ -894,15 +913,15 @@ void printTable(Table & table)
|
|||||||
typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff;
|
typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff;
|
||||||
|
|
||||||
static VersionDiff compareVersionAgainstSet(
|
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;
|
VersionDiff diff = cvUnavail;
|
||||||
version = "?";
|
version = "?";
|
||||||
|
|
||||||
for (auto & i : elems) {
|
for (auto & i : elems) {
|
||||||
DrvName name2(i.queryName());
|
DrvName name2(i.queryName(state));
|
||||||
if (name.name == name2.name) {
|
if (name.name == name2.name) {
|
||||||
std::strong_ordering d = compareVersions(name.version, name2.version);
|
std::strong_ordering d = compareVersions(name.version, name2.version);
|
||||||
if (d < 0) {
|
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;
|
using nlohmann::json;
|
||||||
json topObj = json::object();
|
json topObj = json::object();
|
||||||
@@ -934,18 +953,18 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
|||||||
if (i.hasFailed()) continue;
|
if (i.hasFailed()) continue;
|
||||||
|
|
||||||
|
|
||||||
auto drvName = DrvName(i.queryName());
|
auto drvName = DrvName(i.queryName(state));
|
||||||
json &pkgObj = topObj[i.attrPath];
|
json &pkgObj = topObj[i.attrPath];
|
||||||
pkgObj = {
|
pkgObj = {
|
||||||
{"name", drvName.fullName},
|
{"name", drvName.fullName},
|
||||||
{"pname", drvName.name},
|
{"pname", drvName.name},
|
||||||
{"version", drvName.version},
|
{"version", drvName.version},
|
||||||
{"system", i.querySystem()},
|
{"system", i.querySystem(state)},
|
||||||
{"outputName", i.queryOutputName()},
|
{"outputName", i.queryOutputName(state)},
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
|
DrvInfo::Outputs outputs = i.queryOutputs(state, printOutPath);
|
||||||
json &outputObj = pkgObj["outputs"];
|
json &outputObj = pkgObj["outputs"];
|
||||||
outputObj = json::object();
|
outputObj = json::object();
|
||||||
for (auto & j : outputs) {
|
for (auto & j : outputs) {
|
||||||
@@ -957,29 +976,29 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (printDrvPath) {
|
if (printDrvPath) {
|
||||||
auto drvPath = i.queryDrvPath();
|
auto drvPath = i.queryDrvPath(state);
|
||||||
if (drvPath) pkgObj["drvPath"] = globals.state->store->printStorePath(*drvPath);
|
if (drvPath) pkgObj["drvPath"] = globals.state->store->printStorePath(*drvPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printMeta) {
|
if (printMeta) {
|
||||||
json &metaObj = pkgObj["meta"];
|
json &metaObj = pkgObj["meta"];
|
||||||
metaObj = json::object();
|
metaObj = json::object();
|
||||||
StringSet metaNames = i.queryMetaNames();
|
StringSet metaNames = i.queryMetaNames(state);
|
||||||
for (auto & j : metaNames) {
|
for (auto & j : metaNames) {
|
||||||
Value * v = i.queryMeta(j);
|
Value * v = i.queryMeta(state, j);
|
||||||
if (!v) {
|
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;
|
metaObj[j] = nullptr;
|
||||||
} else {
|
} else {
|
||||||
NixStringContext context;
|
NixStringContext context;
|
||||||
metaObj[j] = printValueAsJSON(*globals.state, true, *v, noPos, context);
|
metaObj[j] = printValueAsJSON(state, true, *v, noPos, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (AssertionError & e) {
|
} 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) {
|
} 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;
|
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)
|
static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
auto & store { *globals.state->store };
|
auto & store { *globals.state->store };
|
||||||
|
auto state = globals.state->begin();
|
||||||
|
|
||||||
Strings remaining;
|
Strings remaining;
|
||||||
std::string attrPath;
|
std::string attrPath;
|
||||||
@@ -1038,14 +1058,14 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
DrvInfos availElems, installedElems;
|
DrvInfos availElems, installedElems;
|
||||||
|
|
||||||
if (source == sInstalled || compareVersions || printStatus)
|
if (source == sInstalled || compareVersions || printStatus)
|
||||||
installedElems = queryInstalled(*globals.state, globals.profile);
|
installedElems = queryInstalled(*state, globals.profile);
|
||||||
|
|
||||||
if (source == sAvailable || compareVersions)
|
if (source == sAvailable || compareVersions)
|
||||||
loadDerivations(*globals.state, *globals.instSource.nixExprPath,
|
loadDerivations(*state, *globals.instSource.nixExprPath,
|
||||||
globals.instSource.systemFilter, *globals.instSource.autoArgs,
|
globals.instSource.systemFilter, *globals.instSource.autoArgs,
|
||||||
attrPath, availElems);
|
attrPath, availElems);
|
||||||
|
|
||||||
DrvInfos elems_ = filterBySelector(*globals.state,
|
DrvInfos elems_ = filterBySelector(*state,
|
||||||
source == sInstalled ? installedElems : availElems,
|
source == sInstalled ? installedElems : availElems,
|
||||||
opArgs, false);
|
opArgs, false);
|
||||||
|
|
||||||
@@ -1056,8 +1076,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
/* !!! */
|
/* !!! */
|
||||||
std::vector<DrvInfo> elems;
|
std::vector<DrvInfo> elems;
|
||||||
for (auto & i : elems_) elems.push_back(i);
|
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
|
/* We only need to know the installed paths when we are querying
|
||||||
the status of the derivation. */
|
the status of the derivation. */
|
||||||
@@ -1065,7 +1084,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
if (printStatus)
|
if (printStatus)
|
||||||
for (auto & i : installedElems)
|
for (auto & i : installedElems)
|
||||||
installed.insert(i.queryOutPath());
|
installed.insert(i.queryOutPath(*state));
|
||||||
|
|
||||||
|
|
||||||
/* Query which paths have substitutes. */
|
/* Query which paths have substitutes. */
|
||||||
@@ -1075,9 +1094,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
StorePathSet paths;
|
StorePathSet paths;
|
||||||
for (auto & i : elems)
|
for (auto & i : elems)
|
||||||
try {
|
try {
|
||||||
paths.insert(i.queryOutPath());
|
paths.insert(i.queryOutPath(*state));
|
||||||
} catch (AssertionError & e) {
|
} 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();
|
i.setFailed();
|
||||||
}
|
}
|
||||||
validPaths = store.queryValidPaths(paths);
|
validPaths = store.queryValidPaths(paths);
|
||||||
@@ -1087,7 +1106,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
/* Print the desired columns, or XML output. */
|
/* Print the desired columns, or XML output. */
|
||||||
if (jsonOutput) {
|
if (jsonOutput) {
|
||||||
queryJSON(globals, elems, printOutPath, printDrvPath, printMeta);
|
queryJSON(*state, globals, elems, printOutPath, printDrvPath, printMeta);
|
||||||
cout << '\n';
|
cout << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1106,8 +1125,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
//Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
|
//Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
|
||||||
|
|
||||||
if (globals.prebuiltOnly &&
|
if (globals.prebuiltOnly &&
|
||||||
!validPaths.count(i.queryOutPath()) &&
|
!validPaths.count(i.queryOutPath(*state)) &&
|
||||||
!substitutablePaths.count(i.queryOutPath()))
|
!substitutablePaths.count(i.queryOutPath(*state)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* For table output. */
|
/* For table output. */
|
||||||
@@ -1117,7 +1136,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
XMLAttrs attrs;
|
XMLAttrs attrs;
|
||||||
|
|
||||||
if (printStatus) {
|
if (printStatus) {
|
||||||
auto outPath = i.queryOutPath();
|
auto outPath = i.queryOutPath(*state);
|
||||||
bool hasSubs = substitutablePaths.count(outPath);
|
bool hasSubs = substitutablePaths.count(outPath);
|
||||||
bool isInstalled = installed.count(outPath);
|
bool isInstalled = installed.count(outPath);
|
||||||
bool isValid = validPaths.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);
|
columns.push_back(i.attrPath);
|
||||||
|
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
auto drvName = DrvName(i.queryName());
|
auto drvName = DrvName(i.queryName(*state));
|
||||||
attrs["name"] = drvName.fullName;
|
attrs["name"] = drvName.fullName;
|
||||||
attrs["pname"] = drvName.name;
|
attrs["pname"] = drvName.name;
|
||||||
attrs["version"] = drvName.version;
|
attrs["version"] = drvName.version;
|
||||||
} else if (printName) {
|
} else if (printName) {
|
||||||
columns.push_back(i.queryName());
|
columns.push_back(i.queryName(*state));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compareVersions) {
|
if (compareVersions) {
|
||||||
@@ -1152,7 +1171,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
elements, or the set of installed elements. !!!
|
elements, or the set of installed elements. !!!
|
||||||
This is O(N * M), should be O(N * lg M). */
|
This is O(N * M), should be O(N * lg M). */
|
||||||
std::string version;
|
std::string version;
|
||||||
VersionDiff diff = compareVersionAgainstSet(i, otherElems, version);
|
VersionDiff diff = compareVersionAgainstSet(*state, i, otherElems, version);
|
||||||
|
|
||||||
char ch;
|
char ch;
|
||||||
switch (diff) {
|
switch (diff) {
|
||||||
@@ -1177,13 +1196,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (i.querySystem() != "") attrs["system"] = i.querySystem();
|
if (i.querySystem(*state) != "") attrs["system"] = i.querySystem(*state);
|
||||||
}
|
}
|
||||||
else if (printSystem)
|
else if (printSystem)
|
||||||
columns.push_back(i.querySystem());
|
columns.push_back(i.querySystem(*state));
|
||||||
|
|
||||||
if (printDrvPath) {
|
if (printDrvPath) {
|
||||||
auto drvPath = i.queryDrvPath();
|
auto drvPath = i.queryDrvPath(*state);
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
|
if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
|
||||||
} else
|
} else
|
||||||
@@ -1191,10 +1210,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlOutput)
|
if (xmlOutput)
|
||||||
attrs["outputName"] = i.queryOutputName();
|
attrs["outputName"] = i.queryOutputName(*state);
|
||||||
|
|
||||||
if (printOutPath && !xmlOutput) {
|
if (printOutPath && !xmlOutput) {
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs();
|
DrvInfo::Outputs outputs = i.queryOutputs(*state);
|
||||||
std::string s;
|
std::string s;
|
||||||
for (auto & j : outputs) {
|
for (auto & j : outputs) {
|
||||||
if (!s.empty()) s += ';';
|
if (!s.empty()) s += ';';
|
||||||
@@ -1205,7 +1224,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (printDescription) {
|
if (printDescription) {
|
||||||
auto descr = i.queryMetaString("description");
|
auto descr = i.queryMetaString(*state, "description");
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
if (descr != "") attrs["description"] = descr;
|
if (descr != "") attrs["description"] = descr;
|
||||||
} else
|
} else
|
||||||
@@ -1214,7 +1233,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
|
|
||||||
if (xmlOutput) {
|
if (xmlOutput) {
|
||||||
XMLOpenElement item(xml, "item", attrs);
|
XMLOpenElement item(xml, "item", attrs);
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
|
DrvInfo::Outputs outputs = i.queryOutputs(*state, printOutPath);
|
||||||
for (auto & j : outputs) {
|
for (auto & j : outputs) {
|
||||||
XMLAttrs attrs2;
|
XMLAttrs attrs2;
|
||||||
attrs2["name"] = j.first;
|
attrs2["name"] = j.first;
|
||||||
@@ -1223,15 +1242,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
xml.writeEmptyElement("output", attrs2);
|
xml.writeEmptyElement("output", attrs2);
|
||||||
}
|
}
|
||||||
if (printMeta) {
|
if (printMeta) {
|
||||||
StringSet metaNames = i.queryMetaNames();
|
StringSet metaNames = i.queryMetaNames(*state);
|
||||||
for (auto & j : metaNames) {
|
for (auto & j : metaNames) {
|
||||||
XMLAttrs attrs2;
|
XMLAttrs attrs2;
|
||||||
attrs2["name"] = j;
|
attrs2["name"] = j;
|
||||||
Value * v = i.queryMeta(j);
|
Value * v = i.queryMeta(*state, j);
|
||||||
if (!v)
|
if (!v)
|
||||||
printError(
|
printError(
|
||||||
"derivation '%s' has invalid meta attribute '%s'",
|
"derivation '%s' has invalid meta attribute '%s'",
|
||||||
i.queryName(), j);
|
i.queryName(*state), j);
|
||||||
else {
|
else {
|
||||||
if (v->type() == nString) {
|
if (v->type() == nString) {
|
||||||
attrs2["type"] = "string";
|
attrs2["type"] = "string";
|
||||||
@@ -1280,9 +1299,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
|
|||||||
cout.flush();
|
cout.flush();
|
||||||
|
|
||||||
} catch (AssertionError & e) {
|
} 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) {
|
} 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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1313,7 +1332,7 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg
|
|||||||
throw UsageError("exactly one argument expected");
|
throw UsageError("exactly one argument expected");
|
||||||
|
|
||||||
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
if (auto dstGen = string2Int<GenerationNumber>(opArgs.front()))
|
||||||
switchGeneration(globals.profile, *dstGen, globals.dryRun);
|
switchGeneration(globals.profile, dstGen, globals.dryRun);
|
||||||
else
|
else
|
||||||
throw UsageError("expected a generation number");
|
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;
|
Strings opFlags, opArgs;
|
||||||
@@ -1432,7 +1451,7 @@ static int main_nix_env(int argc, char * * argv)
|
|||||||
using LegacyArgs::LegacyArgs;
|
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;
|
Operation oldOp = op;
|
||||||
|
|
||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
@@ -1513,20 +1532,20 @@ static int main_nix_env(int argc, char * * argv)
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
myArgs.parseCmdline(argv);
|
||||||
|
|
||||||
if (showHelp) showManPage("nix-env" + opName);
|
if (showHelp) showManPage("nix-env" + opName);
|
||||||
if (!op) throw UsageError("no operation specified");
|
if (!op) throw UsageError("no operation specified");
|
||||||
|
|
||||||
auto store = openStore();
|
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.state->repair = myArgs.repair;
|
||||||
|
|
||||||
globals.instSource.nixExprPath = std::make_shared<SourcePath>(
|
globals.instSource.nixExprPath = std::make_shared<SourcePath>(
|
||||||
file != ""
|
file != ""
|
||||||
? lookupFileArg(*globals.state, file)
|
? lookupFileArg(*globals.state, file)
|
||||||
: globals.state->rootPath(CanonPath(nixExprPath)));
|
: CanonPath(nixExprPath));
|
||||||
|
|
||||||
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);
|
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 "lix/libstore/globals.hh"
|
||||||
#include "print-ambiguous.hh"
|
#include "lix/libexpr/print-ambiguous.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "value-to-xml.hh"
|
#include "lix/libexpr/value-to-xml.hh"
|
||||||
#include "value-to-json.hh"
|
#include "lix/libexpr/value-to-json.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
|
#include "nix-instantiate.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
using namespace nix;
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
static Path gcRoot;
|
static Path gcRoot;
|
||||||
@@ -30,7 +31,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||||||
bool evalOnly, OutputKind output, bool location, Expr & e)
|
bool evalOnly, OutputKind output, bool location, Expr & e)
|
||||||
{
|
{
|
||||||
if (parseOnly) {
|
if (parseOnly) {
|
||||||
e.show(state.symbols, std::cout);
|
e.show(state.ctx.symbols, std::cout);
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -57,18 +58,18 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||||||
} else {
|
} else {
|
||||||
if (strict) state.forceValueDeep(vRes);
|
if (strict) state.forceValueDeep(vRes);
|
||||||
std::set<const void *> seen;
|
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;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DrvInfos drvs;
|
DrvInfos drvs;
|
||||||
getDerivations(state, v, "", autoArgs, drvs, false);
|
getDerivations(state, v, "", autoArgs, drvs, false);
|
||||||
for (auto & i : drvs) {
|
for (auto & i : drvs) {
|
||||||
auto drvPath = i.requireDrvPath();
|
auto drvPath = i.requireDrvPath(state);
|
||||||
auto drvPathS = state.store->printStorePath(drvPath);
|
auto drvPathS = state.ctx.store->printStorePath(drvPath);
|
||||||
|
|
||||||
/* What output do we want? */
|
/* What output do we want? */
|
||||||
std::string outputName = i.queryOutputName();
|
std::string outputName = i.queryOutputName(state);
|
||||||
if (outputName == "")
|
if (outputName == "")
|
||||||
throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
|
throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
|||||||
else {
|
else {
|
||||||
Path rootName = absPath(gcRoot);
|
Path rootName = absPath(gcRoot);
|
||||||
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
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)
|
if (store2)
|
||||||
drvPathS = store2->addPermRoot(drvPath, rootName);
|
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;
|
Strings files;
|
||||||
@@ -108,7 +109,7 @@ static int main_nix_instantiate(int argc, char * * argv)
|
|||||||
using LegacyArgs::LegacyArgs;
|
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")
|
if (*arg == "--help")
|
||||||
showManPage("nix-instantiate");
|
showManPage("nix-instantiate");
|
||||||
else if (*arg == "--version")
|
else if (*arg == "--version")
|
||||||
@@ -148,7 +149,7 @@ static int main_nix_instantiate(int argc, char * * argv)
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
myArgs.parseCmdline(argv);
|
||||||
|
|
||||||
if (evalOnly && !wantsReadWrite)
|
if (evalOnly && !wantsReadWrite)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
@@ -156,26 +157,24 @@ static int main_nix_instantiate(int argc, char * * argv)
|
|||||||
auto store = openStore();
|
auto store = openStore();
|
||||||
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
||||||
|
|
||||||
auto state = std::make_unique<EvalState>(myArgs.searchPath, evalStore, store);
|
auto evaluator = std::make_unique<Evaluator>(myArgs.searchPath, evalStore, store);
|
||||||
state->repair = myArgs.repair;
|
auto state = evaluator->begin();
|
||||||
|
evaluator->repair = myArgs.repair;
|
||||||
|
|
||||||
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
|
Bindings & autoArgs = *myArgs.getAutoArgs(*evaluator);
|
||||||
|
|
||||||
if (attrPaths.empty()) attrPaths = {""};
|
if (attrPaths.empty()) attrPaths = {""};
|
||||||
|
|
||||||
if (findFile) {
|
if (findFile) {
|
||||||
for (auto & i : files) {
|
for (auto & i : files) {
|
||||||
auto p = state->findFile(i);
|
auto p = evaluator->paths.findFile(i);
|
||||||
if (auto fn = p.getPhysicalPath())
|
std::cout << p.canonical().abs() << std::endl;
|
||||||
std::cout << fn->abs() << std::endl;
|
|
||||||
else
|
|
||||||
throw Error("'%s' has no physical path", p);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readStdin) {
|
if (readStdin) {
|
||||||
Expr & e = state->parseStdin();
|
Expr & e = evaluator->parseStdin();
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
} else if (files.empty() && !fromArgs)
|
} else if (files.empty() && !fromArgs)
|
||||||
@@ -183,16 +182,20 @@ static int main_nix_instantiate(int argc, char * * argv)
|
|||||||
|
|
||||||
for (auto & i : files) {
|
for (auto & i : files) {
|
||||||
Expr & e = fromArgs
|
Expr & e = fromArgs
|
||||||
? state->parseExprFromString(i, state->rootPath(CanonPath::fromCwd()))
|
? evaluator->parseExprFromString(i, CanonPath::fromCwd())
|
||||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
: evaluator->parseExprFromFile(evaluator->paths.resolveExprPath(lookupFileArg(*evaluator, i)));
|
||||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
state->maybePrintStats();
|
evaluator->maybePrintStats();
|
||||||
|
|
||||||
return 0;
|
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,33 +1,33 @@
|
|||||||
#include "archive.hh"
|
#include "lix/libutil/archive.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "dotgraph.hh"
|
#include "dotgraph.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libutil/exit.hh"
|
||||||
#include "build-result.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "store-cast.hh"
|
#include "lix/libstore/build-result.hh"
|
||||||
#include "gc-store.hh"
|
#include "lix/libstore/store-cast.hh"
|
||||||
#include "log-store.hh"
|
#include "lix/libstore/gc-store.hh"
|
||||||
#include "local-store.hh"
|
#include "lix/libstore/log-store.hh"
|
||||||
#include "monitor-fd.hh"
|
#include "lix/libstore/local-store.hh"
|
||||||
#include "serve-protocol.hh"
|
#include "lix/libutil/monitor-fd.hh"
|
||||||
#include "serve-protocol-impl.hh"
|
#include "lix/libstore/serve-protocol.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libstore/serve-protocol-impl.hh"
|
||||||
|
#include "lix/libmain/shared.hh"
|
||||||
#include "graphml.hh"
|
#include "graphml.hh"
|
||||||
#include "legacy.hh"
|
#include "lix/libcmd/legacy.hh"
|
||||||
#include "path-with-outputs.hh"
|
#include "lix/libstore/path-with-outputs.hh"
|
||||||
|
#include "nix-store.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
namespace nix_store {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
using namespace nix;
|
|
||||||
using std::cin;
|
using std::cin;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
@@ -831,12 +831,12 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
// FIXME: changing options here doesn't work if we're
|
// FIXME: changing options here doesn't work if we're
|
||||||
// building through the daemon.
|
// building through the daemon.
|
||||||
verbosity = lvlError;
|
verbosity = lvlError;
|
||||||
settings.keepLog = false;
|
settings.keepLog.override(false);
|
||||||
settings.useSubstitutes = false;
|
settings.useSubstitutes.override(false);
|
||||||
settings.maxSilentTime = readInt(in);
|
settings.maxSilentTime.override(readInt(in));
|
||||||
settings.buildTimeout = readInt(in);
|
settings.buildTimeout.override(readInt(in));
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
|
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) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
|
||||||
auto nrRepeats = readInt(in);
|
auto nrRepeats = readInt(in);
|
||||||
if (nrRepeats != 0) {
|
if (nrRepeats != 0) {
|
||||||
@@ -850,10 +850,10 @@ static void opServe(Strings opFlags, Strings opArgs)
|
|||||||
// asked for.
|
// asked for.
|
||||||
readInt(in);
|
readInt(in);
|
||||||
|
|
||||||
settings.runDiffHook = true;
|
settings.runDiffHook.override(true);
|
||||||
}
|
}
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 7) {
|
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
|
/* Scan the arguments; find the operation, set global flags, put all
|
||||||
other flags in a list, and put all other arguments in another
|
other flags in a list, and put all other arguments in another
|
||||||
list. */
|
list. */
|
||||||
static int main_nix_store(int argc, char * * argv)
|
static int main_nix_store(std::string programName, Strings argv)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Strings opFlags, opArgs;
|
Strings opFlags, opArgs;
|
||||||
@@ -1040,7 +1040,7 @@ static int main_nix_store(int argc, char * * argv)
|
|||||||
std::string opName;
|
std::string opName;
|
||||||
bool showHelp = false;
|
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;
|
Operation oldOp = op;
|
||||||
|
|
||||||
if (*arg == "--help")
|
if (*arg == "--help")
|
||||||
@@ -1162,7 +1162,7 @@ static int main_nix_store(int argc, char * * argv)
|
|||||||
throw UsageError("only one operation may be specified");
|
throw UsageError("only one operation may be specified");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
}).parseCmdline(argv);
|
||||||
|
|
||||||
if (showHelp) showManPage("nix-store" + opName);
|
if (showHelp) showManPage("nix-store" + opName);
|
||||||
if (!op) throw UsageError("no operation specified");
|
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 "user-env.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "path-with-outputs.hh"
|
#include "lix/libstore/path-with-outputs.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
#include "profiles.hh"
|
#include "lix/libstore/profiles.hh"
|
||||||
#include "print-ambiguous.hh"
|
#include "lix/libexpr/print-ambiguous.hh"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -24,66 +24,65 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||||||
exist already. */
|
exist already. */
|
||||||
std::vector<StorePathWithOutputs> drvsToBuild;
|
std::vector<StorePathWithOutputs> drvsToBuild;
|
||||||
for (auto & i : elems)
|
for (auto & i : elems)
|
||||||
if (auto drvPath = i.queryDrvPath())
|
if (auto drvPath = i.queryDrvPath(state))
|
||||||
drvsToBuild.push_back({*drvPath});
|
drvsToBuild.push_back({*drvPath});
|
||||||
|
|
||||||
debug("building user environment dependencies");
|
debug("building user environment dependencies");
|
||||||
state.store->buildPaths(
|
state.ctx.store->buildPaths(
|
||||||
toDerivedPaths(drvsToBuild),
|
toDerivedPaths(drvsToBuild),
|
||||||
state.repair ? bmRepair : bmNormal);
|
state.ctx.repair ? bmRepair : bmNormal);
|
||||||
|
|
||||||
/* Construct the whole top level derivation. */
|
/* Construct the whole top level derivation. */
|
||||||
StorePathSet references;
|
StorePathSet references;
|
||||||
Value manifest;
|
Value manifest = state.ctx.mem.newList(elems.size());
|
||||||
state.mkList(manifest, elems.size());
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for (auto & i : elems) {
|
for (auto & i : elems) {
|
||||||
/* Create a pseudo-derivation containing the name, system,
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
output paths, and optionally the derivation path, as well
|
output paths, and optionally the derivation path, as well
|
||||||
as the meta attributes. */
|
as the meta attributes. */
|
||||||
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt;
|
std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath(state) : std::nullopt;
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs(true, true);
|
DrvInfo::Outputs outputs = i.queryOutputs(state, true, true);
|
||||||
StringSet metaNames = i.queryMetaNames();
|
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.ctx.s.type).mkString("derivation");
|
||||||
attrs.alloc(state.sName).mkString(i.queryName());
|
attrs.alloc(state.ctx.s.name).mkString(i.queryName(state));
|
||||||
auto system = i.querySystem();
|
auto system = i.querySystem(state);
|
||||||
if (!system.empty())
|
if (!system.empty())
|
||||||
attrs.alloc(state.sSystem).mkString(system);
|
attrs.alloc(state.ctx.s.system).mkString(system);
|
||||||
attrs.alloc(state.sOutPath).mkString(state.store->printStorePath(i.queryOutPath()));
|
attrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(i.queryOutPath(state)));
|
||||||
if (drvPath)
|
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.
|
// Copy each output meant for installation.
|
||||||
auto & vOutputs = attrs.alloc(state.sOutputs);
|
auto & vOutputs = attrs.alloc(state.ctx.s.outputs);
|
||||||
state.mkList(vOutputs, outputs.size());
|
vOutputs = state.ctx.mem.newList(outputs.size());
|
||||||
for (const auto & [m, j] : enumerate(outputs)) {
|
for (const auto & [m, j] : enumerate(outputs)) {
|
||||||
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
(vOutputs.listElems()[m] = state.ctx.mem.allocValue())->mkString(j.first);
|
||||||
auto outputAttrs = state.buildBindings(2);
|
auto outputAttrs = state.ctx.buildBindings(2);
|
||||||
outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(*j.second));
|
outputAttrs.alloc(state.ctx.s.outPath).mkString(state.ctx.store->printStorePath(*j.second));
|
||||||
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
state.store->addTempRoot(*j.second);
|
state.ctx.store->addTempRoot(*j.second);
|
||||||
state.store->ensurePath(*j.second);
|
state.ctx.store->ensurePath(*j.second);
|
||||||
|
|
||||||
references.insert(*j.second);
|
references.insert(*j.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the meta attributes.
|
// Copy the meta attributes.
|
||||||
auto meta = state.buildBindings(metaNames.size());
|
auto meta = state.ctx.buildBindings(metaNames.size());
|
||||||
for (auto & j : metaNames) {
|
for (auto & j : metaNames) {
|
||||||
Value * v = i.queryMeta(j);
|
Value * v = i.queryMeta(state, j);
|
||||||
if (!v) continue;
|
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);
|
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
|
the store; we need it for future modifications of the
|
||||||
environment. */
|
environment. */
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
printAmbiguous(manifest, state.symbols, str, nullptr, std::numeric_limits<int>::max());
|
printAmbiguous(manifest, state.ctx.symbols, str, nullptr, std::numeric_limits<int>::max());
|
||||||
auto manifestFile = state.store->addTextToStore("env-manifest.nix",
|
auto manifestFile = state.ctx.store->addTextToStore("env-manifest.nix",
|
||||||
str.str(), references);
|
str.str(), references);
|
||||||
|
|
||||||
/* Get the environment builder expression. */
|
/* Get the environment builder expression. */
|
||||||
Value envBuilder;
|
Value envBuilder;
|
||||||
state.eval(state.parseExprFromString(
|
state.eval(state.ctx.parseExprFromString(
|
||||||
#include "buildenv.nix.gen.hh"
|
#include "buildenv.nix.gen.hh"
|
||||||
, state.rootPath(CanonPath::root)), envBuilder);
|
, CanonPath::root), envBuilder);
|
||||||
|
|
||||||
/* Construct a Nix expression that calls the user environment
|
/* Construct a Nix expression that calls the user environment
|
||||||
builder with the manifest as argument. */
|
builder with the manifest as argument. */
|
||||||
auto attrs = state.buildBindings(3);
|
auto attrs = state.ctx.buildBindings(3);
|
||||||
state.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
state.ctx.paths.mkStorePathString(manifestFile, attrs.alloc("manifest"));
|
||||||
attrs.insert(state.symbols.create("derivations"), &manifest);
|
attrs.insert(state.ctx.symbols.create("derivations"), &manifest);
|
||||||
Value args;
|
Value args;
|
||||||
args.mkAttrs(attrs);
|
args.mkAttrs(attrs);
|
||||||
|
|
||||||
@@ -117,21 +116,21 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|||||||
debug("evaluating user environment builder");
|
debug("evaluating user environment builder");
|
||||||
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
state.forceValue(topLevel, topLevel.determinePos(noPos));
|
||||||
NixStringContext context;
|
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, "");
|
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, "");
|
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");
|
||||||
|
|
||||||
/* Realise the resulting store expression. */
|
/* Realise the resulting store expression. */
|
||||||
debug("building user environment");
|
debug("building user environment");
|
||||||
std::vector<StorePathWithOutputs> topLevelDrvs;
|
std::vector<StorePathWithOutputs> topLevelDrvs;
|
||||||
topLevelDrvs.push_back({topLevelDrv});
|
topLevelDrvs.push_back({topLevelDrv});
|
||||||
state.store->buildPaths(
|
state.ctx.store->buildPaths(
|
||||||
toDerivedPaths(topLevelDrvs),
|
toDerivedPaths(topLevelDrvs),
|
||||||
state.repair ? bmRepair : bmNormal);
|
state.ctx.repair ? bmRepair : bmNormal);
|
||||||
|
|
||||||
/* Switch the current user environment to the output path. */
|
/* 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) {
|
if (store2) {
|
||||||
PathLocks lock;
|
PathLocks lock;
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
DrvInfos queryInstalled(EvalState & state, const Path & userEnv);
|
|
||||||
|
|
||||||
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
const Path & profile, bool keepDerivations,
|
const Path & profile, bool keepDerivations,
|
||||||
const std::string & lockToken);
|
const std::string & lockToken);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "built-path.hh"
|
#include "lix/libcmd/built-path.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
#include "derived-path.hh"
|
#include "lix/libstore/derived-path.hh"
|
||||||
#include "realisation.hh"
|
#include "lix/libstore/realisation.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -20,13 +20,15 @@ struct SingleBuiltPathBuilt {
|
|||||||
DECLARE_CMP(SingleBuiltPathBuilt);
|
DECLARE_CMP(SingleBuiltPathBuilt);
|
||||||
};
|
};
|
||||||
|
|
||||||
using _SingleBuiltPathRaw = std::variant<
|
namespace built_path::detail {
|
||||||
|
using SingleBuiltPathRaw = std::variant<
|
||||||
DerivedPathOpaque,
|
DerivedPathOpaque,
|
||||||
SingleBuiltPathBuilt
|
SingleBuiltPathBuilt
|
||||||
>;
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
struct SingleBuiltPath : _SingleBuiltPathRaw {
|
struct SingleBuiltPath : built_path::detail::SingleBuiltPathRaw {
|
||||||
using Raw = _SingleBuiltPathRaw;
|
using Raw = built_path::detail::SingleBuiltPathRaw;
|
||||||
using Raw::Raw;
|
using Raw::Raw;
|
||||||
|
|
||||||
using Opaque = DerivedPathOpaque;
|
using Opaque = DerivedPathOpaque;
|
||||||
@@ -65,17 +67,19 @@ struct BuiltPathBuilt {
|
|||||||
DECLARE_CMP(BuiltPathBuilt);
|
DECLARE_CMP(BuiltPathBuilt);
|
||||||
};
|
};
|
||||||
|
|
||||||
using _BuiltPathRaw = std::variant<
|
namespace built_path::detail {
|
||||||
|
using BuiltPathRaw = std::variant<
|
||||||
DerivedPath::Opaque,
|
DerivedPath::Opaque,
|
||||||
BuiltPathBuilt
|
BuiltPathBuilt
|
||||||
>;
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A built path. Similar to a DerivedPath, but enriched with the corresponding
|
* A built path. Similar to a DerivedPath, but enriched with the corresponding
|
||||||
* output path(s).
|
* output path(s).
|
||||||
*/
|
*/
|
||||||
struct BuiltPath : _BuiltPathRaw {
|
struct BuiltPath : built_path::detail::BuiltPathRaw {
|
||||||
using Raw = _BuiltPathRaw;
|
using Raw = built_path::detail::BuiltPathRaw;
|
||||||
using Raw::Raw;
|
using Raw::Raw;
|
||||||
|
|
||||||
using Opaque = DerivedPathOpaque;
|
using Opaque = DerivedPathOpaque;
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "cmd-profiles.hh"
|
#include "lix/libcmd/cmd-profiles.hh"
|
||||||
#include "built-path.hh"
|
#include "lix/libcmd/built-path.hh"
|
||||||
#include "builtins/buildenv.hh"
|
#include "lix/libstore/builtins/buildenv.hh"
|
||||||
#include "logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
#include "names.hh"
|
#include "lix/libstore/names.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "url-name.hh"
|
#include "lix/libstore/temporary-dir.hh"
|
||||||
|
#include "lix/libutil/url-name.hh"
|
||||||
|
|
||||||
namespace nix
|
namespace nix
|
||||||
{
|
{
|
||||||
@@ -19,8 +20,8 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
|||||||
auto manifestFile = userEnv + "/manifest.nix";
|
auto manifestFile = userEnv + "/manifest.nix";
|
||||||
if (pathExists(manifestFile)) {
|
if (pathExists(manifestFile)) {
|
||||||
Value v;
|
Value v;
|
||||||
state.evalFile(state.rootPath(CanonPath(manifestFile)), v);
|
state.evalFile(CanonPath(manifestFile), v);
|
||||||
Bindings & bindings(*state.allocBindings(0));
|
Bindings & bindings(*state.ctx.mem.allocBindings(0));
|
||||||
getDerivations(state, v, "", bindings, elems, false);
|
getDerivations(state, v, "", bindings, elems, false);
|
||||||
}
|
}
|
||||||
return elems;
|
return elems;
|
||||||
@@ -135,7 +136,7 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile)
|
|||||||
auto & e = elem.value();
|
auto & e = elem.value();
|
||||||
ProfileElement element;
|
ProfileElement element;
|
||||||
for (auto & p : e["storePaths"]) {
|
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"];
|
element.active = e["active"];
|
||||||
if (e.contains("priority")) {
|
if (e.contains("priority")) {
|
||||||
@@ -161,14 +162,14 @@ ProfileManifest::ProfileManifest(EvalState & state, const Path & profile)
|
|||||||
}
|
}
|
||||||
} else if (pathExists(profile + "/manifest.nix")) {
|
} else if (pathExists(profile + "/manifest.nix")) {
|
||||||
// FIXME: needed because of pure mode; ugly.
|
// FIXME: needed because of pure mode; ugly.
|
||||||
state.allowPath(state.store->followLinksToStore(profile));
|
state.ctx.paths.allowPath(state.ctx.store->followLinksToStore(profile));
|
||||||
state.allowPath(state.store->followLinksToStore(profile + "/manifest.nix"));
|
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) {
|
for (auto & drvInfo : drvInfos) {
|
||||||
ProfileElement element;
|
ProfileElement element;
|
||||||
element.storePaths = {drvInfo.queryOutPath()};
|
element.storePaths = {drvInfo.queryOutPath(state)};
|
||||||
addElement(std::move(element));
|
addElement(std::move(element));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "built-path.hh"
|
#include "lix/libcmd/built-path.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "flake/flakeref.hh"
|
#include "lix/libexpr/flake/flakeref.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "types.hh"
|
#include "lix/libutil/types.hh"
|
||||||
#include "url.hh"
|
#include "lix/libutil/url.hh"
|
||||||
#include "url-name.hh"
|
#include "lix/libutil/url-name.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "command.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "nixexpr.hh"
|
#include "lix/libexpr/nixexpr.hh"
|
||||||
#include "profiles.hh"
|
#include "lix/libstore/profiles.hh"
|
||||||
#include "repl.hh"
|
#include "lix/libcmd/repl.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
@@ -28,12 +28,6 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & p
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json NixMultiCommand::toJSON()
|
|
||||||
{
|
|
||||||
// FIXME: use Command::toJSON() as well.
|
|
||||||
return MultiCommand::toJSON();
|
|
||||||
}
|
|
||||||
|
|
||||||
StoreCommand::StoreCommand()
|
StoreCommand::StoreCommand()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -108,26 +102,17 @@ ref<Store> EvalCommand::getEvalStore()
|
|||||||
return ref<Store>(evalStore);
|
return ref<Store>(evalStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<EvalState> EvalCommand::getEvalState()
|
ref<eval_cache::CachingEvaluator> EvalCommand::getEvaluator()
|
||||||
{
|
{
|
||||||
if (!evalState) {
|
if (!evalState) {
|
||||||
evalState =
|
evalState = std::allocate_shared<eval_cache::CachingEvaluator>(
|
||||||
#if HAVE_BOEHMGC
|
TraceableAllocator<EvalState>(), searchPath, getEvalStore(), getStore(),
|
||||||
std::allocate_shared<EvalState>(traceable_allocator<EvalState>(),
|
startReplOnEvalErrors ? AbstractNixRepl::runSimple : nullptr
|
||||||
searchPath, getEvalStore(), getStore())
|
);
|
||||||
#else
|
|
||||||
std::make_shared<EvalState>(
|
|
||||||
searchPath, getEvalStore(), getStore())
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
evalState->repair = repair;
|
evalState->repair = repair;
|
||||||
|
|
||||||
if (startReplOnEvalErrors) {
|
|
||||||
evalState->debugRepl = &AbstractNixRepl::runSimple;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return ref<EvalState>(evalState);
|
return ref<eval_cache::CachingEvaluator>(evalState);
|
||||||
}
|
}
|
||||||
|
|
||||||
MixOperateOnOptions::MixOperateOnOptions()
|
MixOperateOnOptions::MixOperateOnOptions()
|
||||||
@@ -177,7 +162,7 @@ void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
|
|||||||
for (auto & p : store->queryAllValidPaths())
|
for (auto & p : store->queryAllValidPaths())
|
||||||
paths.emplace_back(BuiltPath::Opaque{p});
|
paths.emplace_back(BuiltPath::Opaque{p});
|
||||||
} else {
|
} else {
|
||||||
paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
paths = Installable::toBuiltPaths(*getEvaluator()->begin(), getEvalStore(), store, realiseMode, operateOn, installables);
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
// XXX: This only computes the store path closure, ignoring
|
// XXX: This only computes the store path closure, ignoring
|
||||||
// intermediate realisations
|
// intermediate realisations
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "installable-value.hh"
|
#include "lix/libcmd/installable-value.hh"
|
||||||
#include "args.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libutil/args.hh"
|
||||||
#include "path.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "flake/lockfile.hh"
|
#include "lix/libstore/path.hh"
|
||||||
|
#include "lix/libexpr/flake/lockfile.hh"
|
||||||
|
|
||||||
#include <optional>
|
#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)";
|
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
|
// For the overloaded run methods
|
||||||
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
|
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
|
||||||
|
|
||||||
@@ -81,12 +77,12 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
|
|||||||
|
|
||||||
ref<Store> getEvalStore();
|
ref<Store> getEvalStore();
|
||||||
|
|
||||||
ref<EvalState> getEvalState();
|
virtual ref<eval_cache::CachingEvaluator> getEvaluator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Store> evalStore;
|
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();
|
SourceExprCommand();
|
||||||
|
|
||||||
|
ref<eval_cache::CachingEvaluator> getEvaluator() override;
|
||||||
|
|
||||||
Installables parseInstallables(
|
Installables parseInstallables(
|
||||||
ref<Store> store, std::vector<std::string> ss);
|
EvalState & state, ref<Store> store, std::vector<std::string> ss);
|
||||||
|
|
||||||
ref<Installable> parseInstallable(
|
ref<Installable> parseInstallable(
|
||||||
ref<Store> store, const std::string & installable);
|
EvalState & state, ref<Store> store, const std::string & installable);
|
||||||
|
|
||||||
virtual Strings getDefaultFlakeAttrPaths();
|
virtual Strings getDefaultFlakeAttrPaths();
|
||||||
|
|
||||||
@@ -131,7 +129,7 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
|
|||||||
/**
|
/**
|
||||||
* Complete an installable from the given prefix.
|
* 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
|
* Convenience wrapper around the underlying function to make setting the
|
||||||
@@ -232,7 +230,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BuiltPathsCommand(bool recursive = false);
|
BuiltPathsCommand(bool recursive);
|
||||||
|
|
||||||
virtual void run(ref<Store> store, BuiltPaths && paths) = 0;
|
virtual void run(ref<Store> store, BuiltPaths && paths) = 0;
|
||||||
|
|
||||||
@@ -328,7 +326,7 @@ struct MixEnvironment : virtual Args {
|
|||||||
|
|
||||||
void completeFlakeInputPath(
|
void completeFlakeInputPath(
|
||||||
AddCompletions & completions,
|
AddCompletions & completions,
|
||||||
ref<EvalState> evalState,
|
EvalState & evalState,
|
||||||
const std::vector<FlakeRef> & flakeRefs,
|
const std::vector<FlakeRef> & flakeRefs,
|
||||||
std::string_view prefix);
|
std::string_view prefix);
|
||||||
|
|
||||||
@@ -336,7 +334,8 @@ void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::strin
|
|||||||
|
|
||||||
void completeFlakeRefWithFragment(
|
void completeFlakeRefWithFragment(
|
||||||
AddCompletions & completions,
|
AddCompletions & completions,
|
||||||
ref<EvalState> evalState,
|
EvalState & evalState,
|
||||||
|
ref<eval_cache::CachingEvaluator> evaluator,
|
||||||
flake::LockFlags lockFlags,
|
flake::LockFlags lockFlags,
|
||||||
Strings attrPathPrefixes,
|
Strings attrPathPrefixes,
|
||||||
const Strings & defaultFlakeAttrPaths,
|
const Strings & defaultFlakeAttrPaths,
|
||||||
@@ -1,16 +1,32 @@
|
|||||||
#include "eval-settings.hh"
|
#include "lix/libexpr/eval-settings.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "fetchers.hh"
|
#include "lix/libfetchers/fetchers.hh"
|
||||||
#include "registry.hh"
|
#include "lix/libfetchers/registry.hh"
|
||||||
#include "flake/flakeref.hh"
|
#include "lix/libexpr/flake/flakeref.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "command.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
namespace nix {
|
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()
|
MixEvalArgs::MixEvalArgs()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
@@ -18,7 +34,10 @@ MixEvalArgs::MixEvalArgs()
|
|||||||
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
|
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
|
||||||
.category = category,
|
.category = category,
|
||||||
.labels = {"name", "expr"},
|
.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({
|
addFlag({
|
||||||
@@ -26,7 +45,10 @@ MixEvalArgs::MixEvalArgs()
|
|||||||
.description = "Pass the string *string* as the argument *name* to Nix functions.",
|
.description = "Pass the string *string* as the argument *name* to Nix functions.",
|
||||||
.category = category,
|
.category = category,
|
||||||
.labels = {"name", "string"},
|
.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({
|
addFlag({
|
||||||
@@ -115,7 +137,7 @@ MixEvalArgs::MixEvalArgs()
|
|||||||
.description = "Allow access to mutable paths and repositories.",
|
.description = "Allow access to mutable paths and repositories.",
|
||||||
.category = category,
|
.category = category,
|
||||||
.handler = {[&]() {
|
.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());
|
auto res = state.buildBindings(autoArgs.size());
|
||||||
for (auto & i : autoArgs) {
|
for (auto & i : autoArgs) {
|
||||||
auto v = state.allocValue();
|
auto v = state.mem.allocValue();
|
||||||
if (i.second[0] == 'E')
|
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
|
else
|
||||||
v->mkString(((std::string_view) i.second).substr(1));
|
v->mkString(((std::string_view) i.second).substr(1));
|
||||||
res.insert(state.symbols.create(i.first), v);
|
res.insert(state.symbols.create(i.first), v);
|
||||||
@@ -163,7 +187,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
|||||||
return res.finish();
|
return res.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
|
SourcePath lookupFileArg(Evaluator & state, std::string_view fileArg)
|
||||||
{
|
{
|
||||||
if (EvalSettings::isPseudoUrl(fileArg)) {
|
if (EvalSettings::isPseudoUrl(fileArg)) {
|
||||||
auto const url = EvalSettings::resolvePseudoUrl(fileArg);
|
auto const url = EvalSettings::resolvePseudoUrl(fileArg);
|
||||||
@@ -174,18 +198,18 @@ SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
|
|||||||
/* locked */ false
|
/* locked */ false
|
||||||
);
|
);
|
||||||
StorePath const storePath = downloaded.tree.storePath;
|
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:")) {
|
} else if (fileArg.starts_with("flake:")) {
|
||||||
experimentalFeatureSettings.require(Xp::Flakes);
|
experimentalFeatureSettings.require(Xp::Flakes);
|
||||||
static constexpr size_t FLAKE_LEN = std::string_view("flake:").size();
|
static constexpr size_t FLAKE_LEN = std::string_view("flake:").size();
|
||||||
auto flakeRef = parseFlakeRef(std::string(fileArg.substr(FLAKE_LEN)), {}, true, false);
|
auto flakeRef = parseFlakeRef(std::string(fileArg.substr(FLAKE_LEN)), {}, true, false);
|
||||||
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
|
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) == '>') {
|
} else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
|
||||||
Path p(fileArg.substr(1, fileArg.size() - 2));
|
Path p(fileArg.substr(1, fileArg.size() - 2));
|
||||||
return state.findFile(p);
|
return state.paths.findFile(p);
|
||||||
} else {
|
} else {
|
||||||
return state.rootPath(CanonPath::fromCwd(fileArg));
|
return CanonPath::fromCwd(fileArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "args.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "common-args.hh"
|
#include "lix/libutil/args.hh"
|
||||||
#include "search-path.hh"
|
#include "lix/libmain/common-args.hh"
|
||||||
|
#include "lix/libexpr/search-path.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ struct MixEvalArgs : virtual Args, virtual MixRepair
|
|||||||
|
|
||||||
MixEvalArgs();
|
MixEvalArgs();
|
||||||
|
|
||||||
Bindings * getAutoArgs(EvalState & state);
|
Bindings * getAutoArgs(Evaluator & state);
|
||||||
|
|
||||||
SearchPath searchPath;
|
SearchPath searchPath;
|
||||||
|
|
||||||
@@ -48,6 +49,6 @@ private:
|
|||||||
*
|
*
|
||||||
* @exception nix::ThrownError for failed search path lookup. Probably others.
|
* @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,14 +1,12 @@
|
|||||||
#include "editor-for.hh"
|
#include "lix/libcmd/editor-for.hh"
|
||||||
#include "environment-variables.hh"
|
#include "lix/libutil/environment-variables.hh"
|
||||||
#include "source-path.hh"
|
#include "lix/libutil/source-path.hh"
|
||||||
|
#include "lix/libutil/strings.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Strings editorFor(const SourcePath & file, uint32_t line)
|
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 editor = getEnv("EDITOR").value_or("cat");
|
||||||
auto args = tokenizeString<Strings>(editor);
|
auto args = tokenizeString<Strings>(editor);
|
||||||
if (line > 0 && (
|
if (line > 0 && (
|
||||||
@@ -17,7 +15,7 @@ Strings editorFor(const SourcePath & file, uint32_t line)
|
|||||||
editor.find("vim") != std::string::npos ||
|
editor.find("vim") != std::string::npos ||
|
||||||
editor.find("kak") != std::string::npos))
|
editor.find("kak") != std::string::npos))
|
||||||
args.push_back(fmt("+%d", line));
|
args.push_back(fmt("+%d", line));
|
||||||
args.push_back(path->abs());
|
args.push_back(file.canonical().abs());
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "types.hh"
|
#include "lix/libutil/types.hh"
|
||||||
#include "source-path.hh"
|
#include "lix/libutil/source-path.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
#include "installable-attr-path.hh"
|
#include "lix/libcmd/installable-attr-path.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "lix/libstore/outputs-spec.hh"
|
||||||
#include "command.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "flake/flake.hh"
|
#include "lix/libexpr/flake/flake.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
InstallableAttrPath::InstallableAttrPath(
|
InstallableAttrPath::InstallableAttrPath(
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
SourceExprCommand & cmd,
|
SourceExprCommand & cmd,
|
||||||
Value * v,
|
Value * v,
|
||||||
const std::string & attrPath,
|
const std::string & attrPath,
|
||||||
@@ -26,41 +26,40 @@ InstallableAttrPath::InstallableAttrPath(
|
|||||||
|
|
||||||
std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
|
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);
|
state.forceValue(*vRes, pos);
|
||||||
return {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(
|
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
|
||||||
*v,
|
state, *v, pos, fmt("while evaluating the attribute '%s'", attrPath)
|
||||||
pos,
|
))
|
||||||
fmt("while evaluating the attribute '%s'", attrPath)))
|
|
||||||
{
|
{
|
||||||
return { *derivedPathWithInfo };
|
return { *derivedPathWithInfo };
|
||||||
}
|
}
|
||||||
|
|
||||||
Bindings & autoArgs = *cmd.getAutoArgs(*state);
|
Bindings & autoArgs = *cmd.getAutoArgs(*evaluator);
|
||||||
|
|
||||||
DrvInfos drvInfos;
|
DrvInfos drvInfos;
|
||||||
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
|
getDerivations(state, *v, "", autoArgs, drvInfos, false);
|
||||||
|
|
||||||
// Backward compatibility hack: group results by drvPath. This
|
// Backward compatibility hack: group results by drvPath. This
|
||||||
// helps keep .all output together.
|
// helps keep .all output together.
|
||||||
std::map<StorePath, OutputsSpec> byDrvPath;
|
std::map<StorePath, OutputsSpec> byDrvPath;
|
||||||
|
|
||||||
for (auto & drvInfo : drvInfos) {
|
for (auto & drvInfo : drvInfos) {
|
||||||
auto drvPath = drvInfo.queryDrvPath();
|
auto drvPath = drvInfo.queryDrvPath(state);
|
||||||
if (!drvPath)
|
if (!drvPath)
|
||||||
throw Error("'%s' is not a derivation", what());
|
throw Error("'%s' is not a derivation", what());
|
||||||
|
|
||||||
auto newOutputs = std::visit(overloaded {
|
auto newOutputs = std::visit(overloaded {
|
||||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||||
std::set<std::string> outputsToInstall;
|
std::set<std::string> outputsToInstall;
|
||||||
for (auto & output : drvInfo.queryOutputs(false, true))
|
for (auto & output : drvInfo.queryOutputs(state, false, true))
|
||||||
outputsToInstall.insert(output.first);
|
outputsToInstall.insert(output.first);
|
||||||
return OutputsSpec::Names { std::move(outputsToInstall) };
|
return OutputsSpec::Names { std::move(outputsToInstall) };
|
||||||
},
|
},
|
||||||
@@ -93,7 +92,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
|
|||||||
}
|
}
|
||||||
|
|
||||||
InstallableAttrPath InstallableAttrPath::parse(
|
InstallableAttrPath InstallableAttrPath::parse(
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
SourceExprCommand & cmd,
|
SourceExprCommand & cmd,
|
||||||
Value * v,
|
Value * v,
|
||||||
std::string_view prefix,
|
std::string_view prefix,
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "installable-value.hh"
|
#include "lix/libcmd/installable-value.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "command.hh"
|
#include "lix/libstore/outputs-spec.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
|
#include "lix/libexpr/eval.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ class InstallableAttrPath : public InstallableValue
|
|||||||
ExtendedOutputsSpec extendedOutputsSpec;
|
ExtendedOutputsSpec extendedOutputsSpec;
|
||||||
|
|
||||||
InstallableAttrPath(
|
InstallableAttrPath(
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
SourceExprCommand & cmd,
|
SourceExprCommand & cmd,
|
||||||
Value * v,
|
Value * v,
|
||||||
const std::string & attrPath,
|
const std::string & attrPath,
|
||||||
@@ -29,12 +30,12 @@ class InstallableAttrPath : public InstallableValue
|
|||||||
|
|
||||||
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
std::pair<Value *, PosIdx> toValue(EvalState & state) override;
|
||||||
|
|
||||||
DerivedPathsWithInfo toDerivedPaths() override;
|
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static InstallableAttrPath parse(
|
static InstallableAttrPath parse(
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
SourceExprCommand & cmd,
|
SourceExprCommand & cmd,
|
||||||
Value * v,
|
Value * v,
|
||||||
std::string_view prefix,
|
std::string_view prefix,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "installable-derived-path.hh"
|
#include "lix/libcmd/installable-derived-path.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ std::string InstallableDerivedPath::what() const
|
|||||||
return derivedPath.to_string(*store);
|
return derivedPath.to_string(*store);
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths()
|
DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths(EvalState & state)
|
||||||
{
|
{
|
||||||
return {{
|
return {{
|
||||||
.path = derivedPath,
|
.path = derivedPath,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "installables.hh"
|
#include "lix/libcmd/installables.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ struct InstallableDerivedPath : Installable
|
|||||||
|
|
||||||
std::string what() const override;
|
std::string what() const override;
|
||||||
|
|
||||||
DerivedPathsWithInfo toDerivedPaths() override;
|
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||||
|
|
||||||
std::optional<StorePath> getStorePath() override;
|
std::optional<StorePath> getStorePath() override;
|
||||||
|
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
#include "globals.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "installable-flake.hh"
|
#include "lix/libcmd/installable-flake.hh"
|
||||||
#include "installable-derived-path.hh"
|
#include "lix/libcmd/installable-derived-path.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "lix/libstore/outputs-spec.hh"
|
||||||
#include "command.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "eval-inline.hh"
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "flake/flake.hh"
|
#include "lix/libexpr/flake/flake.hh"
|
||||||
#include "eval-cache.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "url.hh"
|
#include "lix/libutil/url.hh"
|
||||||
#include "registry.hh"
|
#include "lix/libfetchers/registry.hh"
|
||||||
#include "build-result.hh"
|
#include "lix/libstore/build-result.hh"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@@ -41,20 +41,6 @@ std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
|||||||
return res;
|
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)
|
static std::string showAttrPaths(const std::vector<std::string> & paths)
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
@@ -67,7 +53,7 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
|
|||||||
|
|
||||||
InstallableFlake::InstallableFlake(
|
InstallableFlake::InstallableFlake(
|
||||||
SourceExprCommand * cmd,
|
SourceExprCommand * cmd,
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
FlakeRef && flakeRef,
|
FlakeRef && flakeRef,
|
||||||
std::string_view fragment,
|
std::string_view fragment,
|
||||||
ExtendedOutputsSpec extendedOutputsSpec,
|
ExtendedOutputsSpec extendedOutputsSpec,
|
||||||
@@ -85,23 +71,22 @@ InstallableFlake::InstallableFlake(
|
|||||||
throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
|
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()));
|
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?
|
// FIXME: use eval cache?
|
||||||
auto v = attr->forceValue();
|
auto v = attr->forceValue(state);
|
||||||
|
|
||||||
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
|
if (std::optional derivedPathWithInfo = trySinglePathToDerivedPaths(
|
||||||
v,
|
state, v, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath)
|
||||||
noPos,
|
))
|
||||||
fmt("while evaluating the flake output attribute '%s'", attrPath)))
|
|
||||||
{
|
{
|
||||||
return { *derivedPathWithInfo };
|
return { *derivedPathWithInfo };
|
||||||
} else {
|
} else {
|
||||||
@@ -109,19 +94,19 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|||||||
"expected flake output attribute '%s' to be a derivation or path but found %s: %s",
|
"expected flake output attribute '%s' to be a derivation or path but found %s: %s",
|
||||||
attrPath,
|
attrPath,
|
||||||
showType(v),
|
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;
|
std::optional<NixInt::Inner> priority;
|
||||||
|
|
||||||
if (attr->maybeGetAttr(state->sOutputSpecified)) {
|
if (attr->maybeGetAttr(state, "outputSpecified")) {
|
||||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
} else if (auto aMeta = attr->maybeGetAttr(state, "meta")) {
|
||||||
if (auto aPriority = aMeta->maybeGetAttr("priority"))
|
if (auto aPriority = aMeta->maybeGetAttr(state, "priority"))
|
||||||
priority = aPriority->getInt().value;
|
priority = aPriority->getInt(state).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {{
|
return {{
|
||||||
@@ -130,14 +115,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|||||||
.outputs = std::visit(overloaded {
|
.outputs = std::visit(overloaded {
|
||||||
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
|
||||||
std::set<std::string> outputsToInstall;
|
std::set<std::string> outputsToInstall;
|
||||||
if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
|
if (auto aOutputSpecified = attr->maybeGetAttr(state, "outputSpecified")) {
|
||||||
if (aOutputSpecified->getBool()) {
|
if (aOutputSpecified->getBool(state)) {
|
||||||
if (auto aOutputName = attr->maybeGetAttr("outputName"))
|
if (auto aOutputName = attr->maybeGetAttr(state, "outputName"))
|
||||||
outputsToInstall = { aOutputName->getString() };
|
outputsToInstall = { aOutputName->getString(state) };
|
||||||
}
|
}
|
||||||
} else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
|
} else if (auto aMeta = attr->maybeGetAttr(state, "meta")) {
|
||||||
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
|
if (auto aOutputsToInstall = aMeta->maybeGetAttr(state, "outputsToInstall"))
|
||||||
for (auto & s : aOutputsToInstall->getListOfStrings())
|
for (auto & s : aOutputsToInstall->getListOfStrings(state))
|
||||||
outputsToInstall.insert(s);
|
outputsToInstall.insert(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,20 +144,20 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|||||||
},
|
},
|
||||||
ExtraPathInfoFlake::Flake {
|
ExtraPathInfoFlake::Flake {
|
||||||
.originalRef = flakeRef,
|
.originalRef = flakeRef,
|
||||||
.lockedRef = getLockedFlake()->flake.lockedRef,
|
.lockedRef = getLockedFlake(state)->flake.lockedRef,
|
||||||
}),
|
}),
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
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>>
|
std::vector<ref<eval_cache::AttrCursor>>
|
||||||
InstallableFlake::getCursors(EvalState & state)
|
InstallableFlake::getCursors(EvalState & state)
|
||||||
{
|
{
|
||||||
auto evalCache = openEvalCache(state, getLockedFlake());
|
auto evalCache = openEvalCache(*evaluator, getLockedFlake(state));
|
||||||
|
|
||||||
auto root = evalCache->getRoot();
|
auto root = evalCache->getRoot();
|
||||||
|
|
||||||
@@ -184,7 +169,7 @@ InstallableFlake::getCursors(EvalState & state)
|
|||||||
for (auto & attrPath : attrPaths) {
|
for (auto & attrPath : attrPaths) {
|
||||||
debug("trying flake output attribute '%s'", attrPath);
|
debug("trying flake output attribute '%s'", attrPath);
|
||||||
|
|
||||||
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
auto attr = root->findAlongAttrPath(state, parseAttrPath(attrPath));
|
||||||
if (attr) {
|
if (attr) {
|
||||||
res.push_back(ref(*attr));
|
res.push_back(ref(*attr));
|
||||||
} else {
|
} else {
|
||||||
@@ -202,20 +187,20 @@ InstallableFlake::getCursors(EvalState & state)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake(EvalState & state) const
|
||||||
{
|
{
|
||||||
if (!_lockedFlake) {
|
if (!_lockedFlake) {
|
||||||
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
||||||
// FIXME why this side effect?
|
// FIXME why this side effect?
|
||||||
lockFlagsApplyConfig.applyNixConfig = true;
|
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;
|
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 nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
|
||||||
if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
|
if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "installable-value.hh"
|
#include "lix/libcmd/installable-value.hh"
|
||||||
|
#include "lix/libexpr/eval.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ struct InstallableFlake : InstallableValue
|
|||||||
|
|
||||||
InstallableFlake(
|
InstallableFlake(
|
||||||
SourceExprCommand * cmd,
|
SourceExprCommand * cmd,
|
||||||
ref<EvalState> state,
|
ref<eval_cache::CachingEvaluator> state,
|
||||||
FlakeRef && flakeRef,
|
FlakeRef && flakeRef,
|
||||||
std::string_view fragment,
|
std::string_view fragment,
|
||||||
ExtendedOutputsSpec extendedOutputsSpec,
|
ExtendedOutputsSpec extendedOutputsSpec,
|
||||||
@@ -52,9 +53,7 @@ struct InstallableFlake : InstallableValue
|
|||||||
|
|
||||||
std::vector<std::string> getActualAttrPaths();
|
std::vector<std::string> getActualAttrPaths();
|
||||||
|
|
||||||
Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
|
DerivedPathsWithInfo toDerivedPaths(EvalState & state) override;
|
||||||
|
|
||||||
DerivedPathsWithInfo toDerivedPaths() override;
|
|
||||||
|
|
||||||
std::pair<Value *, PosIdx> toValue(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
|
* Get a cursor to every attrpath in getActualAttrPaths() that
|
||||||
* exists. However if none exists, throw an exception.
|
* exists. However if none exists, throw an exception.
|
||||||
*/
|
*/
|
||||||
std::vector<ref<eval_cache::AttrCursor>>
|
std::vector<ref<eval_cache::AttrCursor>> getCursors(EvalState & state) override;
|
||||||
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(
|
ref<eval_cache::EvalCache> openEvalCache(
|
||||||
EvalState & state,
|
eval_cache::CachingEvaluator & state,
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
std::shared_ptr<flake::LockedFlake> lockedFlake);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "installable-value.hh"
|
#include "lix/libcmd/installable-value.hh"
|
||||||
#include "eval-cache.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "fetch-to-store.hh"
|
#include "lix/libfetchers/fetch-to-store.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -8,8 +8,8 @@ std::vector<ref<eval_cache::AttrCursor>>
|
|||||||
InstallableValue::getCursors(EvalState & state)
|
InstallableValue::getCursors(EvalState & state)
|
||||||
{
|
{
|
||||||
auto evalCache =
|
auto evalCache =
|
||||||
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
|
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt,
|
||||||
[&]() { return toValue(state).first; });
|
[&](EvalState & state) { return toValue(state).first; });
|
||||||
return {evalCache->getRoot()};
|
return {evalCache->getRoot()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,10 +42,12 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
|
|||||||
return ref { castedInstallable };
|
return ref { castedInstallable };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
|
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(
|
||||||
|
EvalState & state, Value & v, const PosIdx pos, std::string_view errorCtx
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (v.type() == nPath) {
|
if (v.type() == nPath) {
|
||||||
auto storePath = fetchToStore(*state->store, v.path());
|
auto storePath = fetchToStore(*evaluator->store, state.ctx.paths.checkSourcePath(v.path()));
|
||||||
return {{
|
return {{
|
||||||
.path = DerivedPath::Opaque {
|
.path = DerivedPath::Opaque {
|
||||||
.path = std::move(storePath),
|
.path = std::move(storePath),
|
||||||
@@ -57,7 +59,7 @@ std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths
|
|||||||
else if (v.type() == nString) {
|
else if (v.type() == nString) {
|
||||||
return {{
|
return {{
|
||||||
.path = DerivedPath::fromSingle(
|
.path = DerivedPath::fromSingle(
|
||||||
state->coerceToSingleDerivedPath(pos, v, errorCtx)),
|
state.coerceToSingleDerivedPath(pos, v, errorCtx)),
|
||||||
.info = make_ref<ExtraPathInfo>(),
|
.info = make_ref<ExtraPathInfo>(),
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "installables.hh"
|
#include "lix/libcmd/installables.hh"
|
||||||
#include "flake/flake.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
|
#include "lix/libexpr/eval.hh"
|
||||||
|
#include "lix/libexpr/flake/flake.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct DrvInfo;
|
struct DrvInfo;
|
||||||
struct SourceExprCommand;
|
struct SourceExprCommand;
|
||||||
|
|
||||||
namespace eval_cache { class EvalCache; class AttrCursor; }
|
|
||||||
|
|
||||||
struct App
|
struct App
|
||||||
{
|
{
|
||||||
std::vector<DerivedPath> context;
|
std::vector<DerivedPath> context;
|
||||||
@@ -21,7 +21,7 @@ struct App
|
|||||||
struct UnresolvedApp
|
struct UnresolvedApp
|
||||||
{
|
{
|
||||||
App unresolved;
|
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
|
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() { }
|
virtual ~InstallableValue() { }
|
||||||
|
|
||||||
@@ -84,15 +84,13 @@ struct InstallableValue : Installable
|
|||||||
* However if none exists, throw exception instead of returning
|
* However if none exists, throw exception instead of returning
|
||||||
* empty vector.
|
* empty vector.
|
||||||
*/
|
*/
|
||||||
virtual std::vector<ref<eval_cache::AttrCursor>>
|
virtual std::vector<ref<eval_cache::AttrCursor>> getCursors(EvalState & state);
|
||||||
getCursors(EvalState & state);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first and most preferred cursor this Installable could
|
* Get the first and most preferred cursor this Installable could
|
||||||
* refer to, or throw an exception if none exists.
|
* refer to, or throw an exception if none exists.
|
||||||
*/
|
*/
|
||||||
virtual ref<eval_cache::AttrCursor>
|
virtual ref<eval_cache::AttrCursor> getCursor(EvalState & state);
|
||||||
getCursor(EvalState & state);
|
|
||||||
|
|
||||||
UnresolvedApp toApp(EvalState & state);
|
UnresolvedApp toApp(EvalState & state);
|
||||||
|
|
||||||
@@ -115,7 +113,9 @@ protected:
|
|||||||
* @result A derived path (with empty info, for now) if the value
|
* @result A derived path (with empty info, for now) if the value
|
||||||
* matched the above criteria.
|
* 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 "lix/libstore/globals.hh"
|
||||||
#include "installables.hh"
|
#include "lix/libcmd/installables.hh"
|
||||||
#include "installable-derived-path.hh"
|
#include "lix/libcmd/installable-derived-path.hh"
|
||||||
#include "installable-attr-path.hh"
|
#include "lix/libcmd/installable-attr-path.hh"
|
||||||
#include "installable-flake.hh"
|
#include "lix/libcmd/installable-flake.hh"
|
||||||
#include "logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "lix/libstore/outputs-spec.hh"
|
||||||
#include "command.hh"
|
#include "lix/libcmd/command.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "eval-settings.hh"
|
#include "lix/libexpr/eval-settings.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "flake/flake.hh"
|
#include "lix/libexpr/flake/flake.hh"
|
||||||
#include "eval-cache.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "registry.hh"
|
#include "lix/libfetchers/registry.hh"
|
||||||
#include "build-result.hh"
|
#include "lix/libstore/build-result.hh"
|
||||||
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
@@ -25,12 +25,12 @@ namespace nix {
|
|||||||
|
|
||||||
void completeFlakeInputPath(
|
void completeFlakeInputPath(
|
||||||
AddCompletions & completions,
|
AddCompletions & completions,
|
||||||
ref<EvalState> evalState,
|
EvalState & evalState,
|
||||||
const std::vector<FlakeRef> & flakeRefs,
|
const std::vector<FlakeRef> & flakeRefs,
|
||||||
std::string_view prefix)
|
std::string_view prefix)
|
||||||
{
|
{
|
||||||
for (auto & flakeRef : flakeRefs) {
|
for (auto & flakeRef : flakeRefs) {
|
||||||
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
auto flake = flake::getFlake(evalState, flakeRef, true);
|
||||||
for (auto & input : flake.inputs)
|
for (auto & input : flake.inputs)
|
||||||
if (input.first.starts_with(prefix))
|
if (input.first.starts_with(prefix))
|
||||||
completions.add(input.first);
|
completions.add(input.first);
|
||||||
@@ -86,9 +86,9 @@ MixFlakeOptions::MixFlakeOptions()
|
|||||||
}},
|
}},
|
||||||
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
|
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
|
completeFlakeInputPath(completions, *getEvaluator()->begin(), getFlakeRefsForCompletion(), prefix);
|
||||||
} else if (n == 1) {
|
} else if (n == 1) {
|
||||||
completeFlakeRef(completions, getEvalState()->store, prefix);
|
completeFlakeRef(completions, getEvaluator()->store, prefix);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
@@ -121,7 +121,7 @@ MixFlakeOptions::MixFlakeOptions()
|
|||||||
.category = category,
|
.category = category,
|
||||||
.labels = {"flake-url"},
|
.labels = {"flake-url"},
|
||||||
.handler = {[&](std::string flakeRef) {
|
.handler = {[&](std::string flakeRef) {
|
||||||
auto evalState = getEvalState();
|
auto evalState = getEvaluator()->begin();
|
||||||
auto flake = flake::lockFlake(
|
auto flake = flake::lockFlake(
|
||||||
*evalState,
|
*evalState,
|
||||||
parseFlakeRef(flakeRef, absPath(".")),
|
parseFlakeRef(flakeRef, absPath(".")),
|
||||||
@@ -137,7 +137,7 @@ MixFlakeOptions::MixFlakeOptions()
|
|||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
.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()
|
Args::CompleterClosure SourceExprCommand::getCompleteInstallable()
|
||||||
{
|
{
|
||||||
return [this](AddCompletions & completions, size_t, std::string_view prefix) {
|
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 {
|
try {
|
||||||
if (file) {
|
if (file) {
|
||||||
completions.setType(AddCompletions::Type::Attrs);
|
completions.setType(AddCompletions::Type::Attrs);
|
||||||
|
|
||||||
evalSettings.pureEval = false;
|
auto evaluator = getEvaluator();
|
||||||
auto state = getEvalState();
|
|
||||||
Expr & e = state->parseExprFromFile(
|
Expr & e = evaluator->parseExprFromFile(
|
||||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
state.ctx.paths.resolveExprPath(lookupFileArg(*evaluator, *file))
|
||||||
);
|
);
|
||||||
|
|
||||||
Value root;
|
Value root;
|
||||||
state->eval(e, root);
|
state.eval(e, root);
|
||||||
|
|
||||||
auto autoArgs = getAutoArgs(*state);
|
auto autoArgs = getAutoArgs(*evaluator);
|
||||||
|
|
||||||
std::string prefix_ = std::string(prefix);
|
std::string prefix_ = std::string(prefix);
|
||||||
auto sep = prefix_.rfind('.');
|
auto sep = prefix_.rfind('.');
|
||||||
@@ -234,15 +234,15 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
|||||||
prefix_ = "";
|
prefix_ = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root);
|
auto [v, pos] = findAlongAttrPath(state, prefix_, *autoArgs, root);
|
||||||
Value &v1(*v);
|
Value &v1(*v);
|
||||||
state->forceValue(v1, pos);
|
state.forceValue(v1, pos);
|
||||||
Value v2;
|
Value v2;
|
||||||
state->autoCallFunction(*autoArgs, v1, v2);
|
state.autoCallFunction(*autoArgs, v1, v2);
|
||||||
|
|
||||||
if (v2.type() == nAttrs) {
|
if (v2.type() == nAttrs) {
|
||||||
for (auto & i : *v2.attrs) {
|
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 (name.find(searchWord) == 0) {
|
||||||
if (prefix_ == "")
|
if (prefix_ == "")
|
||||||
completions.add(name);
|
completions.add(name);
|
||||||
@@ -254,7 +254,8 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
|||||||
} else {
|
} else {
|
||||||
completeFlakeRefWithFragment(
|
completeFlakeRefWithFragment(
|
||||||
completions,
|
completions,
|
||||||
getEvalState(),
|
state,
|
||||||
|
getEvaluator(),
|
||||||
lockFlags,
|
lockFlags,
|
||||||
getDefaultFlakeAttrPathPrefixes(),
|
getDefaultFlakeAttrPathPrefixes(),
|
||||||
getDefaultFlakeAttrPaths(),
|
getDefaultFlakeAttrPaths(),
|
||||||
@@ -267,7 +268,8 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
|||||||
|
|
||||||
void completeFlakeRefWithFragment(
|
void completeFlakeRefWithFragment(
|
||||||
AddCompletions & completions,
|
AddCompletions & completions,
|
||||||
ref<EvalState> evalState,
|
EvalState & evalState,
|
||||||
|
ref<eval_cache::CachingEvaluator> evaluator,
|
||||||
flake::LockFlags lockFlags,
|
flake::LockFlags lockFlags,
|
||||||
Strings attrPathPrefixes,
|
Strings attrPathPrefixes,
|
||||||
const Strings & defaultFlakeAttrPaths,
|
const Strings & defaultFlakeAttrPaths,
|
||||||
@@ -278,7 +280,7 @@ void completeFlakeRefWithFragment(
|
|||||||
try {
|
try {
|
||||||
auto hash = prefix.find('#');
|
auto hash = prefix.find('#');
|
||||||
if (hash == std::string::npos) {
|
if (hash == std::string::npos) {
|
||||||
completeFlakeRef(completions, evalState->store, prefix);
|
completeFlakeRef(completions, evaluator->store, prefix);
|
||||||
} else {
|
} else {
|
||||||
completions.setType(AddCompletions::Type::Attrs);
|
completions.setType(AddCompletions::Type::Attrs);
|
||||||
|
|
||||||
@@ -291,8 +293,10 @@ void completeFlakeRefWithFragment(
|
|||||||
auto flakeRefS = std::string(prefix.substr(0, hash));
|
auto flakeRefS = std::string(prefix.substr(0, hash));
|
||||||
auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath("."));
|
auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath("."));
|
||||||
|
|
||||||
auto evalCache = openEvalCache(*evalState,
|
auto evalCache = openEvalCache(
|
||||||
std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags)));
|
*evaluator,
|
||||||
|
std::make_shared<flake::LockedFlake>(lockFlake(evalState, flakeRef, lockFlags))
|
||||||
|
);
|
||||||
|
|
||||||
auto root = evalCache->getRoot();
|
auto root = evalCache->getRoot();
|
||||||
|
|
||||||
@@ -305,25 +309,25 @@ void completeFlakeRefWithFragment(
|
|||||||
attrPathPrefixes.push_back("");
|
attrPathPrefixes.push_back("");
|
||||||
|
|
||||||
for (auto & attrPathPrefixS : attrPathPrefixes) {
|
for (auto & attrPathPrefixS : attrPathPrefixes) {
|
||||||
auto attrPathPrefix = parseAttrPath(*evalState, attrPathPrefixS);
|
auto attrPathPrefix = parseAttrPath(attrPathPrefixS);
|
||||||
auto attrPathS = attrPathPrefixS + std::string(fragment);
|
auto attrPathS = attrPathPrefixS + std::string(fragment);
|
||||||
auto attrPath = parseAttrPath(*evalState, attrPathS);
|
auto attrPath = parseAttrPath(attrPathS);
|
||||||
|
|
||||||
std::string lastAttr;
|
std::string lastAttr;
|
||||||
if (!attrPath.empty() && !attrPathS.ends_with(".")) {
|
if (!attrPath.empty() && !attrPathS.ends_with(".")) {
|
||||||
lastAttr = evalState->symbols[attrPath.back()];
|
lastAttr = attrPath.back();
|
||||||
attrPath.pop_back();
|
attrPath.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attr = root->findAlongAttrPath(attrPath);
|
auto attr = root->findAlongAttrPath(evalState, attrPath);
|
||||||
if (!attr) continue;
|
if (!attr) continue;
|
||||||
|
|
||||||
for (auto & attr2 : (*attr)->getAttrs()) {
|
for (auto & attr2 : (*attr)->getAttrs(evalState)) {
|
||||||
if (std::string_view(evalState->symbols[attr2]).starts_with(lastAttr)) {
|
if (std::string_view attr2s = attr2; attr2s.starts_with(lastAttr)) {
|
||||||
auto attrPath2 = (*attr)->getAttrPath(attr2);
|
auto attrPath2 = (*attr)->getAttrPath(evalState, attr2s);
|
||||||
/* Strip the attrpath prefix. */
|
/* Strip the attrpath prefix. */
|
||||||
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
|
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. */
|
attrpaths. */
|
||||||
if (fragment.empty()) {
|
if (fragment.empty()) {
|
||||||
for (auto & attrPath : defaultFlakeAttrPaths) {
|
for (auto & attrPath : defaultFlakeAttrPaths) {
|
||||||
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
|
auto attr = root->findAlongAttrPath(evalState, parseAttrPath(attrPath));
|
||||||
if (!attr) continue;
|
if (!attr) continue;
|
||||||
completions.add(flakeRefS + "#" + prefixRoot);
|
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)
|
if (buildables.size() != 1)
|
||||||
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
|
throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
|
||||||
return std::move(buildables[0]);
|
return std::move(buildables[0]);
|
||||||
@@ -390,43 +394,49 @@ static StorePath getDeriver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref<eval_cache::EvalCache> openEvalCache(
|
ref<eval_cache::EvalCache> openEvalCache(
|
||||||
EvalState & state,
|
eval_cache::CachingEvaluator & state,
|
||||||
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
std::shared_ptr<flake::LockedFlake> lockedFlake)
|
||||||
{
|
{
|
||||||
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
||||||
? std::make_optional(lockedFlake->getFingerprint())
|
? std::make_optional(lockedFlake->getFingerprint())
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
auto rootLoader = [&state, lockedFlake]()
|
auto rootLoader = [lockedFlake](EvalState & state)
|
||||||
{
|
{
|
||||||
/* For testing whether the evaluation cache is
|
/* For testing whether the evaluation cache is
|
||||||
complete. */
|
complete. */
|
||||||
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
|
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
|
||||||
throw Error("not everything is cached, but evaluation is not allowed");
|
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);
|
flake::callFlake(state, *lockedFlake, *vFlake);
|
||||||
|
|
||||||
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
||||||
|
|
||||||
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
|
auto aOutputs = vFlake->attrs->get(state.ctx.symbols.create("outputs"));
|
||||||
assert(aOutputs);
|
assert(aOutputs);
|
||||||
|
|
||||||
return aOutputs->value;
|
return aOutputs->value;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fingerprint) {
|
if (fingerprint) {
|
||||||
auto search = state.evalCaches.find(fingerprint.value());
|
return state.getCacheFor(fingerprint.value(), rootLoader);
|
||||||
if (search == state.evalCaches.end()) {
|
|
||||||
search = state.evalCaches.emplace(fingerprint.value(), make_ref<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader)).first;
|
|
||||||
}
|
|
||||||
return search->second;
|
|
||||||
} else {
|
} 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(
|
Installables SourceExprCommand::parseInstallables(
|
||||||
ref<Store> store, std::vector<std::string> ss)
|
EvalState & state, ref<Store> store, std::vector<std::string> ss)
|
||||||
{
|
{
|
||||||
Installables result;
|
Installables result;
|
||||||
|
|
||||||
@@ -434,21 +444,18 @@ Installables SourceExprCommand::parseInstallables(
|
|||||||
if (file && expr)
|
if (file && expr)
|
||||||
throw UsageError("'--file' and '--expr' are exclusive");
|
throw UsageError("'--file' and '--expr' are exclusive");
|
||||||
|
|
||||||
// FIXME: backward compatibility hack
|
auto evaluator = getEvaluator();
|
||||||
if (file) evalSettings.pureEval = false;
|
auto vFile = evaluator->mem.allocValue();
|
||||||
|
|
||||||
auto state = getEvalState();
|
|
||||||
auto vFile = state->allocValue();
|
|
||||||
|
|
||||||
if (file == "-") {
|
if (file == "-") {
|
||||||
auto & e = state->parseStdin();
|
auto & e = evaluator->parseStdin();
|
||||||
state->eval(e, *vFile);
|
state.eval(e, *vFile);
|
||||||
}
|
}
|
||||||
else if (file)
|
else if (file)
|
||||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
state.evalFile(lookupFileArg(*evaluator, *file), *vFile);
|
||||||
else {
|
else {
|
||||||
auto & e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
|
auto & e = evaluator->parseExprFromString(*expr, CanonPath::fromCwd());
|
||||||
state->eval(e, *vFile);
|
state.eval(e, *vFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & s : ss) {
|
for (auto & s : ss) {
|
||||||
@@ -456,7 +463,7 @@ Installables SourceExprCommand::parseInstallables(
|
|||||||
result.push_back(
|
result.push_back(
|
||||||
make_ref<InstallableAttrPath>(
|
make_ref<InstallableAttrPath>(
|
||||||
InstallableAttrPath::parse(
|
InstallableAttrPath::parse(
|
||||||
state, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
|
evaluator, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec))));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -485,7 +492,7 @@ Installables SourceExprCommand::parseInstallables(
|
|||||||
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath("."));
|
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath("."));
|
||||||
result.push_back(make_ref<InstallableFlake>(
|
result.push_back(make_ref<InstallableFlake>(
|
||||||
this,
|
this,
|
||||||
getEvalState(),
|
getEvaluator(),
|
||||||
std::move(flakeRef),
|
std::move(flakeRef),
|
||||||
fragment,
|
fragment,
|
||||||
std::move(extendedOutputsSpec),
|
std::move(extendedOutputsSpec),
|
||||||
@@ -505,9 +512,9 @@ Installables SourceExprCommand::parseInstallables(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref<Installable> SourceExprCommand::parseInstallable(
|
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);
|
assert(installables.size() == 1);
|
||||||
return installables.front();
|
return installables.front();
|
||||||
}
|
}
|
||||||
@@ -537,6 +544,7 @@ static SingleBuiltPath getBuiltPath(ref<Store> evalStore, ref<Store> store, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BuiltPathWithResult> Installable::build(
|
std::vector<BuiltPathWithResult> Installable::build(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -544,7 +552,7 @@ std::vector<BuiltPathWithResult> Installable::build(
|
|||||||
BuildMode bMode)
|
BuildMode bMode)
|
||||||
{
|
{
|
||||||
std::vector<BuiltPathWithResult> res;
|
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);
|
res.push_back(builtPathWithResult);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -581,6 +589,7 @@ static void throwBuildErrors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
|
std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -600,7 +609,7 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
|
|||||||
std::map<DerivedPath, std::vector<Aux>> backmap;
|
std::map<DerivedPath, std::vector<Aux>> backmap;
|
||||||
|
|
||||||
for (auto & i : installables) {
|
for (auto & i : installables) {
|
||||||
for (auto b : i->toDerivedPaths()) {
|
for (auto b : i->toDerivedPaths(state)) {
|
||||||
pathsToBuild.push_back(b.path);
|
pathsToBuild.push_back(b.path);
|
||||||
backmap[b.path].push_back({.info = b.info, .installable = i});
|
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(
|
BuiltPaths Installable::toBuiltPaths(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -687,7 +697,7 @@ BuiltPaths Installable::toBuiltPaths(
|
|||||||
{
|
{
|
||||||
if (operateOn == OperateOn::Output) {
|
if (operateOn == OperateOn::Output) {
|
||||||
BuiltPaths res;
|
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);
|
res.push_back(p.path);
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
@@ -695,20 +705,21 @@ BuiltPaths Installable::toBuiltPaths(
|
|||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
BuiltPaths res;
|
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});
|
res.emplace_back(BuiltPath::Opaque{drvPath});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StorePathSet Installable::toStorePathSet(
|
StorePathSet Installable::toStorePathSet(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode, OperateOn operateOn,
|
Realise mode, OperateOn operateOn,
|
||||||
const Installables & installables)
|
const Installables & installables)
|
||||||
{
|
{
|
||||||
StorePathSet outPaths;
|
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();
|
auto thisOutPaths = path.outPaths();
|
||||||
outPaths.insert(thisOutPaths.begin(), thisOutPaths.end());
|
outPaths.insert(thisOutPaths.begin(), thisOutPaths.end());
|
||||||
}
|
}
|
||||||
@@ -716,13 +727,14 @@ StorePathSet Installable::toStorePathSet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
StorePaths Installable::toStorePaths(
|
StorePaths Installable::toStorePaths(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode, OperateOn operateOn,
|
Realise mode, OperateOn operateOn,
|
||||||
const Installables & installables)
|
const Installables & installables)
|
||||||
{
|
{
|
||||||
StorePaths outPaths;
|
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();
|
auto thisOutPaths = path.outPaths();
|
||||||
outPaths.insert(outPaths.end(), thisOutPaths.begin(), thisOutPaths.end());
|
outPaths.insert(outPaths.end(), thisOutPaths.begin(), thisOutPaths.end());
|
||||||
}
|
}
|
||||||
@@ -730,12 +742,13 @@ StorePaths Installable::toStorePaths(
|
|||||||
}
|
}
|
||||||
|
|
||||||
StorePath Installable::toStorePath(
|
StorePath Installable::toStorePath(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode, OperateOn operateOn,
|
Realise mode, OperateOn operateOn,
|
||||||
ref<Installable> installable)
|
ref<Installable> installable)
|
||||||
{
|
{
|
||||||
auto paths = toStorePathSet(evalStore, store, mode, operateOn, {installable});
|
auto paths = toStorePathSet(state, evalStore, store, mode, operateOn, {installable});
|
||||||
|
|
||||||
if (paths.size() != 1)
|
if (paths.size() != 1)
|
||||||
throw Error("argument '%s' should evaluate to one store path", installable->what());
|
throw Error("argument '%s' should evaluate to one store path", installable->what());
|
||||||
@@ -744,6 +757,7 @@ StorePath Installable::toStorePath(
|
|||||||
}
|
}
|
||||||
|
|
||||||
StorePathSet Installable::toDerivations(
|
StorePathSet Installable::toDerivations(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const Installables & installables,
|
const Installables & installables,
|
||||||
bool useDeriver)
|
bool useDeriver)
|
||||||
@@ -751,7 +765,7 @@ StorePathSet Installable::toDerivations(
|
|||||||
StorePathSet drvPaths;
|
StorePathSet drvPaths;
|
||||||
|
|
||||||
for (const auto & i : installables)
|
for (const auto & i : installables)
|
||||||
for (const auto & b : i->toDerivedPaths())
|
for (const auto & b : i->toDerivedPaths(state))
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](const DerivedPath::Opaque & bo) {
|
[&](const DerivedPath::Opaque & bo) {
|
||||||
drvPaths.insert(
|
drvPaths.insert(
|
||||||
@@ -828,7 +842,7 @@ std::vector<FlakeRef> InstallableCommand::getFlakeRefsForCompletion()
|
|||||||
|
|
||||||
void InstallablesCommand::run(ref<Store> store, std::vector<std::string> && rawInstallables)
|
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));
|
run(store, std::move(installables));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,7 +859,7 @@ InstallableCommand::InstallableCommand()
|
|||||||
|
|
||||||
void InstallableCommand::run(ref<Store> store)
|
void InstallableCommand::run(ref<Store> store)
|
||||||
{
|
{
|
||||||
auto installable = parseInstallable(store, _installable);
|
auto installable = parseInstallable(*getEvaluator()->begin(), store, _installable);
|
||||||
run(store, std::move(installable));
|
run(store, std::move(installable));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "path.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "outputs-spec.hh"
|
#include "lix/libstore/path.hh"
|
||||||
#include "derived-path.hh"
|
#include "lix/libstore/outputs-spec.hh"
|
||||||
#include "built-path.hh"
|
#include "lix/libstore/derived-path.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libcmd/built-path.hh"
|
||||||
#include "build-result.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
|
#include "lix/libstore/build-result.hh"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ struct Installable
|
|||||||
*
|
*
|
||||||
* This is the main method of this class
|
* 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
|
* 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,
|
* If no or multiple \ref DerivedPath "derived paths" are produced,
|
||||||
* and error is raised.
|
* and error is raised.
|
||||||
*/
|
*/
|
||||||
DerivedPathWithInfo toDerivedPath();
|
DerivedPathWithInfo toDerivedPath(EvalState & state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a value only if this installable is a store path or a
|
* Return a value only if this installable is a store path or a
|
||||||
@@ -152,6 +153,7 @@ struct Installable
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<BuiltPathWithResult> build(
|
static std::vector<BuiltPathWithResult> build(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -159,6 +161,7 @@ struct Installable
|
|||||||
BuildMode bMode = bmNormal);
|
BuildMode bMode = bmNormal);
|
||||||
|
|
||||||
static std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> build2(
|
static std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> build2(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -166,6 +169,7 @@ struct Installable
|
|||||||
BuildMode bMode = bmNormal);
|
BuildMode bMode = bmNormal);
|
||||||
|
|
||||||
static std::set<StorePath> toStorePathSet(
|
static std::set<StorePath> toStorePathSet(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -173,6 +177,7 @@ struct Installable
|
|||||||
const Installables & installables);
|
const Installables & installables);
|
||||||
|
|
||||||
static std::vector<StorePath> toStorePaths(
|
static std::vector<StorePath> toStorePaths(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -180,6 +185,7 @@ struct Installable
|
|||||||
const Installables & installables);
|
const Installables & installables);
|
||||||
|
|
||||||
static StorePath toStorePath(
|
static StorePath toStorePath(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -187,11 +193,13 @@ struct Installable
|
|||||||
ref<Installable> installable);
|
ref<Installable> installable);
|
||||||
|
|
||||||
static std::set<StorePath> toDerivations(
|
static std::set<StorePath> toDerivations(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const Installables & installables,
|
const Installables & installables,
|
||||||
bool useDeriver = false);
|
bool useDeriver = false);
|
||||||
|
|
||||||
static BuiltPaths toBuiltPaths(
|
static BuiltPaths toBuiltPaths(
|
||||||
|
EvalState & state,
|
||||||
ref<Store> evalStore,
|
ref<Store> evalStore,
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
Realise mode,
|
Realise mode,
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "lix/libcmd/legacy.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
LegacyCommands::Commands * LegacyCommands::commands = 0;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,19 +2,20 @@
|
|||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace nix {
|
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;
|
typedef std::map<std::string, MainFunction> Commands;
|
||||||
static Commands * 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;
|
if (!commands) commands = new Commands;
|
||||||
(*commands)[name] = fun;
|
(*commands)[name] = fun;
|
||||||
@@ -7,4 +7,3 @@ Description: Lix Package Manager (libcmd)
|
|||||||
Version: @PACKAGE_VERSION@
|
Version: @PACKAGE_VERSION@
|
||||||
Requires: lix-base lix-util
|
Requires: lix-base lix-util
|
||||||
Libs: -L${libdir} -llixcmd
|
Libs: -L${libdir} -llixcmd
|
||||||
Cflags: -I${includedir}/lix/libcmd
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "markdown.hh"
|
#include "lix/libcmd/markdown.hh"
|
||||||
#include "error.hh"
|
#include "lix/libutil/error.hh"
|
||||||
#include "finally.hh"
|
#include "lix/libutil/finally.hh"
|
||||||
#include "terminal.hh"
|
#include "lix/libutil/terminal.hh"
|
||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <lowdown.h>
|
#include <lowdown.h>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "types.hh"
|
#include "lix/libutil/types.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -47,11 +47,14 @@ libcmd = library(
|
|||||||
liblixfetchers,
|
liblixfetchers,
|
||||||
liblixmain,
|
liblixmain,
|
||||||
boehm,
|
boehm,
|
||||||
|
ncurses,
|
||||||
editline,
|
editline,
|
||||||
lowdown,
|
lowdown,
|
||||||
nlohmann_json,
|
nlohmann_json,
|
||||||
lix_doc
|
liblix_doc,
|
||||||
],
|
],
|
||||||
|
# '../..' for self references like "lix/libcmd/*.hh"
|
||||||
|
include_directories : [ '../..' ],
|
||||||
cpp_pch : cpp_pch,
|
cpp_pch : cpp_pch,
|
||||||
install : true,
|
install : true,
|
||||||
# FIXME(Qyriad): is this right?
|
# FIXME(Qyriad): is this right?
|
||||||
@@ -68,7 +71,7 @@ custom_target(
|
|||||||
)
|
)
|
||||||
|
|
||||||
liblixcmd = declare_dependency(
|
liblixcmd = declare_dependency(
|
||||||
include_directories : '.',
|
include_directories : include_directories('../..'),
|
||||||
link_with : libcmd,
|
link_with : libcmd,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "error.hh"
|
#include "lix/libutil/error.hh"
|
||||||
#include "file-system.hh"
|
#include "lix/libutil/file-system.hh"
|
||||||
#include "logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -8,10 +8,6 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <cerrno>
|
#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
|
// editline < 1.15.2 don't wrap their API for C++ usage
|
||||||
// (added in https://github.com/troglobit/editline/commit/91398ceb3427b730995357e9d120539fb9bb7461).
|
// (added in https://github.com/troglobit/editline/commit/91398ceb3427b730995357e9d120539fb9bb7461).
|
||||||
// This results in linker errors due to to name-mangling of editline C symbols.
|
// This results in linker errors due to to name-mangling of editline C symbols.
|
||||||
@@ -20,10 +16,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include <editline.h>
|
#include <editline.h>
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "finally.hh"
|
#include "lix/libutil/finally.hh"
|
||||||
#include "repl-interacter.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libcmd/repl-interacter.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
@@ -35,52 +31,14 @@ void sigintHandler(int signo)
|
|||||||
{
|
{
|
||||||
g_signal_received = signo;
|
g_signal_received = signo;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
static detail::ReplCompleterMixin * curRepl; // ugly
|
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;
|
int ac = 0;
|
||||||
char ** vp = nullptr;
|
char ** vp = nullptr;
|
||||||
|
|
||||||
@@ -95,15 +53,95 @@ static int listPossibleCallback(char * s, char *** avp)
|
|||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
|
|
||||||
vp = check(static_cast<char **>(malloc(possible.size() * sizeof(char *))));
|
vp = check(static_cast<char **>(malloc(possible.size() * sizeof(char *))));
|
||||||
|
|
||||||
for (auto & p : possible)
|
for (auto & p : possible)
|
||||||
vp[ac++] = check(strdup(p.c_str()));
|
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)
|
ReadlineLikeInteracter::Guard ReadlineLikeInteracter::init(detail::ReplCompleterMixin * repl)
|
||||||
@@ -115,17 +153,15 @@ ReadlineLikeInteracter::Guard ReadlineLikeInteracter::init(detail::ReplCompleter
|
|||||||
} catch (SysError & e) {
|
} catch (SysError & e) {
|
||||||
logWarning(e.info());
|
logWarning(e.info());
|
||||||
}
|
}
|
||||||
#ifndef READLINE
|
|
||||||
el_hist_size = 1000;
|
el_hist_size = 1000;
|
||||||
#endif
|
|
||||||
read_history(historyFile.c_str());
|
read_history(historyFile.c_str());
|
||||||
auto oldRepl = curRepl;
|
auto oldRepl = curRepl;
|
||||||
curRepl = repl;
|
curRepl = repl;
|
||||||
Guard restoreRepl([oldRepl] { curRepl = oldRepl; });
|
Guard restoreRepl([oldRepl] { curRepl = oldRepl; });
|
||||||
#ifndef READLINE
|
// editline does its own escaping of completions, so we rebind tab
|
||||||
rl_set_complete_func(completionCallback);
|
// to our own completion function to skip that and do nix escaping
|
||||||
rl_set_list_possib_func(listPossibleCallback);
|
// instead of shell escaping.
|
||||||
#endif
|
el_bind_key(CTL('I'), doCompletion);
|
||||||
return restoreRepl;
|
return restoreRepl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
/// @file
|
/// @file
|
||||||
|
|
||||||
#include "finally.hh"
|
#include "lix/libutil/finally.hh"
|
||||||
#include "types.hh"
|
#include "lix/libutil/types.hh"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
virtual ~ReplInteracter(){};
|
virtual ~ReplInteracter(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReadlineLikeInteracter : public virtual ReplInteracter
|
class ReadlineLikeInteracter final : public ReplInteracter
|
||||||
{
|
{
|
||||||
std::string historyFile;
|
std::string historyFile;
|
||||||
public:
|
public:
|
||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
virtual ~ReadlineLikeInteracter() override;
|
virtual ~ReadlineLikeInteracter() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AutomationInteracter : public virtual ReplInteracter
|
class AutomationInteracter final : public ReplInteracter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AutomationInteracter() = default;
|
AutomationInteracter() = default;
|
||||||
@@ -6,34 +6,35 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "box_ptr.hh"
|
#include "lix/libutil/box_ptr.hh"
|
||||||
#include "repl-interacter.hh"
|
#include "lix/libcmd/repl-interacter.hh"
|
||||||
#include "repl.hh"
|
#include "lix/libcmd/repl.hh"
|
||||||
|
|
||||||
#include "ansicolor.hh"
|
#include "lix/libutil/ansicolor.hh"
|
||||||
#include "shared.hh"
|
#include "lix/libmain/shared.hh"
|
||||||
#include "eval.hh"
|
#include "lix/libutil/escape-string.hh"
|
||||||
#include "eval-cache.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "lix/libexpr/eval-cache.hh"
|
||||||
#include "eval-settings.hh"
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
#include "attr-path.hh"
|
#include "lix/libexpr/eval-settings.hh"
|
||||||
#include "signals.hh"
|
#include "lix/libexpr/attr-path.hh"
|
||||||
#include "store-api.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
#include "log-store.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "lix/libstore/log-store.hh"
|
||||||
#include "get-drvs.hh"
|
#include "lix/libcmd/common-eval-args.hh"
|
||||||
#include "derivations.hh"
|
#include "lix/libexpr/get-drvs.hh"
|
||||||
#include "globals.hh"
|
#include "lix/libstore/derivations.hh"
|
||||||
#include "flake/flake.hh"
|
#include "lix/libstore/globals.hh"
|
||||||
#include "flake/lockfile.hh"
|
#include "lix/libexpr/flake/flake.hh"
|
||||||
#include "editor-for.hh"
|
#include "lix/libexpr/flake/lockfile.hh"
|
||||||
#include "finally.hh"
|
#include "lix/libcmd/editor-for.hh"
|
||||||
#include "markdown.hh"
|
#include "lix/libutil/finally.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "lix/libcmd/markdown.hh"
|
||||||
#include "signals.hh"
|
#include "lix/libstore/local-fs-store.hh"
|
||||||
#include "print.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
#include "gc-small-vector.hh"
|
#include "lix/libexpr/print.hh"
|
||||||
#include "users.hh"
|
#include "lix/libexpr/gc-small-vector.hh"
|
||||||
|
#include "lix/libutil/users.hh"
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
#define GC_INCLUDE_NEW
|
#define GC_INCLUDE_NEW
|
||||||
@@ -119,6 +120,7 @@ struct NixRepl
|
|||||||
};
|
};
|
||||||
/* clang-format: on */
|
/* clang-format: on */
|
||||||
|
|
||||||
|
Evaluator & evaluator;
|
||||||
size_t debugTraceIndex;
|
size_t debugTraceIndex;
|
||||||
|
|
||||||
Strings loadedFiles;
|
Strings loadedFiles;
|
||||||
@@ -133,7 +135,7 @@ struct NixRepl
|
|||||||
|
|
||||||
box_ptr<ReplInteracter> interacter;
|
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);
|
std::function<AnnotatedValues()> getValues);
|
||||||
virtual ~NixRepl() = default;
|
virtual ~NixRepl() = default;
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ struct NixRepl
|
|||||||
void addVarToScope(const Symbol name, Value & v);
|
void addVarToScope(const Symbol name, Value & v);
|
||||||
Expr & parseString(std::string s);
|
Expr & parseString(std::string s);
|
||||||
void evalString(std::string s, Value & v);
|
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
|
* 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.
|
* Note: This is `shared_ptr` to avoid garbage collection.
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<Value *> replOverlaysEvalFunction =
|
std::shared_ptr<Value *> replOverlaysEvalFunction =
|
||||||
#if HAVE_BOEHMGC
|
std::allocate_shared<Value *>(TraceableAllocator<Value *>(), nullptr);
|
||||||
std::allocate_shared<Value *>(traceable_allocator<Value *>(), nullptr);
|
|
||||||
#else
|
|
||||||
std::make_shared<Value *>(nullptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the `info` AttrSet that's passed as the first argument to each
|
* Get the `info` AttrSet that's passed as the first argument to each
|
||||||
@@ -206,7 +204,7 @@ struct NixRepl
|
|||||||
Value & v,
|
Value & v,
|
||||||
unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
|
unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
|
||||||
{
|
{
|
||||||
::nix::printValue(*state, str, v, PrintOptions {
|
::nix::printValue(state, str, v, PrintOptions {
|
||||||
.ansiColors = true,
|
.ansiColors = true,
|
||||||
.force = true,
|
.force = true,
|
||||||
.derivationPaths = true,
|
.derivationPaths = true,
|
||||||
@@ -232,12 +230,13 @@ static box_ptr<ReplInteracter> makeInteracter() {
|
|||||||
return make_box_ptr<ReadlineLikeInteracter>(getDataDir() + "/nix/repl-history");
|
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)
|
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||||
: AbstractNixRepl(state)
|
: AbstractNixRepl(state)
|
||||||
|
, evaluator(state.ctx)
|
||||||
, debugTraceIndex(0)
|
, debugTraceIndex(0)
|
||||||
, getValues(getValues)
|
, getValues(getValues)
|
||||||
, staticEnv(new StaticEnv(nullptr, state->staticBaseEnv.get()))
|
, staticEnv(new StaticEnv(nullptr, evaluator.builtins.staticEnv.get()))
|
||||||
, interacter(makeInteracter())
|
, interacter(makeInteracter())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -251,7 +250,7 @@ void runNix(Path program, const Strings & args)
|
|||||||
.program = settings.nixBinDir+ "/" + program,
|
.program = settings.nixBinDir+ "/" + program,
|
||||||
.args = args,
|
.args = args,
|
||||||
.environment = subprocessEnv,
|
.environment = subprocessEnv,
|
||||||
}).wait();
|
}).waitAndCheck();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -285,7 +284,7 @@ ReplExitStatus NixRepl::mainLoop()
|
|||||||
{
|
{
|
||||||
if (isFirstRepl) {
|
if (isFirstRepl) {
|
||||||
std::string_view debuggerNotice = "";
|
std::string_view debuggerNotice = "";
|
||||||
if (state->debugRepl) {
|
if (evaluator.debug && evaluator.debug->inDebugger) {
|
||||||
debuggerNotice = " debugger";
|
debuggerNotice = " debugger";
|
||||||
}
|
}
|
||||||
notice("Lix %1%%2%\nType :? for help.", nixVersion, debuggerNotice);
|
notice("Lix %1%%2%\nType :? for help.", nixVersion, debuggerNotice);
|
||||||
@@ -310,7 +309,9 @@ ReplExitStatus NixRepl::mainLoop()
|
|||||||
// number of chars as the prompt.
|
// number of chars as the prompt.
|
||||||
if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
|
if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) {
|
||||||
// Ctrl-D should exit the debugger.
|
// Ctrl-D should exit the debugger.
|
||||||
state->debugStop = false;
|
if (evaluator.debug) {
|
||||||
|
evaluator.debug->stop = false;
|
||||||
|
}
|
||||||
logger->cout("");
|
logger->cout("");
|
||||||
// TODO: Should Ctrl-D exit just the current debugger session or
|
// TODO: Should Ctrl-D exit just the current debugger session or
|
||||||
// the entire program?
|
// 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;
|
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) {
|
for (auto const & colonCmd : this->DEBUG_COMMANDS) {
|
||||||
if (colonCmd.starts_with(prefix)) {
|
if (colonCmd.starts_with(prefix)) {
|
||||||
completions.insert(std::string(colonCmd));
|
completions.insert(std::string(colonCmd));
|
||||||
@@ -415,10 +416,25 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else {
|
} 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. */
|
/* Temporarily disable the debugger, to avoid re-entering readline. */
|
||||||
auto debug_repl = state->debugRepl;
|
auto debug = std::move(evaluator.debug);
|
||||||
state->debugRepl = nullptr;
|
Finally restoreDebug([&]() { evaluator.debug = std::move(debug); });
|
||||||
Finally restoreDebug([&]() { state->debugRepl = debug_repl; });
|
|
||||||
try {
|
try {
|
||||||
/* This is an expression that should evaluate to an
|
/* This is an expression that should evaluate to an
|
||||||
attribute set. Evaluate it to get the names of the
|
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);
|
Expr & e = parseString(expr);
|
||||||
Value v;
|
Value v;
|
||||||
e.eval(*state, *env, v);
|
e.eval(state, *env, v);
|
||||||
state->forceAttrs(v, noPos, "while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
|
state.forceAttrs(v, noPos, "while evaluating an attrset for the purpose of completion (this error should not be displayed; file an issue?)");
|
||||||
|
|
||||||
for (auto & i : *v.attrs) {
|
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;
|
if (name.substr(0, cur2.size()) != cur2) continue;
|
||||||
completions.insert(concatStrings(prev, expr, ".", name));
|
completions.insert(concatStrings(prev, expr, ".", name));
|
||||||
}
|
}
|
||||||
@@ -470,28 +489,28 @@ static bool isVarName(std::string_view s)
|
|||||||
|
|
||||||
|
|
||||||
StorePath NixRepl::getDerivationPath(Value & v) {
|
StorePath NixRepl::getDerivationPath(Value & v) {
|
||||||
auto drvInfo = getDerivation(*state, v, false);
|
auto drvInfo = getDerivation(state, v, false);
|
||||||
if (!drvInfo)
|
if (!drvInfo)
|
||||||
throw Error("expression does not evaluate to a derivation, so I can't build it");
|
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)
|
if (!drvPath)
|
||||||
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
|
throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
|
||||||
if (!state->store->isValidPath(*drvPath))
|
if (!evaluator.store->isValidPath(*drvPath))
|
||||||
throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
|
throw Error("expression evaluated to invalid derivation '%s'", evaluator.store->printStorePath(*drvPath));
|
||||||
return *drvPath;
|
return *drvPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NixRepl::loadDebugTraceEnv(DebugTrace & dt)
|
void NixRepl::loadDebugTraceEnv(const DebugTrace & dt)
|
||||||
{
|
{
|
||||||
initEnv();
|
initEnv();
|
||||||
|
|
||||||
auto se = state->getStaticEnv(dt.expr);
|
auto se = evaluator.debug->staticEnvFor(dt.expr);
|
||||||
if (se) {
|
if (se) {
|
||||||
auto vm = mapStaticEnvBindings(state->symbols, *se.get(), dt.env);
|
auto vm = mapStaticEnvBindings(evaluator.symbols, *se.get(), dt.env);
|
||||||
|
|
||||||
// add staticenv vars.
|
// add staticenv vars.
|
||||||
for (auto & [name, value] : *(vm.get()))
|
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"
|
<< " errors\n"
|
||||||
<< " :?, :help Brings up this help menu\n"
|
<< " :?, :help Brings up this help menu\n"
|
||||||
;
|
;
|
||||||
if (state->debugRepl) {
|
if (evaluator.debug && evaluator.debug->inDebugger) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< " Debug mode commands\n"
|
<< " Debug mode commands\n"
|
||||||
@@ -556,49 +575,52 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (state->debugRepl && (command == ":bt" || command == ":backtrace")) {
|
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":bt" || command == ":backtrace")) {
|
||||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
auto traces = evaluator.debug->traces();
|
||||||
|
for (const auto & [idx, i] : enumerate(traces)) {
|
||||||
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
|
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")) {
|
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":env")) {
|
||||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
auto traces = evaluator.debug->traces();
|
||||||
|
for (const auto & [idx, i] : enumerate(traces)) {
|
||||||
if (idx == debugTraceIndex) {
|
if (idx == debugTraceIndex) {
|
||||||
printEnvBindings(*state, i.expr, i.env);
|
printEnvBindings(state, i->expr, i->env);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (state->debugRepl && (command == ":st")) {
|
else if (evaluator.debug && evaluator.debug->inDebugger && (command == ":st")) {
|
||||||
try {
|
try {
|
||||||
// change the DebugTrace index.
|
// change the DebugTrace index.
|
||||||
debugTraceIndex = stoi(arg);
|
debugTraceIndex = stoi(arg);
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
|
|
||||||
for (const auto & [idx, i] : enumerate(state->debugTraces)) {
|
auto traces = evaluator.debug->traces();
|
||||||
|
for (const auto & [idx, i] : enumerate(traces)) {
|
||||||
if (idx == debugTraceIndex) {
|
if (idx == debugTraceIndex) {
|
||||||
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
|
std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": ";
|
||||||
showDebugTrace(std::cout, state->positions, i);
|
showDebugTrace(std::cout, evaluator.positions, *i);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
printEnvBindings(*state, i.expr, i.env);
|
printEnvBindings(state, i->expr, i->env);
|
||||||
loadDebugTraceEnv(i);
|
loadDebugTraceEnv(*i);
|
||||||
break;
|
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.
|
// set flag to stop at next DebugTrace; exit repl.
|
||||||
state->debugStop = true;
|
evaluator.debug->stop = true;
|
||||||
return ProcessLineResult::Continue;
|
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.
|
// set flag to run to next breakpoint or end of program; exit repl.
|
||||||
state->debugStop = false;
|
evaluator.debug->stop = false;
|
||||||
return ProcessLineResult::Continue;
|
return ProcessLineResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,7 +631,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":l" || command == ":load") {
|
else if (command == ":l" || command == ":load") {
|
||||||
state->resetFileCache();
|
state.resetFileCache();
|
||||||
loadFile(arg);
|
loadFile(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,7 +640,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":r" || command == ":reload") {
|
else if (command == ":r" || command == ":reload") {
|
||||||
state->resetFileCache();
|
state.resetFileCache();
|
||||||
reloadFiles();
|
reloadFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,17 +651,17 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
const auto [path, line] = [&] () -> std::pair<SourcePath, uint32_t> {
|
const auto [path, line] = [&] () -> std::pair<SourcePath, uint32_t> {
|
||||||
if (v.type() == nPath || v.type() == nString) {
|
if (v.type() == nPath || v.type() == nString) {
|
||||||
NixStringContext context;
|
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};
|
return {path, 0};
|
||||||
} else if (v.isLambda()) {
|
} else if (v.isLambda()) {
|
||||||
auto pos = state->positions[v.lambda.fun->pos];
|
auto pos = evaluator.positions[v.lambda.fun->pos];
|
||||||
if (auto path = std::get_if<SourcePath>(&pos.origin))
|
if (auto path = std::get_if<CheckedSourcePath>(&pos.origin))
|
||||||
return {*path, pos.line};
|
return {*path, pos.line};
|
||||||
else
|
else
|
||||||
throw Error("'%s' cannot be shown in an editor", pos);
|
throw Error("'%s' cannot be shown in an editor", pos);
|
||||||
} else {
|
} else {
|
||||||
// assume it's a derivation
|
// assume it's a derivation
|
||||||
return findPackageFilename(*state, v, arg);
|
return findPackageFilename(state, v, arg);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@@ -650,12 +672,12 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
|
|
||||||
// runProgram redirects stdout to a StringSink,
|
// runProgram redirects stdout to a StringSink,
|
||||||
// using runProgram2 to allow editors to display their UI
|
// using runProgram2 to allow editors to display their UI
|
||||||
runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }).wait();
|
runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }).waitAndCheck();
|
||||||
|
|
||||||
// Reload right after exiting the editor if path is not in store
|
// 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
|
// Store is immutable, so there could be no changes, so there's no need to reload
|
||||||
if (!state->store->isInStore(path.resolveSymlinks().path.abs())) {
|
if (!evaluator.store->isInStore(canonPath(path.canonical().abs(), true))) {
|
||||||
state->resetFileCache();
|
state.resetFileCache();
|
||||||
reloadFiles();
|
reloadFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,15 +692,15 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
Value v, f, result;
|
Value v, f, result;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
|
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);
|
StorePath drvPath = getDerivationPath(result);
|
||||||
runNix("nix-shell", {state->store->printStorePath(drvPath)});
|
runNix("nix-shell", {evaluator.store->printStorePath(drvPath)});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":log") {
|
else if (command == ":log") {
|
||||||
StorePath drvPath = ([&] {
|
StorePath drvPath = ([&] {
|
||||||
auto maybeDrvPath = state->store->maybeParseStorePath(arg);
|
auto maybeDrvPath = evaluator.store->maybeParseStorePath(arg);
|
||||||
if (maybeDrvPath && maybeDrvPath->isDerivation()) {
|
if (maybeDrvPath && maybeDrvPath->isDerivation()) {
|
||||||
return std::move(*maybeDrvPath);
|
return std::move(*maybeDrvPath);
|
||||||
} else {
|
} else {
|
||||||
@@ -687,7 +709,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
return getDerivationPath(v);
|
return getDerivationPath(v);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
Path drvPathRaw = state->store->printStorePath(drvPath);
|
Path drvPathRaw = evaluator.store->printStorePath(drvPath);
|
||||||
|
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
Finally roModeReset([&]() {
|
Finally roModeReset([&]() {
|
||||||
@@ -695,7 +717,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
});
|
});
|
||||||
auto subs = getDefaultSubstituters();
|
auto subs = getDefaultSubstituters();
|
||||||
|
|
||||||
subs.push_front(state->store);
|
subs.push_front(evaluator.store);
|
||||||
|
|
||||||
bool foundLog = false;
|
bool foundLog = false;
|
||||||
RunPager pager;
|
RunPager pager;
|
||||||
@@ -722,7 +744,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
Value v;
|
Value v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
StorePath drvPath = getDerivationPath(v);
|
StorePath drvPath = getDerivationPath(v);
|
||||||
Path drvPathRaw = state->store->printStorePath(drvPath);
|
Path drvPathRaw = evaluator.store->printStorePath(drvPath);
|
||||||
|
|
||||||
if (command == ":b" || command == ":bl") {
|
if (command == ":b" || command == ":bl") {
|
||||||
// TODO: this only shows a progress bar for explicitly initiated builds,
|
// TODO: this only shows a progress bar for explicitly initiated builds,
|
||||||
@@ -734,22 +756,22 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
logger->pause();
|
logger->pause();
|
||||||
});
|
});
|
||||||
|
|
||||||
state->store->buildPaths({
|
evaluator.store->buildPaths({
|
||||||
DerivedPath::Built {
|
DerivedPath::Built {
|
||||||
.drvPath = makeConstantStorePathRef(drvPath),
|
.drvPath = makeConstantStorePathRef(drvPath),
|
||||||
.outputs = OutputsSpec::All { },
|
.outputs = OutputsSpec::All { },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
auto drv = state->store->readDerivation(drvPath);
|
auto drv = evaluator.store->readDerivation(drvPath);
|
||||||
logger->cout("\nThis derivation produced the following outputs:");
|
logger->cout("\nThis derivation produced the following outputs:");
|
||||||
for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) {
|
for (auto & [outputName, outputPath] : evaluator.store->queryDerivationOutputMap(drvPath)) {
|
||||||
auto localStore = state->store.dynamic_pointer_cast<LocalFSStore>();
|
auto localStore = evaluator.store.dynamic_pointer_cast<LocalFSStore>();
|
||||||
if (localStore && command == ":bl") {
|
if (localStore && command == ":bl") {
|
||||||
std::string symlink = "repl-result-" + outputName;
|
std::string symlink = "repl-result-" + outputName;
|
||||||
localStore->addPermRoot(outputPath, absPath(symlink));
|
localStore->addPermRoot(outputPath, absPath(symlink));
|
||||||
logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath));
|
logger->cout(" ./%s -> %s", symlink, evaluator.store->printStorePath(outputPath));
|
||||||
} else {
|
} else {
|
||||||
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
|
logger->cout(" %s -> %s", outputName, evaluator.store->printStorePath(outputPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (command == ":i") {
|
} else if (command == ":i") {
|
||||||
@@ -771,14 +793,16 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":q" || command == ":quit") {
|
else if (command == ":q" || command == ":quit") {
|
||||||
state->debugStop = false;
|
if (evaluator.debug) {
|
||||||
|
evaluator.debug->stop = false;
|
||||||
|
}
|
||||||
return ProcessLineResult::Quit;
|
return ProcessLineResult::Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (command == ":doc") {
|
else if (command == ":doc") {
|
||||||
Value v;
|
Value v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
if (auto doc = state->getDoc(v)) {
|
if (auto doc = evaluator.builtins.getDoc(v)) {
|
||||||
std::string markdown;
|
std::string markdown;
|
||||||
|
|
||||||
if (!doc->args.empty() && doc->name) {
|
if (!doc->args.empty() && doc->name) {
|
||||||
@@ -795,8 +819,8 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
|
|
||||||
logger->cout(trim(renderMarkdownToTerminal(markdown)));
|
logger->cout(trim(renderMarkdownToTerminal(markdown)));
|
||||||
} else if (v.isLambda()) {
|
} else if (v.isLambda()) {
|
||||||
auto pos = state->positions[v.lambda.fun->pos];
|
auto pos = evaluator.positions[v.lambda.fun->pos];
|
||||||
if (auto path = std::get_if<SourcePath>(&pos.origin)) {
|
if (auto path = std::get_if<CheckedSourcePath>(&pos.origin)) {
|
||||||
// Path and position have now been obtained, feed to nix-doc library to get data.
|
// Path and position have now been obtained, feed to nix-doc library to get data.
|
||||||
auto docComment = lambdaDocsForPos(*path, pos);
|
auto docComment = lambdaDocsForPos(*path, pos);
|
||||||
if (!docComment) {
|
if (!docComment) {
|
||||||
@@ -817,10 +841,10 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
|||||||
else if (command == ":te" || command == ":trace-enable") {
|
else if (command == ":te" || command == ":trace-enable") {
|
||||||
if (arg == "false" || (arg == "" && loggerSettings.showTrace)) {
|
if (arg == "false" || (arg == "" && loggerSettings.showTrace)) {
|
||||||
std::cout << "not showing error traces\n";
|
std::cout << "not showing error traces\n";
|
||||||
loggerSettings.showTrace = false;
|
loggerSettings.showTrace.override(false);
|
||||||
} else if (arg == "true" || (arg == "" && !loggerSettings.showTrace)) {
|
} else if (arg == "true" || (arg == "" && !loggerSettings.showTrace)) {
|
||||||
std::cout << "showing error traces\n";
|
std::cout << "showing error traces\n";
|
||||||
loggerSettings.showTrace = true;
|
loggerSettings.showTrace.override(true);
|
||||||
} else {
|
} else {
|
||||||
throw Error("unexpected argument '%s' to %s", arg, command);
|
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))))
|
isVarName(name = removeWhitespace(line.substr(0, p))))
|
||||||
{
|
{
|
||||||
Expr & e = parseString(line.substr(p + 1));
|
Expr & e = parseString(line.substr(p + 1));
|
||||||
Value & v(*state->allocValue());
|
Value & v(*evaluator.mem.allocValue());
|
||||||
v.mkThunk(env, e);
|
v.mkThunk(env, e);
|
||||||
addVarToScope(state->symbols.create(name), v);
|
addVarToScope(evaluator.symbols.create(name), v);
|
||||||
} else {
|
} else {
|
||||||
Value v;
|
Value v;
|
||||||
evalString(line, v);
|
evalString(line, v);
|
||||||
@@ -857,8 +881,8 @@ void NixRepl::loadFile(const Path & path)
|
|||||||
loadedFiles.remove(path);
|
loadedFiles.remove(path);
|
||||||
loadedFiles.push_back(path);
|
loadedFiles.push_back(path);
|
||||||
Value v, v2;
|
Value v, v2;
|
||||||
state->evalFile(lookupFileArg(*state, path), v);
|
state.evalFile(lookupFileArg(evaluator, path), v);
|
||||||
state->autoCallFunction(*autoArgs, v, v2);
|
state.autoCallFunction(*autoArgs, v, v2);
|
||||||
addAttrsToScope(v2);
|
addAttrsToScope(v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,8 +897,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
|||||||
|
|
||||||
Value v;
|
Value v;
|
||||||
|
|
||||||
flake::callFlake(*state,
|
flake::callFlake(state,
|
||||||
flake::lockFlake(*state, flakeRef,
|
flake::lockFlake(state, flakeRef,
|
||||||
flake::LockFlags {
|
flake::LockFlags {
|
||||||
.updateLockFile = false,
|
.updateLockFile = false,
|
||||||
.useRegistries = !evalSettings.pureEval,
|
.useRegistries = !evalSettings.pureEval,
|
||||||
@@ -887,14 +911,14 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
|||||||
|
|
||||||
void NixRepl::initEnv()
|
void NixRepl::initEnv()
|
||||||
{
|
{
|
||||||
env = &state->allocEnv(envSize);
|
env = &evaluator.mem.allocEnv(envSize);
|
||||||
env->up = &state->baseEnv;
|
env->up = &evaluator.builtins.env;
|
||||||
displ = 0;
|
displ = 0;
|
||||||
staticEnv->vars.clear();
|
staticEnv->vars.clear();
|
||||||
|
|
||||||
varNames.clear();
|
varNames.clear();
|
||||||
for (auto & i : state->staticBaseEnv->vars)
|
for (auto & i : evaluator.builtins.staticEnv->vars)
|
||||||
varNames.emplace(state->symbols[i.first]);
|
varNames.emplace(evaluator.symbols[i.first]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -926,16 +950,16 @@ void NixRepl::loadFiles()
|
|||||||
|
|
||||||
void NixRepl::loadReplOverlays()
|
void NixRepl::loadReplOverlays()
|
||||||
{
|
{
|
||||||
if (!evalSettings.replOverlays) {
|
if (evalSettings.replOverlays.get().empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
notice("Loading '%1%'...", Magenta("repl-overlays"));
|
notice("Loading '%1%'...", Magenta("repl-overlays"));
|
||||||
auto replInitFilesFunction = getReplOverlaysEvalFunction();
|
auto replInitFilesFunction = getReplOverlaysEvalFunction();
|
||||||
|
|
||||||
Value &newAttrs(*state->allocValue());
|
Value &newAttrs(*evaluator.mem.allocValue());
|
||||||
SmallValueVector<3> args = {replInitInfo(), bindingsToAttrs(), replOverlays()};
|
SmallValueVector<3> args = {replInitInfo(), bindingsToAttrs(), replOverlays()};
|
||||||
state->callFunction(
|
state.callFunction(
|
||||||
*replInitFilesFunction,
|
*replInitFilesFunction,
|
||||||
args.size(),
|
args.size(),
|
||||||
args.data(),
|
args.data(),
|
||||||
@@ -958,25 +982,25 @@ Value * NixRepl::getReplOverlaysEvalFunction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto evalReplInitFilesPath = CanonPath::root + "repl-overlays.nix";
|
auto evalReplInitFilesPath = CanonPath::root + "repl-overlays.nix";
|
||||||
*replOverlaysEvalFunction = state->allocValue();
|
*replOverlaysEvalFunction = evaluator.mem.allocValue();
|
||||||
auto code =
|
auto code =
|
||||||
#include "repl-overlays.nix.gen.hh"
|
#include "repl-overlays.nix.gen.hh"
|
||||||
;
|
;
|
||||||
auto & expr = state->parseExprFromString(
|
auto & expr = evaluator.parseExprFromString(
|
||||||
code,
|
code,
|
||||||
SourcePath(evalReplInitFilesPath),
|
SourcePath(evalReplInitFilesPath),
|
||||||
state->staticBaseEnv
|
evaluator.builtins.staticEnv
|
||||||
);
|
);
|
||||||
|
|
||||||
state->eval(expr, **replOverlaysEvalFunction);
|
state.eval(expr, **replOverlaysEvalFunction);
|
||||||
|
|
||||||
return *replOverlaysEvalFunction;
|
return *replOverlaysEvalFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * NixRepl::replOverlays()
|
Value * NixRepl::replOverlays()
|
||||||
{
|
{
|
||||||
Value * replInits(state->allocValue());
|
Value * replInits(evaluator.mem.allocValue());
|
||||||
state->mkList(*replInits, evalSettings.replOverlays.get().size());
|
*replInits = evaluator.mem.newList(evalSettings.replOverlays.get().size());
|
||||||
Value ** replInitElems = replInits->listElems();
|
Value ** replInitElems = replInits->listElems();
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -986,10 +1010,10 @@ Value * NixRepl::replOverlays()
|
|||||||
auto replInit = evalFile(sourcePath);
|
auto replInit = evalFile(sourcePath);
|
||||||
|
|
||||||
if (!replInit->isLambda()) {
|
if (!replInit->isLambda()) {
|
||||||
state->error<TypeError>(
|
evaluator.errors.make<TypeError>(
|
||||||
"Expected `repl-overlays` to be a lambda but found %1%: %2%",
|
"Expected `repl-overlays` to be a lambda but found %1%: %2%",
|
||||||
showType(*replInit),
|
showType(*replInit),
|
||||||
ValuePrinter(*state, *replInit, errorPrintOptions)
|
ValuePrinter(state, *replInit, errorPrintOptions)
|
||||||
)
|
)
|
||||||
.atPos(replInit->determinePos(noPos))
|
.atPos(replInit->determinePos(noPos))
|
||||||
.debugThrow();
|
.debugThrow();
|
||||||
@@ -997,7 +1021,7 @@ Value * NixRepl::replOverlays()
|
|||||||
|
|
||||||
if (replInit->lambda.fun->hasFormals()
|
if (replInit->lambda.fun->hasFormals()
|
||||||
&& !replInit->lambda.fun->formals->ellipsis) {
|
&& !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",
|
"Expected first argument of %1% to have %2% to allow future versions of Lix to add additional attributes to the argument",
|
||||||
"repl-overlays",
|
"repl-overlays",
|
||||||
"..."
|
"..."
|
||||||
@@ -1016,13 +1040,13 @@ Value * NixRepl::replOverlays()
|
|||||||
|
|
||||||
Value * NixRepl::replInitInfo()
|
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());
|
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());
|
info->mkAttrs(builder.finish());
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -1030,14 +1054,14 @@ Value * NixRepl::replInitInfo()
|
|||||||
|
|
||||||
void NixRepl::addAttrsToScope(Value & attrs)
|
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)
|
if (displ + attrs.attrs->size() >= envSize)
|
||||||
throw Error("environment full; cannot add more variables");
|
throw Error("environment full; cannot add more variables");
|
||||||
|
|
||||||
for (auto & i : *attrs.attrs) {
|
for (auto & i : *attrs.attrs) {
|
||||||
staticEnv->vars.emplace_back(i.name, displ);
|
staticEnv->vars.emplace_back(i.name, displ);
|
||||||
env->values[displ++] = i.value;
|
env->values[displ++] = i.value;
|
||||||
varNames.emplace(state->symbols[i.name]);
|
varNames.emplace(evaluator.symbols[i.name]);
|
||||||
}
|
}
|
||||||
staticEnv->sort();
|
staticEnv->sort();
|
||||||
staticEnv->deduplicate();
|
staticEnv->deduplicate();
|
||||||
@@ -1054,17 +1078,17 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
|
|||||||
staticEnv->vars.emplace_back(name, displ);
|
staticEnv->vars.emplace_back(name, displ);
|
||||||
staticEnv->sort();
|
staticEnv->sort();
|
||||||
env->values[displ++] = &v;
|
env->values[displ++] = &v;
|
||||||
varNames.emplace(state->symbols[name]);
|
varNames.emplace(evaluator.symbols[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * NixRepl::bindingsToAttrs()
|
Value * NixRepl::bindingsToAttrs()
|
||||||
{
|
{
|
||||||
auto builder = state->buildBindings(staticEnv->vars.size());
|
auto builder = evaluator.buildBindings(staticEnv->vars.size());
|
||||||
for (auto & [symbol, displacement] : staticEnv->vars) {
|
for (auto & [symbol, displacement] : staticEnv->vars) {
|
||||||
builder.insert(symbol, env->values[displacement]);
|
builder.insert(symbol, env->values[displacement]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * attrs(state->allocValue());
|
Value * attrs(evaluator.mem.allocValue());
|
||||||
attrs->mkAttrs(builder.finish());
|
attrs->mkAttrs(builder.finish());
|
||||||
return attrs;
|
return attrs;
|
||||||
}
|
}
|
||||||
@@ -1072,63 +1096,50 @@ Value * NixRepl::bindingsToAttrs()
|
|||||||
|
|
||||||
Expr & NixRepl::parseString(std::string s)
|
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)
|
void NixRepl::evalString(std::string s, Value & v)
|
||||||
{
|
{
|
||||||
Expr & e = parseString(s);
|
Expr & e = parseString(s);
|
||||||
e.eval(*state, *env, v);
|
e.eval(state, *env, v);
|
||||||
state->forceValue(v, v.determinePos(noPos));
|
state.forceValue(v, v.determinePos(noPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * NixRepl::evalFile(SourcePath & path)
|
Value * NixRepl::evalFile(SourcePath & path)
|
||||||
{
|
{
|
||||||
auto & expr = state->parseExprFromFile(path, staticEnv);
|
auto & expr = evaluator.parseExprFromFile(evaluator.paths.checkSourcePath(path), staticEnv);
|
||||||
Value * result(state->allocValue());
|
Value * result(evaluator.mem.allocValue());
|
||||||
expr.eval(*state, *env, *result);
|
expr.eval(state, *env, *result);
|
||||||
state->forceValue(*result, result->determinePos(noPos));
|
state.forceValue(*result, result->determinePos(noPos));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReplExitStatus AbstractNixRepl::run(
|
||||||
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
const SearchPath & searchPath,
|
||||||
const SearchPath & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
nix::ref<Store> store,
|
||||||
std::function<AnnotatedValues()> getValues)
|
EvalState & state,
|
||||||
|
std::function<AnnotatedValues()> getValues,
|
||||||
|
const ValMap & extraEnv,
|
||||||
|
Bindings * autoArgs
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return std::make_unique<NixRepl>(
|
NixRepl repl(searchPath, store, state, getValues);
|
||||||
searchPath,
|
|
||||||
openStore(),
|
repl.autoArgs = autoArgs;
|
||||||
state,
|
repl.initEnv();
|
||||||
getValues
|
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
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "lix/libexpr/eval.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct AbstractNixRepl
|
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;
|
Bindings * autoArgs;
|
||||||
|
|
||||||
AbstractNixRepl(ref<EvalState> state)
|
AbstractNixRepl(EvalState & state)
|
||||||
: state(state)
|
: state(state)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual ~AbstractNixRepl()
|
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 void initEnv() = 0;
|
||||||
|
|
||||||
virtual ReplExitStatus mainLoop() = 0;
|
virtual ReplExitStatus mainLoop() = 0;
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
#include "lix/libexpr/attr-path.hh"
|
||||||
|
#include "lix/libexpr/eval-inline.hh"
|
||||||
|
#include "print-options.hh"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> parseAttrPath(std::string_view const s)
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
std::string cur;
|
||||||
|
bool haveData = false;
|
||||||
|
auto i = s.begin();
|
||||||
|
while (i != s.end()) {
|
||||||
|
if (*i == '.') {
|
||||||
|
res.push_back(cur);
|
||||||
|
haveData = false;
|
||||||
|
cur.clear();
|
||||||
|
} else if (*i == '"') {
|
||||||
|
// If there is a quote there *will* be a named term even if it is empty.
|
||||||
|
++i;
|
||||||
|
haveData = true;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (i == s.end())
|
||||||
|
throw ParseError("missing closing quote in selection path '%1%'", s);
|
||||||
|
if (*i == '"') break;
|
||||||
|
cur.push_back(*i++);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur.push_back(*i);
|
||||||
|
haveData = true;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (haveData) res.push_back(cur);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string unparseAttrPath(std::vector<std::string> const & attrPath)
|
||||||
|
{
|
||||||
|
// FIXME(jade): can probably be rewritten with ranges once libc++ has a
|
||||||
|
// fully featured implementation
|
||||||
|
// https://github.com/llvm/llvm-project/pull/65536
|
||||||
|
auto ret = std::ostringstream{};
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for (auto const & part : attrPath) {
|
||||||
|
if (!first) {
|
||||||
|
ret << ".";
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
bool mustQuote = std::ranges::any_of(part, [](char c) -> bool {
|
||||||
|
return c == '"' || c == '.' || c == ' ';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mustQuote || part.empty()) {
|
||||||
|
ret << '"' << part << '"';
|
||||||
|
} else {
|
||||||
|
ret << part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
|
||||||
|
Bindings & autoArgs, Value & vIn)
|
||||||
|
{
|
||||||
|
auto tokens = parseAttrPath(attrPath);
|
||||||
|
|
||||||
|
Value * v = &vIn;
|
||||||
|
PosIdx pos = noPos;
|
||||||
|
|
||||||
|
for (auto [attrPathIdx, attr] : enumerate(tokens)) {
|
||||||
|
|
||||||
|
/* Is i an index (integer) or a normal attribute name? */
|
||||||
|
auto attrIndex = string2Int<unsigned int>(attr);
|
||||||
|
|
||||||
|
/* Evaluate the expression. */
|
||||||
|
Value * vNew = state.ctx.mem.allocValue();
|
||||||
|
state.autoCallFunction(autoArgs, *v, *vNew);
|
||||||
|
v = vNew;
|
||||||
|
state.forceValue(*v, noPos);
|
||||||
|
|
||||||
|
/* It should evaluate to either a set or an expression,
|
||||||
|
according to what is specified in the attrPath. */
|
||||||
|
|
||||||
|
if (!attrIndex) {
|
||||||
|
if (attr.empty())
|
||||||
|
throw Error("empty attribute name in selection path '%1%'", attrPath);
|
||||||
|
|
||||||
|
if (v->type() != nAttrs) {
|
||||||
|
auto pathPart =
|
||||||
|
std::vector<std::string>(tokens.begin(), tokens.begin() + attrPathIdx);
|
||||||
|
state.ctx.errors
|
||||||
|
.make<TypeError>(
|
||||||
|
"the value being indexed in the selection path '%1%' at '%2%' should be a "
|
||||||
|
"set but is %3%: %4%",
|
||||||
|
attrPath,
|
||||||
|
unparseAttrPath(pathPart),
|
||||||
|
showType(*v),
|
||||||
|
ValuePrinter(state, *v, errorPrintOptions)
|
||||||
|
)
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bindings::iterator a = v->attrs->find(state.ctx.symbols.create(attr));
|
||||||
|
if (a == v->attrs->end()) {
|
||||||
|
std::set<std::string> attrNames;
|
||||||
|
for (auto & attr : *v->attrs)
|
||||||
|
attrNames.insert(state.ctx.symbols[attr.name]);
|
||||||
|
|
||||||
|
auto suggestions = Suggestions::bestMatches(attrNames, attr);
|
||||||
|
auto pathPart =
|
||||||
|
std::vector<std::string>(tokens.begin(), tokens.begin() + attrPathIdx);
|
||||||
|
throw AttrPathNotFound(
|
||||||
|
suggestions,
|
||||||
|
"attribute '%1%' in selection path '%2%' not found inside path '%3%', whose "
|
||||||
|
"contents are: %4%",
|
||||||
|
attr,
|
||||||
|
attrPath,
|
||||||
|
unparseAttrPath(pathPart),
|
||||||
|
ValuePrinter(state, *v, errorPrintOptions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
v = &*a->value;
|
||||||
|
pos = a->pos;
|
||||||
|
} else {
|
||||||
|
if (!v->isList()) {
|
||||||
|
state.ctx.errors
|
||||||
|
.make<TypeError>(
|
||||||
|
"the expression selected by the selection path '%1%' should be a list but "
|
||||||
|
"is %2%: %3%",
|
||||||
|
attrPath,
|
||||||
|
showType(*v),
|
||||||
|
ValuePrinter(state, *v, errorPrintOptions)
|
||||||
|
)
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
if (*attrIndex >= v->listSize()) {
|
||||||
|
throw AttrPathNotFound(
|
||||||
|
"list index %1% in selection path '%2%' is out of range for list %3%",
|
||||||
|
*attrIndex,
|
||||||
|
attrPath,
|
||||||
|
ValuePrinter(state, *v, errorPrintOptions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v->listElems()[*attrIndex];
|
||||||
|
pos = noPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {v, pos};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
|
||||||
|
{
|
||||||
|
Value * v2;
|
||||||
|
try {
|
||||||
|
auto dummyArgs = state.ctx.mem.allocBindings(0);
|
||||||
|
v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
|
||||||
|
} catch (Error &) {
|
||||||
|
throw NoPositionInfo("package '%s' has no source location information", what);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: is it possible to extract the Pos object instead of doing this
|
||||||
|
// toString + parsing?
|
||||||
|
NixStringContext context;
|
||||||
|
auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");
|
||||||
|
|
||||||
|
auto fn = path.canonical().abs();
|
||||||
|
|
||||||
|
auto fail = [fn]() {
|
||||||
|
throw ParseError("cannot parse 'meta.position' attribute '%s'", fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto colon = fn.rfind(':');
|
||||||
|
if (colon == std::string::npos) fail();
|
||||||
|
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
|
||||||
|
return {CanonPath(fn.substr(0, colon)), lineno};
|
||||||
|
} catch (std::invalid_argument & e) {
|
||||||
|
fail();
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user