Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fecad91b67 | ||
|
|
0220da3e10 | ||
|
|
936f9d45ba | ||
|
|
4b83830d0c | ||
|
|
5904262640 | ||
|
|
2c1ecf8e81 | ||
|
|
88c07341a6 | ||
|
|
07a08bddf0 | ||
|
|
c57ed84e28 | ||
|
|
ef4f5ba85e | ||
|
|
06bb2d95b4 | ||
|
|
6f809194d7 | ||
|
|
57d18df7d0 | ||
|
|
92077b4547 | ||
|
|
33972629d7 | ||
|
|
ac1b754138 | ||
|
|
c28dfc0305 | ||
|
|
e9b92169a5 | ||
|
|
ecd830b3b9 | ||
|
|
6ec8dab06a | ||
|
|
b29d3f4aee | ||
|
|
efe4289464 | ||
|
|
afc6c1bad6 | ||
|
|
6cd6ce5608 | ||
|
|
34bb806f74 | ||
|
|
c6c024ca6f | ||
|
|
03eaef3d7a | ||
|
|
b3110a15e9 | ||
|
|
25a108bb9c | ||
|
|
d308aeaf53 | ||
|
|
297b762513 | ||
|
|
46222bbc43 | ||
|
|
58204a3c39 | ||
|
|
3fb7ae0586 | ||
|
|
161a2ccf7a | ||
|
|
a583a2bc59 | ||
|
|
263d668222 | ||
|
|
fd7d979c79 | ||
|
|
46ffcce0c3 | ||
|
|
8e74c0bfd1 | ||
|
|
3d77b28eac | ||
|
|
47701677e8 | ||
|
|
5d147e125c | ||
|
|
159e621d1a | ||
|
|
511455965e | ||
|
|
7df4ef983e | ||
|
|
0a470fc345 | ||
|
|
8ae6d55db1 | ||
|
|
e068f49f7d | ||
|
|
20866a7031 | ||
|
|
70e68e0ec6 | ||
|
|
e87d1a63bd | ||
|
|
7cf539c728 | ||
|
|
7b09e9f2c4 | ||
|
|
15e5ac8039 | ||
|
|
48858ad5ca | ||
|
|
2bc5de8635 | ||
|
|
dc5f2e7da6 | ||
|
|
a4921b8ceb | ||
|
|
16591eb3cc | ||
|
|
c3f5413e80 | ||
|
|
aeb810b01e | ||
|
|
25a00cae5b | ||
|
|
620d57f036 | ||
|
|
6fcc290619 | ||
|
|
ed09d0c0a4 | ||
|
|
656390062a | ||
|
|
212e96f39c | ||
|
|
b584a42e3d | ||
|
|
5116214343 | ||
|
|
7986711632 | ||
|
|
1917d750a0 | ||
|
|
7ccd946407 | ||
|
|
5558652709 | ||
|
|
1906cce6fc | ||
|
|
9b11165aec | ||
|
|
22144afa8d | ||
|
|
2b29e4b852 | ||
|
|
6016bcd30e | ||
|
|
1b6ee8f4c7 | ||
|
|
cd49ee0897 | ||
|
|
1e2c7c04b1 | ||
|
|
6cc2a8f8ed | ||
|
|
bfee9a2581 | ||
|
|
f9ff67e948 | ||
|
|
6b05f688ee | ||
|
|
5c06e5297d | ||
|
|
24a356bf71 | ||
|
|
24e063efdc | ||
|
|
ca70fba0bf | ||
|
|
5959c591a0 | ||
|
|
c5f9d0d080 | ||
|
|
75e12b8e66 | ||
|
|
f0576d6775 | ||
|
|
ff08306746 | ||
|
|
bc2e43f3c8 | ||
|
|
039d5a023f | ||
|
|
b09b87321c | ||
|
|
107505e13a | ||
|
|
72d8209548 | ||
|
|
18a48d80a0 | ||
|
|
1b3a03f161 | ||
|
|
229567293c | ||
|
|
a4cb62ac25 | ||
|
|
31a551a60f | ||
|
|
6e85d1b5ba | ||
|
|
3a0cc43ac8 | ||
|
|
be0b9dda31 | ||
|
|
78206f06ec | ||
|
|
2ee9da9e22 | ||
|
|
6eba05613a | ||
|
|
7a03cbf09d | ||
|
|
69b8f9980f | ||
|
|
e93acab852 | ||
|
|
806970349b | ||
|
|
ea019e9a26 | ||
|
|
cc837e2458 | ||
|
|
28034bfa49 | ||
|
|
93f4fa8a15 | ||
|
|
c51b6a893c | ||
|
|
e6c44d166a | ||
|
|
7391533ea5 | ||
|
|
5cc2fc46ec | ||
|
|
3628b61ce0 | ||
|
|
470553bd05 | ||
|
|
4ddd077bfa | ||
|
|
0374d94437 | ||
|
|
00f698eb8b | ||
|
|
938092a213 | ||
|
|
772b70952f | ||
|
|
f9974f856e | ||
|
|
6955d41f2b | ||
|
|
934cf2d1f4 | ||
|
|
08d96ffad0 | ||
|
|
a9b4e26b5c | ||
|
|
c642441beb | ||
|
|
05420e7883 | ||
|
|
258897c265 | ||
|
|
239841787b | ||
|
|
cc63db1dd5 | ||
|
|
2c9cf50746 | ||
|
|
c3fc60d936 | ||
|
|
f72ed36025 | ||
|
|
78d777ca15 | ||
|
|
a68ebf8e37 | ||
|
|
804709706c | ||
|
|
c56bc3d81c | ||
|
|
4b07476848 | ||
|
|
bdd4646338 | ||
|
|
e73d9e9488 | ||
|
|
28bba8c44f | ||
|
|
8057a192e3 | ||
|
|
9fa1bee575 | ||
|
|
f45c731cd7 | ||
|
|
88936411bc | ||
|
|
0111ba98ea | ||
|
|
b008674e46 | ||
|
|
826dc0d07d | ||
|
|
97c6009c47 | ||
|
|
ca9c02dff1 | ||
|
|
5526a282b5 | ||
|
|
dadf7a5b46 | ||
|
|
3e067ac11c | ||
|
|
5ea138dc4b | ||
|
|
79a3ba7fa3 | ||
|
|
5f18cd2e84 | ||
|
|
52172607cf | ||
|
|
01a5ea9914 | ||
|
|
8add116acd | ||
|
|
d6143801fd | ||
|
|
9842077cb2 | ||
|
|
5e9c3da412 | ||
|
|
99ed558a93 | ||
|
|
1943b60ad8 | ||
|
|
96fbbbde55 | ||
|
|
d6fd6d8aff | ||
|
|
536c85ea49 | ||
|
|
66fa9e6a4d | ||
|
|
e42df686f3 | ||
|
|
92926be2fe | ||
|
|
b424d29d1b | ||
|
|
3007f57377 | ||
|
|
def5160b61 | ||
|
|
0a4e90395c | ||
|
|
f12492c66d | ||
|
|
aebea2e489 | ||
|
|
649bb60617 | ||
|
|
42d6f640c1 | ||
|
|
299141ecbd | ||
|
|
1b3a78a459 | ||
|
|
82248abd8f | ||
|
|
12f9129f60 | ||
|
|
b7629778ef | ||
|
|
68dcbb187e | ||
|
|
5ee7d8fbab | ||
|
|
2754a07ead | ||
|
|
06f62defe6 | ||
|
|
9c29a2ed35 | ||
|
|
e775d4d84f | ||
|
|
fbf0b2fa45 | ||
|
|
228ea7c2f9 | ||
|
|
cc511fd65b | ||
|
|
a9045c727f | ||
|
|
9fa12fc201 | ||
|
|
3ad53e43c8 | ||
|
|
772778c0ec | ||
|
|
e087bfef5f | ||
|
|
a6ce6d9e7c | ||
|
|
8cc19ed089 | ||
|
|
52edef3495 | ||
|
|
8d100dbef1 | ||
|
|
5c487761c4 | ||
|
|
3631dc6b2f | ||
|
|
aa61bc7472 | ||
|
|
0f96966a44 | ||
|
|
566afa1e9c | ||
|
|
444b03a36f | ||
|
|
d5a01d0f9d | ||
|
|
a7b4aaa2c3 | ||
|
|
3100b29fc5 | ||
|
|
094a08f839 | ||
|
|
4387d19359 | ||
|
|
24d5875514 | ||
|
|
b215b23e9e | ||
|
|
56d29dcd62 | ||
|
|
2d5e8e267b | ||
|
|
5ad89398d1 | ||
|
|
21c2d8d102 | ||
|
|
d62fc71b85 | ||
|
|
4bb4d5479a | ||
|
|
8eed07cda4 | ||
|
|
6c98e6a5de | ||
|
|
8b8ee53bc7 | ||
|
|
5943f41b8b | ||
|
|
08964d7328 | ||
|
|
69c88f5028 | ||
|
|
408a7bfac1 | ||
|
|
8d8d47abd2 | ||
|
|
46a369ad95 | ||
|
|
a3d6585c5a | ||
|
|
9de6bc5d05 | ||
|
|
bf3725da2a | ||
|
|
17dc306aa3 | ||
|
|
f794465ca8 | ||
|
|
8541d27fce | ||
|
|
3acc8adcad | ||
|
|
ea89df2b76 | ||
|
|
48c19c4633 | ||
|
|
198dbe7fa1 | ||
|
|
10dcee99ed | ||
|
|
4c9e3fa641 | ||
|
|
182e15b661 | ||
|
|
88164325fa | ||
|
|
f581ce0b0c | ||
|
|
91ef4d9a81 | ||
|
|
a9a8baaccb | ||
|
|
c31ebc50aa | ||
|
|
e28b683324 | ||
|
|
bbc107ef1e | ||
|
|
3a95e1a17c | ||
|
|
82951e5582 | ||
|
|
620e92e880 | ||
|
|
df27db712d | ||
|
|
d0fc615af6 | ||
|
|
4c34d384e6 | ||
|
|
a28b4445a4 | ||
|
|
2980d1fba9 | ||
|
|
dde6486eab | ||
|
|
c8daeba303 | ||
|
|
167e36a5c3 | ||
|
|
ac238d619c | ||
|
|
600daf972f | ||
|
|
e345182055 | ||
|
|
ecedd9c50c | ||
|
|
70f75be199 | ||
|
|
ad328bea15 | ||
|
|
bfaa5635de | ||
|
|
904f50412c | ||
|
|
90b8a34f82 | ||
|
|
d1de836938 | ||
|
|
f766e146f4 | ||
|
|
e35d6f78dc | ||
|
|
522ecab9b8 | ||
|
|
7586095504 | ||
|
|
a562d544d8 | ||
|
|
9c41c66c5b | ||
|
|
2bbc4a214e | ||
|
|
2e90a5a2a7 | ||
|
|
0a7084567f | ||
|
|
a807edfae8 | ||
|
|
a3f205b249 | ||
|
|
2001895f3d | ||
|
|
cf46f19444 | ||
|
|
8e3a7bd712 | ||
|
|
9958bd6992 | ||
|
|
e666e1156f | ||
|
|
f406288cc7 | ||
|
|
95c74eae26 | ||
|
|
f46612be96 | ||
|
|
d534f137f0 | ||
|
|
0f358ca5b6 | ||
|
|
cb6651e878 | ||
|
|
e464b0247d | ||
|
|
28bf183d2d | ||
|
|
c1f91570b3 | ||
|
|
20582e9ae3 | ||
|
|
b9c2b4d5b4 | ||
|
|
b9124a5c33 | ||
|
|
76e88871b2 | ||
|
|
00092b2d35 | ||
|
|
b674665765 | ||
|
|
09eb230900 | ||
|
|
983220bcd4 | ||
|
|
9fd9dedf12 | ||
|
|
1bda006b74 | ||
|
|
aac14222f5 | ||
|
|
54fe8e0773 | ||
|
|
47ae3ce2ca | ||
|
|
e03a8a1c92 | ||
|
|
8fbe96cb31 | ||
|
|
e6e495649c | ||
|
|
2923b55f9d | ||
|
|
31114ec3a5 | ||
|
|
c845c0ccad | ||
|
|
b14717ab90 | ||
|
|
6c4ac29917 | ||
|
|
e56f71edaf | ||
|
|
4fca02077c | ||
|
|
479e9172b3 | ||
|
|
4ba47205c6 | ||
|
|
6762424e24 | ||
|
|
d4c3b6327f | ||
|
|
1f7901ec3b | ||
|
|
5e2ffd0b8a | ||
|
|
8cf672091e | ||
|
|
9dbda2b3fe | ||
|
|
a2785b7391 | ||
|
|
295027f533 | ||
|
|
d3004c78d9 | ||
|
|
360056e174 | ||
|
|
f7b650d234 | ||
|
|
15e1b2c223 | ||
|
|
9e2fc6951c | ||
|
|
cfd968dd94 | ||
|
|
f3077fd88d | ||
|
|
cc8641815b | ||
|
|
2688fb73f1 | ||
|
|
8207359227 | ||
|
|
8b8fe6139e | ||
|
|
babe54bf97 | ||
|
|
e94806d030 | ||
|
|
a9e6752bbd | ||
|
|
4aa1e5c554 | ||
|
|
d950cfe70b | ||
|
|
56e30e161c | ||
|
|
f0eab0636b | ||
|
|
862c4c5ec5 | ||
|
|
767101824a | ||
|
|
e5c589d271 | ||
|
|
3e89ef597c | ||
|
|
9c2d63084b | ||
|
|
198d0338be | ||
|
|
b9e5b908ed | ||
|
|
4ccd48ce24 | ||
|
|
62f72eb9e1 | ||
|
|
e82767910c | ||
|
|
325d1cfebf | ||
|
|
d025142f52 | ||
|
|
b6c989b801 | ||
|
|
108e14bb18 | ||
|
|
6763084ae5 | ||
|
|
01d56c1eec | ||
|
|
967d066d8e | ||
|
|
1df702d347 | ||
|
|
9c2decaa19 | ||
|
|
5170c5691a | ||
|
|
79bba3782c | ||
|
|
ca94b38371 | ||
|
|
46f852cda0 | ||
|
|
afa7e01878 | ||
|
|
234ce610e0 | ||
|
|
7b10562370 | ||
|
|
8a25d787d7 | ||
|
|
c770a2422a | ||
|
|
4d1b64f118 | ||
|
|
eb7849e3a2 | ||
|
|
90d9c58d4d | ||
|
|
89a8207029 | ||
|
|
157170059d | ||
|
|
97421eb5ec | ||
|
|
d50d7a2874 | ||
|
|
9cd63d2244 | ||
|
|
f3eb29c653 | ||
|
|
9de6d10d11 | ||
|
|
ab42bf1dab | ||
|
|
d059bf48e4 | ||
|
|
f9613da180 | ||
|
|
6183cf2f19 | ||
|
|
f15083c10a | ||
|
|
66a3ac6a56 | ||
|
|
6ecf4f13f6 | ||
|
|
e6ab52cdd1 | ||
|
|
73acb8b836 | ||
|
|
fbf59d95f6 | ||
|
|
3a8f841612 | ||
|
|
b4ea83249b | ||
|
|
7f8e805c8e | ||
|
|
67c6f3eded | ||
|
|
50395b71a9 | ||
|
|
e3ce54ccee | ||
|
|
609586a16d | ||
|
|
7861260a5f | ||
|
|
7892ad15ab | ||
|
|
dbce685e91 | ||
|
|
8c79100839 | ||
|
|
3a4623afbb | ||
|
|
2605f4f4e6 | ||
|
|
477b0fbeca | ||
|
|
f5954e2d94 | ||
|
|
1ef2d5765b | ||
|
|
b1112bbef1 | ||
|
|
566a30c007 | ||
|
|
e98c029717 | ||
|
|
fd63c8bfcd | ||
|
|
0f65793f94 | ||
|
|
680ab6f83d | ||
|
|
6193105710 | ||
|
|
564fb7d9fa | ||
|
|
ed59bf7a18 | ||
|
|
6852289c46 | ||
|
|
1832ab71db | ||
|
|
98193bb440 | ||
|
|
b7fd2c2822 | ||
|
|
58337e0e61 | ||
|
|
aa115e22df | ||
|
|
fe241ece29 | ||
|
|
ccc52adfb2 | ||
|
|
220818f758 | ||
|
|
a6f348599c | ||
|
|
3a9fdf2747 | ||
|
|
1217204c81 | ||
|
|
51d71ad3d7 | ||
|
|
6c01fb4d68 | ||
|
|
53b24f3518 | ||
|
|
a7a43adb79 | ||
|
|
04559a0d45 | ||
|
|
e4d6bcb6cd | ||
|
|
f2bdc87595 | ||
|
|
15c15da482 | ||
|
|
d287b62b64 | ||
|
|
b74d92755d | ||
|
|
09a6321aeb | ||
|
|
58ef4d9a95 | ||
|
|
667d5f1936 | ||
|
|
eb3036da87 | ||
|
|
6586414bc7 | ||
|
|
5ee8944155 | ||
|
|
eae802459d | ||
|
|
2dd3117c27 | ||
|
|
51f9f9924b | ||
|
|
035aa11403 | ||
|
|
a2865f6b3d | ||
|
|
53f52c2111 | ||
|
|
543bf742c9 | ||
|
|
f863673a90 | ||
|
|
a994eb92a4 | ||
|
|
9d94a28bed | ||
|
|
fd2630e1f7 | ||
|
|
6450f5699f | ||
|
|
40c01ec467 | ||
|
|
c4df747267 | ||
|
|
27f0c34390 | ||
|
|
ae72be1b8b | ||
|
|
a560124cdf | ||
|
|
087dee6e1b | ||
|
|
5755a5c354 | ||
|
|
099125435f | ||
|
|
98a423b75a | ||
|
|
425cc612ad | ||
|
|
400e556b34 | ||
|
|
11800e6198 | ||
|
|
cd94665f38 | ||
|
|
ae60643c15 | ||
|
|
89380c03e9 | ||
|
|
2a8e5c8b11 | ||
|
|
d694c599e2 | ||
|
|
8319b1ab9f | ||
|
|
cf49472d60 | ||
|
|
6ec7460af1 | ||
|
|
6b1e671ac6 | ||
|
|
440adfbdd1 | ||
|
|
f4190c38ba | ||
|
|
000132cbd1 | ||
|
|
37f7098464 | ||
|
|
91b8814f0d | ||
|
|
4911a10a4e | ||
|
|
49cd7387ad | ||
|
|
1aba0bf0fa | ||
|
|
42f5a2fc29 | ||
|
|
3ee208516f | ||
|
|
1db38ae81b | ||
|
|
5489086456 | ||
|
|
8da6772ed4 | ||
|
|
723a68c826 | ||
|
|
7ffa523fd1 | ||
|
|
df716c98d2 | ||
|
|
2f3f413e91 | ||
|
|
02fb6323e0 | ||
|
|
221626e715 | ||
|
|
a7ed1f67ee | ||
|
|
8922346305 | ||
|
|
6a214f3e06 | ||
|
|
d0308073c3 | ||
|
|
e545a7f9a8 | ||
|
|
f5398d374b | ||
|
|
881beb170d | ||
|
|
4bc4da331a | ||
|
|
2c26985835 | ||
|
|
8058dab26e | ||
|
|
0301525e6c | ||
|
|
6814b1dfa1 | ||
|
|
591aab7e21 | ||
|
|
e071f87dc5 | ||
|
|
cac9eb39fe |
+6
-15
@@ -35,8 +35,11 @@ Makefile.in
|
|||||||
|
|
||||||
# /doc/manual/
|
# /doc/manual/
|
||||||
/doc/manual/manual.html
|
/doc/manual/manual.html
|
||||||
|
/doc/manual/manual.xmli
|
||||||
|
/doc/manual/manual.pdf
|
||||||
/doc/manual/manual.is-valid
|
/doc/manual/manual.is-valid
|
||||||
/doc/manual/*.1
|
/doc/manual/*.1
|
||||||
|
/doc/manual/*.5
|
||||||
/doc/manual/*.8
|
/doc/manual/*.8
|
||||||
/doc/manual/images
|
/doc/manual/images
|
||||||
/doc/manual/version.txt
|
/doc/manual/version.txt
|
||||||
@@ -60,14 +63,12 @@ Makefile.in
|
|||||||
/scripts/GeneratePatches.pm
|
/scripts/GeneratePatches.pm
|
||||||
/scripts/download-using-manifests.pl
|
/scripts/download-using-manifests.pl
|
||||||
/scripts/copy-from-other-stores.pl
|
/scripts/copy-from-other-stores.pl
|
||||||
|
/scripts/download-from-binary-cache.pl
|
||||||
/scripts/find-runtime-roots.pl
|
/scripts/find-runtime-roots.pl
|
||||||
/scripts/build-remote.pl
|
/scripts/build-remote.pl
|
||||||
/scripts/nix-reduce-build
|
/scripts/nix-reduce-build
|
||||||
/scripts/nix-http-export.cgi
|
/scripts/nix-http-export.cgi
|
||||||
|
|
||||||
# /src/bin2c/
|
|
||||||
/src/bin2c/bin2c
|
|
||||||
|
|
||||||
# /src/bsdiff-4.3/
|
# /src/bsdiff-4.3/
|
||||||
/src/bsdiff-4.3/bsdiff
|
/src/bsdiff-4.3/bsdiff
|
||||||
/src/bsdiff-4.3/bspatch
|
/src/bsdiff-4.3/bspatch
|
||||||
@@ -78,26 +79,19 @@ Makefile.in
|
|||||||
/src/libexpr/parser-tab.cc
|
/src/libexpr/parser-tab.cc
|
||||||
/src/libexpr/parser-tab.hh
|
/src/libexpr/parser-tab.hh
|
||||||
/src/libexpr/parser-tab.output
|
/src/libexpr/parser-tab.output
|
||||||
/src/libexpr/nixexpr-ast.hh
|
|
||||||
/src/libexpr/nixexpr-ast.cc
|
|
||||||
/src/libexpr/nix.tbl
|
/src/libexpr/nix.tbl
|
||||||
|
|
||||||
# /src/libstore/
|
# /src/libstore/
|
||||||
/src/libstore/derivations-ast.cc
|
|
||||||
/src/libstore/derivations-ast.hh
|
|
||||||
/src/libstore/schema.sql.hh
|
/src/libstore/schema.sql.hh
|
||||||
|
|
||||||
# /src/nix-env/
|
# /src/nix-env/
|
||||||
/src/nix-env/nix-env
|
/src/nix-env/nix-env
|
||||||
/src/nix-env/help.txt.hh
|
|
||||||
|
|
||||||
# /src/nix-hash/
|
# /src/nix-hash/
|
||||||
/src/nix-hash/nix-hash
|
/src/nix-hash/nix-hash
|
||||||
/src/nix-hash/help.txt.hh
|
|
||||||
|
|
||||||
# /src/nix-instantiate/
|
# /src/nix-instantiate/
|
||||||
/src/nix-instantiate/nix-instantiate
|
/src/nix-instantiate/nix-instantiate
|
||||||
/src/nix-instantiate/help.txt.hh
|
|
||||||
|
|
||||||
# /src/nix-log2xml/
|
# /src/nix-log2xml/
|
||||||
/src/nix-log2xml/nix-log2xml
|
/src/nix-log2xml/nix-log2xml
|
||||||
@@ -108,15 +102,12 @@ Makefile.in
|
|||||||
|
|
||||||
# /src/nix-setuid-helper/
|
# /src/nix-setuid-helper/
|
||||||
/src/nix-setuid-helper/nix-setuid-helper
|
/src/nix-setuid-helper/nix-setuid-helper
|
||||||
/src/nix-setuid-helper/help.txt.hh
|
|
||||||
|
|
||||||
# /src/nix-store/
|
# /src/nix-store/
|
||||||
/src/nix-store/help.txt.hh
|
|
||||||
/src/nix-store/nix-store
|
/src/nix-store/nix-store
|
||||||
|
|
||||||
# /src/nix-worker/
|
# /src/nix-daemon/
|
||||||
/src/nix-worker/nix-worker
|
/src/nix-daemon/nix-daemon
|
||||||
/src/nix-worker/help.txt.hh
|
|
||||||
|
|
||||||
# /tests/
|
# /tests/
|
||||||
/tests/test-tmp
|
/tests/test-tmp
|
||||||
|
|||||||
+1
-7
@@ -1,6 +1,6 @@
|
|||||||
SUBDIRS = src perl scripts corepkgs doc misc tests
|
SUBDIRS = src perl scripts corepkgs doc misc tests
|
||||||
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
|
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
|
||||||
nix.conf.example NEWS version
|
NEWS version misc/systemd/nix-daemon.service
|
||||||
|
|
||||||
pkginclude_HEADERS = config.h
|
pkginclude_HEADERS = config.h
|
||||||
|
|
||||||
@@ -10,10 +10,6 @@ nix.spec: nix.spec.in
|
|||||||
|
|
||||||
install-data-local: init-state
|
install-data-local: init-state
|
||||||
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
|
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
|
||||||
$(INSTALL_DATA) $(srcdir)/nix.conf.example $(DESTDIR)$(sysconfdir)/nix
|
|
||||||
if ! test -e $(DESTDIR)$(sysconfdir)/nix/nix.conf; then \
|
|
||||||
$(INSTALL_DATA) $(srcdir)/nix.conf.example $(DESTDIR)$(sysconfdir)/nix/nix.conf; \
|
|
||||||
fi
|
|
||||||
$(INSTALL) -d $(DESTDIR)$(docdir)
|
$(INSTALL) -d $(DESTDIR)$(docdir)
|
||||||
$(INSTALL_DATA) README $(DESTDIR)$(docdir)/
|
$(INSTALL_DATA) README $(DESTDIR)$(docdir)/
|
||||||
|
|
||||||
@@ -31,11 +27,9 @@ init-state:
|
|||||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/profiles
|
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/profiles
|
||||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots
|
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots
|
||||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
|
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
|
||||||
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
|
|
||||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
|
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
|
||||||
-$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(storedir)
|
-$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(storedir)
|
||||||
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
|
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
|
||||||
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
with import <nix-make/lib>;
|
||||||
|
with pkgs;
|
||||||
|
|
||||||
|
rec {
|
||||||
|
|
||||||
|
bin2c = link {
|
||||||
|
objects = [ (compileC { main = ./src/bin2c/bin2c.c; }) ];
|
||||||
|
programName = "bin2c";
|
||||||
|
};
|
||||||
|
|
||||||
|
bsdiff = link {
|
||||||
|
objects = [ (compileC { main = ./src/bsdiff-4.3/bsdiff.c; buildInputs = [ pkgs.bzip2 ]; }) ];
|
||||||
|
programName = "bsdiff";
|
||||||
|
buildInputs = [ pkgs.bzip2 ];
|
||||||
|
flags = "-lbz2";
|
||||||
|
};
|
||||||
|
|
||||||
|
bspatch = link {
|
||||||
|
objects = [ (compileC { main = ./src/bsdiff-4.3/bspatch.c; buildInputs = [ pkgs.bzip2 ]; }) ];
|
||||||
|
programName = "bspatch";
|
||||||
|
buildInputs = [ pkgs.bzip2 ];
|
||||||
|
flags = "-lbz2";
|
||||||
|
};
|
||||||
|
|
||||||
|
libformat = makeLibrary {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src ];
|
||||||
|
})
|
||||||
|
[ ./src/boost/format/format_implementation.cc
|
||||||
|
./src/boost/format/free_funcs.cc
|
||||||
|
./src/boost/format/parsing.cc
|
||||||
|
];
|
||||||
|
libraryName = "format";
|
||||||
|
};
|
||||||
|
|
||||||
|
libutil = makeLibrary {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/libutil ./src ./. ];
|
||||||
|
buildInputs = [ pkgs.openssl ];
|
||||||
|
})
|
||||||
|
[ ./src/libutil/util.cc
|
||||||
|
./src/libutil/hash.cc
|
||||||
|
./src/libutil/serialise.cc
|
||||||
|
./src/libutil/archive.cc
|
||||||
|
./src/libutil/xml-writer.cc
|
||||||
|
./src/libutil/immutable.cc
|
||||||
|
];
|
||||||
|
libraryName = "util";
|
||||||
|
};
|
||||||
|
|
||||||
|
libstore = makeLibrary {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
buildInputs = [ pkgs.sqlite ];
|
||||||
|
cFlags = "-DNIX_STORE_DIR=\"/nix/store\" -DNIX_DATA_DIR=\"/home/eelco/Dev/nix/inst/share\" -DNIX_STATE_DIR=\"/nix/var/nix\" -DNIX_LOG_DIR=\"/foo\" -DNIX_CONF_DIR=\"/foo\" -DNIX_LIBEXEC_DIR=\"/foo\" -DNIX_BIN_DIR=\"/home/eelco/Dev/nix/inst/bin\"";
|
||||||
|
})
|
||||||
|
[ ./src/libstore/store-api.cc
|
||||||
|
./src/libstore/local-store.cc
|
||||||
|
./src/libstore/remote-store.cc
|
||||||
|
./src/libstore/derivations.cc
|
||||||
|
./src/libstore/build.cc
|
||||||
|
./src/libstore/misc.cc
|
||||||
|
./src/libstore/globals.cc
|
||||||
|
./src/libstore/references.cc
|
||||||
|
./src/libstore/pathlocks.cc
|
||||||
|
./src/libstore/gc.cc
|
||||||
|
./src/libstore/optimise-store.cc
|
||||||
|
];
|
||||||
|
libraryName = "store";
|
||||||
|
};
|
||||||
|
|
||||||
|
libmain = makeLibrary {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/libmain/shared.cc ];
|
||||||
|
libraryName = "main";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix_hash = link {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/nix-hash ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/nix-hash/nix-hash.cc
|
||||||
|
];
|
||||||
|
libraries = [ libformat libutil libstore libmain ];
|
||||||
|
buildInputs = [ pkgs.openssl pkgs.sqlite ];
|
||||||
|
flags = "-lssl -lsqlite3 -lstdc++";
|
||||||
|
programName = "nix-hash";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix_store = link {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/nix-store ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/nix-store/nix-store.cc
|
||||||
|
./src/nix-store/dotgraph.cc
|
||||||
|
./src/nix-store/xmlgraph.cc
|
||||||
|
];
|
||||||
|
libraries = [ libformat libutil libstore libmain ];
|
||||||
|
buildInputs = [ pkgs.openssl pkgs.sqlite ];
|
||||||
|
flags = "-lssl -lsqlite3 -lstdc++";
|
||||||
|
programName = "nix-store";
|
||||||
|
};
|
||||||
|
|
||||||
|
libexpr = makeLibrary {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/libexpr ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/libexpr/nixexpr.cc
|
||||||
|
./src/libexpr/eval.cc
|
||||||
|
./src/libexpr/primops.cc
|
||||||
|
./src/libexpr/lexer-tab.cc
|
||||||
|
./src/libexpr/parser-tab.cc
|
||||||
|
./src/libexpr/get-drvs.cc
|
||||||
|
./src/libexpr/attr-path.cc
|
||||||
|
./src/libexpr/value-to-xml.cc
|
||||||
|
./src/libexpr/common-opts.cc
|
||||||
|
./src/libexpr/names.cc
|
||||||
|
];
|
||||||
|
libraryName = "expr";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix_instantiate = link {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/nix-instantiate ./src/libexpr ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/nix-instantiate/nix-instantiate.cc ];
|
||||||
|
libraries = [ libformat libutil libstore libmain libexpr ];
|
||||||
|
buildInputs = [ pkgs.openssl pkgs.sqlite ];
|
||||||
|
flags = "-lssl -lsqlite3 -lstdc++";
|
||||||
|
programName = "nix-instantiate";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix_env = link {
|
||||||
|
objects =
|
||||||
|
map (fn: compileC {
|
||||||
|
main = fn;
|
||||||
|
localIncludePath = [ ./src/nix-env ./src/libexpr ./src/libmain ./src/libstore ./src/libutil ./src ./. ];
|
||||||
|
})
|
||||||
|
[ ./src/nix-env/nix-env.cc
|
||||||
|
./src/nix-env/profiles.cc
|
||||||
|
./src/nix-env/user-env.cc
|
||||||
|
];
|
||||||
|
libraries = [ libformat libutil libstore libmain libexpr ];
|
||||||
|
buildInputs = [ pkgs.openssl pkgs.sqlite ];
|
||||||
|
flags = "-lssl -lsqlite3 -lstdc++";
|
||||||
|
programName = "nix-env";
|
||||||
|
};
|
||||||
|
|
||||||
|
all = [ bsdiff bspatch nix_hash nix_store nix_instantiate nix_env ];
|
||||||
|
|
||||||
|
}
|
||||||
+59
-9
@@ -25,12 +25,12 @@ AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
|
|||||||
|
|
||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
linux-gnu*)
|
linux-gnu*)
|
||||||
# For backward compatibility, strip the `-gnu' part.
|
# For backward compatibility, strip the `-gnu' part.
|
||||||
system="$machine_name-linux";;
|
system="$machine_name-linux";;
|
||||||
*)
|
*)
|
||||||
# Strip the version number from names such as `gnu0.3',
|
# Strip the version number from names such as `gnu0.3',
|
||||||
# `darwin10.2.0', etc.
|
# `darwin10.2.0', etc.
|
||||||
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
|
system="$machine_name-`echo $host_os | "$SED" -e's/@<:@0-9.@:>@*$//g'`";;
|
||||||
esac])
|
esac])
|
||||||
|
|
||||||
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
|
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
|
||||||
@@ -40,7 +40,7 @@ case $sys_name in
|
|||||||
sys_name=cygwin
|
sys_name=cygwin
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
AC_MSG_RESULT($system)
|
AC_MSG_RESULT($system)
|
||||||
AC_SUBST(system)
|
AC_SUBST(system)
|
||||||
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
|
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
|
||||||
@@ -68,6 +68,8 @@ if test "$sys_name" = sunos; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS=${CFLAGS:--g -O3 -Wall}
|
||||||
|
CXXFLAGS=${CXXFLAGS:--g -O3 -Wall}
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
|
|
||||||
@@ -106,6 +108,7 @@ AC_LANG_POP(C++)
|
|||||||
# Check for chroot support (requires chroot() and bind mounts).
|
# Check for chroot support (requires chroot() and bind mounts).
|
||||||
AC_CHECK_FUNCS([chroot])
|
AC_CHECK_FUNCS([chroot])
|
||||||
AC_CHECK_FUNCS([unshare])
|
AC_CHECK_FUNCS([unshare])
|
||||||
|
AC_CHECK_FUNCS([statvfs])
|
||||||
AC_CHECK_HEADERS([sched.h])
|
AC_CHECK_HEADERS([sched.h])
|
||||||
AC_CHECK_HEADERS([sys/param.h])
|
AC_CHECK_HEADERS([sys/param.h])
|
||||||
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
||||||
@@ -115,6 +118,31 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# Check for vfork.
|
||||||
|
#AC_FUNC_FORK()
|
||||||
|
|
||||||
|
|
||||||
|
# Check for lutimes, optionally used for changing the mtime of
|
||||||
|
# symlinks.
|
||||||
|
AC_CHECK_FUNCS([lutimes])
|
||||||
|
|
||||||
|
|
||||||
|
# Check for sched_setaffinity.
|
||||||
|
AC_CHECK_FUNCS([sched_setaffinity])
|
||||||
|
|
||||||
|
|
||||||
|
# Check whether the store optimiser can optimise symlinks.
|
||||||
|
AC_MSG_CHECKING([whether it is possible to create a link to a symlink])
|
||||||
|
ln -s bla tmp_link
|
||||||
|
if ln tmp_link tmp_link2 2> /dev/null; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(CAN_LINK_SYMLINK, 1, [Whether link() works on symlinks.])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
rm -f tmp_link tmp_link2
|
||||||
|
|
||||||
|
|
||||||
# Check for <locale>.
|
# Check for <locale>.
|
||||||
AC_LANG_PUSH(C++)
|
AC_LANG_PUSH(C++)
|
||||||
AC_CHECK_HEADERS([locale])
|
AC_CHECK_HEADERS([locale])
|
||||||
@@ -161,9 +189,10 @@ NEED_PROG(perl, perl)
|
|||||||
NEED_PROG(sed, sed)
|
NEED_PROG(sed, sed)
|
||||||
NEED_PROG(tar, tar)
|
NEED_PROG(tar, tar)
|
||||||
NEED_PROG(bzip2, bzip2)
|
NEED_PROG(bzip2, bzip2)
|
||||||
|
NEED_PROG(gzip, gzip)
|
||||||
|
NEED_PROG(xz, xz)
|
||||||
AC_PATH_PROG(dot, dot)
|
AC_PATH_PROG(dot, dot)
|
||||||
AC_PATH_PROG(dblatex, dblatex)
|
AC_PATH_PROG(dblatex, dblatex)
|
||||||
AC_PATH_PROG(gzip, gzip)
|
|
||||||
AC_PATH_PROG(pv, pv, pv)
|
AC_PATH_PROG(pv, pv, pv)
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +278,7 @@ if test "$gc" = yes; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Check for the required Perl dependencies (DBI and DBD::SQLite).
|
# Check for the required Perl dependencies (DBI, DBD::SQLite and WWW::Curl).
|
||||||
perlFlags="-I$perllibdir"
|
perlFlags="-I$perllibdir"
|
||||||
|
|
||||||
AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],
|
AC_ARG_WITH(dbi, AC_HELP_STRING([--with-dbi=PATH],
|
||||||
@@ -260,13 +289,24 @@ AC_ARG_WITH(dbd-sqlite, AC_HELP_STRING([--with-dbd-sqlite=PATH],
|
|||||||
[prefix of the Perl DBD::SQLite library]),
|
[prefix of the Perl DBD::SQLite library]),
|
||||||
perlFlags="$perlFlags -I$withval")
|
perlFlags="$perlFlags -I$withval")
|
||||||
|
|
||||||
|
AC_ARG_WITH(www-curl, AC_HELP_STRING([--with-www-curl=PATH],
|
||||||
|
[prefix of the Perl WWW::Curl library]),
|
||||||
|
perlFlags="$perlFlags -I$withval")
|
||||||
|
|
||||||
AC_MSG_CHECKING([whether DBD::SQLite works])
|
AC_MSG_CHECKING([whether DBD::SQLite works])
|
||||||
if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then
|
if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])
|
AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether WWW::Curl works])
|
||||||
|
if ! $perl $perlFlags -e 'use WWW::Curl;' 2>&5; then
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_MSG_FAILURE([The Perl module WWW::Curl is missing.])
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
|
||||||
AC_SUBST(perlFlags)
|
AC_SUBST(perlFlags)
|
||||||
|
|
||||||
|
|
||||||
@@ -310,10 +350,20 @@ eval dynlib_suffix=$shrext_cmds
|
|||||||
AC_SUBST(dynlib_suffix)
|
AC_SUBST(dynlib_suffix)
|
||||||
|
|
||||||
|
|
||||||
|
# Do we have GNU tar?
|
||||||
|
AC_MSG_CHECKING([if you have a recent GNU tar])
|
||||||
|
if $tar --version 2> /dev/null | grep -q GNU && tar cvf /dev/null --warning=no-timestamp ./config.log > /dev/null; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
tarFlags="--warning=no-timestamp"
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
AC_SUBST(tarFlags)
|
||||||
|
|
||||||
|
|
||||||
AM_CONFIG_HEADER([config.h])
|
AM_CONFIG_HEADER([config.h])
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/bin2c/Makefile
|
|
||||||
src/boost/Makefile
|
src/boost/Makefile
|
||||||
src/boost/format/Makefile
|
src/boost/format/Makefile
|
||||||
src/libutil/Makefile
|
src/libutil/Makefile
|
||||||
@@ -324,7 +374,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/libexpr/Makefile
|
src/libexpr/Makefile
|
||||||
src/nix-instantiate/Makefile
|
src/nix-instantiate/Makefile
|
||||||
src/nix-env/Makefile
|
src/nix-env/Makefile
|
||||||
src/nix-worker/Makefile
|
src/nix-daemon/Makefile
|
||||||
src/nix-setuid-helper/Makefile
|
src/nix-setuid-helper/Makefile
|
||||||
src/nix-log2xml/Makefile
|
src/nix-log2xml/Makefile
|
||||||
src/bsdiff-4.3/Makefile
|
src/bsdiff-4.3/Makefile
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
all-local: config.nix
|
all-local: config.nix
|
||||||
|
|
||||||
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix unpack-channel.sh derivation.nix
|
files = nar.nix buildenv.nix buildenv.pl unpack-channel.nix derivation.nix fetchurl.nix \
|
||||||
|
imported-drv-to-derivation.nix
|
||||||
|
|
||||||
install-exec-local:
|
install-exec-local:
|
||||||
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
|
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/corepkgs
|
||||||
|
|||||||
@@ -2,18 +2,22 @@ with import <nix/config.nix>;
|
|||||||
|
|
||||||
{ derivations, manifest }:
|
{ derivations, manifest }:
|
||||||
|
|
||||||
derivation {
|
derivation {
|
||||||
name = "user-environment";
|
name = "user-environment";
|
||||||
system = builtins.currentSystem;
|
system = builtins.currentSystem;
|
||||||
builder = perl;
|
builder = perl;
|
||||||
args = [ "-w" ./buildenv.pl ];
|
args = [ "-w" ./buildenv.pl ];
|
||||||
|
|
||||||
manifest = manifest;
|
manifest = manifest;
|
||||||
|
|
||||||
# !!! grmbl, need structured data for passing this in a clean way.
|
# !!! grmbl, need structured data for passing this in a clean way.
|
||||||
paths = derivations;
|
derivations =
|
||||||
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
|
map (d:
|
||||||
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
|
[ (d.meta.active or "true")
|
||||||
|
(d.meta.priority or 5)
|
||||||
|
(builtins.length d.outputs)
|
||||||
|
] ++ map (output: builtins.getAttr output d) d.outputs)
|
||||||
|
derivations;
|
||||||
|
|
||||||
# Building user environments remotely just causes huge amounts of
|
# Building user environments remotely just causes huge amounts of
|
||||||
# network traffic, so don't do that.
|
# network traffic, so don't do that.
|
||||||
|
|||||||
+26
-27
@@ -36,19 +36,16 @@ sub createLinks {
|
|||||||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
||||||
$srcFile =~ /\/nix-support$/ ||
|
$srcFile =~ /\/nix-support$/ ||
|
||||||
$srcFile =~ /\/perllocal.pod$/ ||
|
$srcFile =~ /\/perllocal.pod$/ ||
|
||||||
$srcFile =~ /\/easy-install.pth$/ ||
|
|
||||||
$srcFile =~ /\/site.py$/ ||
|
|
||||||
$srcFile =~ /\/site.pyc$/ ||
|
|
||||||
$srcFile =~ /\/info\/dir$/ ||
|
$srcFile =~ /\/info\/dir$/ ||
|
||||||
$srcFile =~ /\/log$/)
|
$srcFile =~ /\/log$/)
|
||||||
{
|
{
|
||||||
# Do nothing.
|
# Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif (-d $srcFile) {
|
elsif (-d $srcFile) {
|
||||||
|
|
||||||
lstat $dstFile;
|
lstat $dstFile;
|
||||||
|
|
||||||
if (-d _) {
|
if (-d _) {
|
||||||
createLinks($srcFile, $dstFile, $priority);
|
createLinks($srcFile, $dstFile, $priority);
|
||||||
}
|
}
|
||||||
@@ -56,10 +53,10 @@ sub createLinks {
|
|||||||
elsif (-l _) {
|
elsif (-l _) {
|
||||||
my $target = readlink $dstFile or die;
|
my $target = readlink $dstFile or die;
|
||||||
if (!-d $target) {
|
if (!-d $target) {
|
||||||
die "collission between directory `$srcFile' and non-directory `$target'";
|
die "collision between directory `$srcFile' and non-directory `$target'";
|
||||||
}
|
}
|
||||||
unlink $dstFile or die "error unlinking `$dstFile': $!";
|
unlink $dstFile or die "error unlinking `$dstFile': $!";
|
||||||
mkdir $dstFile, 0755 ||
|
mkdir $dstFile, 0755 ||
|
||||||
die "error creating directory `$dstFile': $!";
|
die "error creating directory `$dstFile': $!";
|
||||||
createLinks($target, $dstFile, $priorities{$dstFile});
|
createLinks($target, $dstFile, $priorities{$dstFile});
|
||||||
createLinks($srcFile, $dstFile, $priority);
|
createLinks($srcFile, $dstFile, $priority);
|
||||||
@@ -78,15 +75,15 @@ sub createLinks {
|
|||||||
if (-l $dstFile) {
|
if (-l $dstFile) {
|
||||||
my $target = readlink $dstFile;
|
my $target = readlink $dstFile;
|
||||||
my $prevPriority = $priorities{$dstFile};
|
my $prevPriority = $priorities{$dstFile};
|
||||||
die ( "Collission between `$srcFile' and `$target'. "
|
die ( "collision between `$srcFile' and `$target'; "
|
||||||
. "Suggested solution: use `nix-env --set-flag "
|
. "use `nix-env --set-flag "
|
||||||
. "priority NUMBER PKGNAME' to change the priority of "
|
. "priority NUMBER PKGNAME' to change the priority of "
|
||||||
. "one of the conflicting packages.\n" )
|
. "one of the conflicting packages\n" )
|
||||||
if $prevPriority == $priority;
|
if $prevPriority == $priority;
|
||||||
next if $prevPriority < $priority;
|
next if $prevPriority < $priority;
|
||||||
unlink $dstFile or die;
|
unlink $dstFile or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
symlink($srcFile, $dstFile) ||
|
symlink($srcFile, $dstFile) ||
|
||||||
die "error creating link `$dstFile': $!";
|
die "error creating link `$dstFile': $!";
|
||||||
$priorities{$dstFile} = $priority;
|
$priorities{$dstFile} = $priority;
|
||||||
@@ -125,27 +122,29 @@ sub addPkg {
|
|||||||
|
|
||||||
# Convert the stuff we get from the environment back into a coherent
|
# Convert the stuff we get from the environment back into a coherent
|
||||||
# data type.
|
# data type.
|
||||||
my @paths = split ' ', $ENV{"paths"};
|
my @pkgs;
|
||||||
my @active = split ' ', $ENV{"active"};
|
my @derivations = split ' ', $ENV{"derivations"};
|
||||||
my @priority = split ' ', $ENV{"priority"};
|
while (scalar @derivations) {
|
||||||
|
my $active = shift @derivations;
|
||||||
die if scalar @paths != scalar @active;
|
my $priority = shift @derivations;
|
||||||
die if scalar @paths != scalar @priority;
|
my $outputs = shift @derivations;
|
||||||
|
for (my $n = 0; $n < $outputs; $n++) {
|
||||||
my %pkgs;
|
my $path = shift @derivations;
|
||||||
|
push @pkgs,
|
||||||
for (my $n = 0; $n < scalar @paths; $n++) {
|
{ path => $path
|
||||||
$pkgs{$paths[$n]} =
|
, active => $active ne "false"
|
||||||
{ active => $active[$n]
|
, priority => int($priority) };
|
||||||
, priority => $priority[$n] };
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Symlink to the packages that have been installed explicitly by the
|
# Symlink to the packages that have been installed explicitly by the
|
||||||
# user.
|
# user. Process in priority order to reduce unnecessary
|
||||||
foreach my $pkg (sort (keys %pkgs)) {
|
# symlink/unlink steps.
|
||||||
|
@pkgs = sort { $a->{priority} <=> $b->{priority} || $a->{path} cmp $b->{path} } @pkgs;
|
||||||
|
foreach my $pkg (@pkgs) {
|
||||||
#print $pkg, " ", $pkgs{$pkg}->{priority}, "\n";
|
#print $pkg, " ", $pkgs{$pkg}->{priority}, "\n";
|
||||||
addPkg($pkg, $pkgs{$pkg}->{priority}) if $pkgs{$pkg}->{active} ne "false";
|
addPkg($pkg->{path}, $pkg->{priority}) if $pkg->{active};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ in {
|
|||||||
perl = "@perl@";
|
perl = "@perl@";
|
||||||
shell = "@shell@";
|
shell = "@shell@";
|
||||||
coreutils = "@coreutils@";
|
coreutils = "@coreutils@";
|
||||||
bzip2 = fromEnv "NIX_BZIP2" "@bzip2@";
|
bzip2 = "@bzip2@";
|
||||||
|
gzip = "@gzip@";
|
||||||
|
xz = "@xz@";
|
||||||
tar = "@tar@";
|
tar = "@tar@";
|
||||||
|
tarFlags = "@tarFlags@";
|
||||||
tr = "@tr@";
|
tr = "@tr@";
|
||||||
|
curl = "@curl@";
|
||||||
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
|
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ drvAttrs @ { outputs ? [ "out" ], ... }:
|
|||||||
let
|
let
|
||||||
|
|
||||||
strict = derivationStrict drvAttrs;
|
strict = derivationStrict drvAttrs;
|
||||||
|
|
||||||
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
|
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
|
||||||
{ all = map (x: x.value) outputsList;
|
{ all = map (x: x.value) outputsList;
|
||||||
inherit drvAttrs;
|
inherit drvAttrs;
|
||||||
@@ -21,7 +21,7 @@ let
|
|||||||
inherit outputName;
|
inherit outputName;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputsList = map outputToAttrListElement outputs;
|
outputsList = map outputToAttrListElement outputs;
|
||||||
|
|
||||||
in (builtins.head outputsList).value
|
in (builtins.head outputsList).value
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
with import <nix/config.nix>;
|
||||||
|
|
||||||
|
{system ? builtins.currentSystem, url, outputHash ? "", outputHashAlgo ? "", md5 ? "", sha1 ? "", sha256 ? "", executable ? false}:
|
||||||
|
|
||||||
|
assert (outputHash != "" && outputHashAlgo != "")
|
||||||
|
|| md5 != "" || sha1 != "" || sha256 != "";
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
builder = builtins.toFile "fetchurl.sh"
|
||||||
|
(''
|
||||||
|
echo "downloading $url into $out"
|
||||||
|
${curl} --fail --location --max-redirs 20 --insecure "$url" > "$out"
|
||||||
|
'' + (if executable then "${coreutils}/chmod +x $out" else ""));
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
derivation {
|
||||||
|
name = baseNameOf (toString url);
|
||||||
|
builder = shell;
|
||||||
|
args = [ "-e" builder ];
|
||||||
|
|
||||||
|
# New-style output content requirements.
|
||||||
|
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
|
||||||
|
if sha256 != "" then "sha256" else if sha1 != "" then "sha1" else "md5";
|
||||||
|
outputHash = if outputHash != "" then outputHash else
|
||||||
|
if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5;
|
||||||
|
outputHashMode = if executable then "recursive" else "flat";
|
||||||
|
|
||||||
|
inherit system url;
|
||||||
|
|
||||||
|
# No need to double the amount of network traffic
|
||||||
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
# Don't build in a chroot because Nix's dependencies may not be there.
|
||||||
|
__noChroot = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
attrs @ { drvPath, outputs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
commonAttrs = (builtins.listToAttrs outputsList) //
|
||||||
|
{ all = map (x: x.value) outputsList;
|
||||||
|
inherit drvPath;
|
||||||
|
type = "derivation";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputToAttrListElement = outputName:
|
||||||
|
{ name = outputName;
|
||||||
|
value = commonAttrs // {
|
||||||
|
outPath = builtins.getAttr outputName attrs;
|
||||||
|
inherit outputName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputsList = map outputToAttrListElement outputs;
|
||||||
|
|
||||||
|
in (builtins.head outputsList).value
|
||||||
+21
-6
@@ -6,29 +6,44 @@ let
|
|||||||
''
|
''
|
||||||
export PATH=${nixBinDir}:${coreutils}
|
export PATH=${nixBinDir}:${coreutils}
|
||||||
|
|
||||||
|
if [ $compressionType = xz ]; then
|
||||||
|
ext=.xz
|
||||||
|
compressor="| ${xz} -7"
|
||||||
|
elif [ $compressionType = bzip2 ]; then
|
||||||
|
ext=.bz2
|
||||||
|
compressor="| ${bzip2}"
|
||||||
|
else
|
||||||
|
ext=
|
||||||
|
compressor=
|
||||||
|
fi
|
||||||
|
|
||||||
echo "packing ‘$storePath’..."
|
echo "packing ‘$storePath’..."
|
||||||
mkdir $out
|
mkdir $out
|
||||||
dst=$out/tmp.nar.bz2
|
dst=$out/tmp.nar$ext
|
||||||
|
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
nix-store --dump "$storePath" | ${bzip2} > $dst
|
eval "nix-store --dump \"$storePath\" $compressor > $dst"
|
||||||
|
|
||||||
nix-hash --flat --type $hashAlgo --base32 $dst > $out/narbz2-hash
|
hash=$(nix-hash --flat --type $hashAlgo --base32 $dst)
|
||||||
|
echo -n $hash > $out/nar-compressed-hash
|
||||||
|
|
||||||
mv $out/tmp.nar.bz2 $out/$(cat $out/narbz2-hash).nar.bz2
|
mv $dst $out/$hash.nar$ext
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{ storePath, hashAlgo }:
|
{ storePath, hashAlgo, compressionType }:
|
||||||
|
|
||||||
derivation {
|
derivation {
|
||||||
name = "nar";
|
name = "nar";
|
||||||
system = builtins.currentSystem;
|
system = builtins.currentSystem;
|
||||||
builder = shell;
|
builder = shell;
|
||||||
args = [ "-e" builder ];
|
args = [ "-e" builder ];
|
||||||
inherit storePath hashAlgo;
|
inherit storePath hashAlgo compressionType;
|
||||||
|
|
||||||
# Don't build in a chroot because Nix's dependencies may not be there.
|
# Don't build in a chroot because Nix's dependencies may not be there.
|
||||||
__noChroot = true;
|
__noChroot = true;
|
||||||
|
|
||||||
|
# Remote machines may not have ${nixBinDir} or ${coreutils} in the same prefixes
|
||||||
|
preferLocalBuild = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,39 @@
|
|||||||
with import <nix/config.nix>;
|
with import <nix/config.nix>;
|
||||||
|
|
||||||
{ name, channelName, src }:
|
let
|
||||||
|
|
||||||
|
builder = builtins.toFile "unpack-channel.sh"
|
||||||
|
''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
xzpat="\.xz\$"
|
||||||
|
gzpat="\.gz\$"
|
||||||
|
if [[ "$src" =~ $xzpat ]]; then
|
||||||
|
${xz} -d < $src | ${tar} xf - ${tarFlags}
|
||||||
|
elif [[ "$src" =~ $gzpat ]]; then
|
||||||
|
${gzip} -d < $src | ${tar} xf - ${tarFlags}
|
||||||
|
else
|
||||||
|
${bzip2} -d < $src | ${tar} xf - ${tarFlags}
|
||||||
|
fi
|
||||||
|
mv * $out/$channelName
|
||||||
|
if [ -n "$binaryCacheURL" ]; then
|
||||||
|
mkdir $out/binary-caches
|
||||||
|
echo -n "$binaryCacheURL" > $out/binary-caches/$channelName
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{ name, channelName, src, binaryCacheURL ? "" }:
|
||||||
|
|
||||||
derivation {
|
derivation {
|
||||||
system = builtins.currentSystem;
|
system = builtins.currentSystem;
|
||||||
builder = shell;
|
builder = shell;
|
||||||
args = [ "-e" ./unpack-channel.sh ];
|
args = [ "-e" builder ];
|
||||||
inherit name channelName src bzip2 tar tr;
|
inherit name channelName src binaryCacheURL;
|
||||||
|
|
||||||
PATH = "${nixBinDir}:${coreutils}";
|
PATH = "${nixBinDir}:${coreutils}";
|
||||||
|
|
||||||
# No point in doing this remotely.
|
# No point in doing this remotely.
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
mkdir $out
|
|
||||||
cd $out
|
|
||||||
$bzip2 -d < $src | $tar xf -
|
|
||||||
mv * $out/$channelName
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
if [ -e tests/test-tmp ]; then
|
||||||
|
chmod -R u+w tests/test-tmp
|
||||||
|
rm -rf tests/test-tmp
|
||||||
|
fi
|
||||||
|
|
||||||
|
s=$(type -p nix-shell)
|
||||||
|
exec $s release.nix -A tarball --command "
|
||||||
|
export NIX_REMOTE=daemon
|
||||||
|
export NIX_PATH='$NIX_PATH'
|
||||||
|
export NIX_BUILD_SHELL=$(type -p bash)
|
||||||
|
export c=\$configureFlags
|
||||||
|
exec $s release.nix -A build.x86_64-linux --exclude tarball --command '
|
||||||
|
configureFlags+=\" \$c --prefix=$(pwd)/inst --sysconfdir=$(pwd)/inst/etc\"
|
||||||
|
return
|
||||||
|
'" \
|
||||||
|
"$@"
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
To produce a `stable' release from the trunk:
|
|
||||||
|
|
||||||
-1. Update the release notes; make sure that the release date is
|
|
||||||
correct.
|
|
||||||
|
|
||||||
0. Make sure that the trunk builds in the release supervisor.
|
|
||||||
|
|
||||||
1. Branch the trunk, e.g., `svn cp .../trunk
|
|
||||||
.../branches/0.5-release'.
|
|
||||||
|
|
||||||
2. Switch to the branch, e.g., `svn switch .../branches/0.5-release'.
|
|
||||||
|
|
||||||
3. In `configure.ac', change `STABLE=0' into `STABLE=1' and commit.
|
|
||||||
|
|
||||||
4. In the release supervisor, add a one-time job to build
|
|
||||||
`.../branches/0.5-release'.
|
|
||||||
|
|
||||||
5. Make sure that the release succeeds.
|
|
||||||
|
|
||||||
6. Move the branch to a tag, e.g., `svn mv .../branches/0.5-release
|
|
||||||
.../tags/0.5'.
|
|
||||||
|
|
||||||
Note that the branch should not be used for maintenance; it should
|
|
||||||
be deleted after the release has been created. A maintenance
|
|
||||||
branch (e.g., `.../branches/0.5') should be created from the
|
|
||||||
original revision of the trunk (since maintenance releases should
|
|
||||||
also be tested first; hence, we cannot have `STABLE=1'). The same
|
|
||||||
procedure can then be followed to produce maintenance releases;
|
|
||||||
just substitute `.../branches/VERSION' for the trunk.
|
|
||||||
|
|
||||||
7. Switch back to the trunk.
|
|
||||||
|
|
||||||
8. Bump the version number in `configure.ac' (in AC_INIT).
|
|
||||||
@@ -16,12 +16,14 @@ dblatex_opts = \
|
|||||||
# Note: we use GIF for now, since the PNGs shipped with Docbook aren't
|
# Note: we use GIF for now, since the PNGs shipped with Docbook aren't
|
||||||
# transparent.
|
# transparent.
|
||||||
|
|
||||||
man1_MANS = nix-env.1 nix-build.1 nix-store.1 nix-instantiate.1 \
|
man1_MANS = nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
|
||||||
nix-collect-garbage.1 nix-push.1 nix-pull.1 \
|
nix-collect-garbage.1 nix-push.1 nix-pull.1 \
|
||||||
nix-prefetch-url.1 nix-channel.1 \
|
nix-prefetch-url.1 nix-channel.1 \
|
||||||
nix-install-package.1 nix-hash.1 nix-copy-closure.1
|
nix-install-package.1 nix-hash.1 nix-copy-closure.1
|
||||||
|
|
||||||
man8_MANS = nix-worker.8
|
man5_MANS = nix.conf.5
|
||||||
|
|
||||||
|
man8_MANS = nix-daemon.8
|
||||||
|
|
||||||
FIGURES = figures/user-environments.png
|
FIGURES = figures/user-environments.png
|
||||||
|
|
||||||
|
|||||||
+113
-57
@@ -19,7 +19,7 @@ is also available as <function>builtins.derivation</function>.</para>
|
|||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
|
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Abort Nix expression evaluation, print error
|
<listitem><para>Abort Nix expression evaluation, print error
|
||||||
@@ -27,7 +27,7 @@ is also available as <function>builtins.derivation</function>.</para>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.add</function>
|
<varlistentry><term><function>builtins.add</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ is also available as <function>builtins.derivation</function>.</para>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.attrNames</function>
|
<varlistentry><term><function>builtins.attrNames</function>
|
||||||
<replaceable>attrs</replaceable></term>
|
<replaceable>attrs</replaceable></term>
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
|
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Return the <emphasis>base name</emphasis> of the
|
<listitem><para>Return the <emphasis>base name</emphasis> of the
|
||||||
@@ -65,7 +65,7 @@ attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><varname>builtins</varname></term>
|
<varlistentry><term><varname>builtins</varname></term>
|
||||||
|
|
||||||
<listitem><para>The attribute set <varname>builtins</varname>
|
<listitem><para>The attribute set <varname>builtins</varname>
|
||||||
@@ -82,7 +82,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.compareVersions</function>
|
<varlistentry><term><function>builtins.compareVersions</function>
|
||||||
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
|
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
|
||||||
|
|
||||||
@@ -99,7 +99,16 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><function>builtins.concatLists</function>
|
||||||
|
<replaceable>lists</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Concatenate a list of lists into a single
|
||||||
|
list.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry
|
<varlistentry
|
||||||
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
|
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
|
||||||
|
|
||||||
@@ -124,7 +133,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<varlistentry><term><function>dependencyClosure</function></term>
|
<varlistentry><term><function>dependencyClosure</function></term>
|
||||||
|
|
||||||
@@ -133,7 +142,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>derivation</function>
|
<varlistentry><term><function>derivation</function>
|
||||||
<replaceable>attrs</replaceable></term>
|
<replaceable>attrs</replaceable></term>
|
||||||
|
|
||||||
@@ -152,7 +161,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.div</function>
|
<varlistentry><term><function>builtins.div</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -162,7 +171,40 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><function>builtins.elem</function>
|
||||||
|
<replaceable>x</replaceable> <replaceable>xs</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Return <literal>true</literal> if a value equal to
|
||||||
|
<replaceable>x</replaceable> occurs in the list
|
||||||
|
<replaceable>xs</replaceable>, and <literal>false</literal>
|
||||||
|
otherwise.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><function>builtins.elemAt</function>
|
||||||
|
<replaceable>xs</replaceable> <replaceable>n</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Return element <replaceable>n</replaceable> from
|
||||||
|
the list <replaceable>xs</replaceable>. Elements are counted
|
||||||
|
starting from 0. A fatal error occurs in the index is out of
|
||||||
|
bounds.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><function>builtins.filter</function>
|
||||||
|
<replaceable>f</replaceable> <replaceable>xs</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Return a list consisting of the elements of
|
||||||
|
<replaceable>xs</replaceable> for which the function
|
||||||
|
<replaceable>f</replaceable> returns
|
||||||
|
<literal>true</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.filterSource</function>
|
<varlistentry><term><function>builtins.filterSource</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -214,7 +256,7 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.getAttr</function>
|
<varlistentry><term><function>builtins.getAttr</function>
|
||||||
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
||||||
|
|
||||||
@@ -227,7 +269,7 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.getEnv</function>
|
<varlistentry><term><function>builtins.getEnv</function>
|
||||||
<replaceable>s</replaceable></term>
|
<replaceable>s</replaceable></term>
|
||||||
|
|
||||||
@@ -245,7 +287,7 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.hasAttr</function>
|
<varlistentry><term><function>builtins.hasAttr</function>
|
||||||
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
||||||
|
|
||||||
@@ -259,7 +301,19 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><function>builtins.hashString</function>
|
||||||
|
<replaceable>type</replaceable> <replaceable>s</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Return a base-16 representation of the
|
||||||
|
cryptographic hash of string <replaceable>s</replaceable>. The
|
||||||
|
hash algorithm specified by <replaceable>type</replaceable> must
|
||||||
|
be one of <literal>"md5"</literal>, <literal>"sha1"</literal> or
|
||||||
|
<literal>"sha256"</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.head</function>
|
<varlistentry><term><function>builtins.head</function>
|
||||||
<replaceable>list</replaceable></term>
|
<replaceable>list</replaceable></term>
|
||||||
|
|
||||||
@@ -270,13 +324,15 @@ stdenv.mkDerivation {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>import</function>
|
<varlistentry><term><function>import</function>
|
||||||
<replaceable>path</replaceable></term>
|
<replaceable>path</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Load, parse and return the Nix expression in the
|
<listitem><para>Load, parse and return the Nix expression in the
|
||||||
file <replaceable>path</replaceable>. Evaluation aborts if the
|
file <replaceable>path</replaceable>. If <replaceable>path
|
||||||
file doesn’t exist or contains an incorrect Nix
|
</replaceable> is a directory, the file <filename>default.nix
|
||||||
|
</filename> in that directory is loaded. Evaluation aborts if
|
||||||
|
the file doesn’t exist or contains an incorrect Nix
|
||||||
expression. <function>import</function> implements Nix’s module
|
expression. <function>import</function> implements Nix’s module
|
||||||
system: you can put any Nix expression (such as an attribute set
|
system: you can put any Nix expression (such as an attribute set
|
||||||
or a function) in a separate file, and use it from Nix expressions
|
or a function) in a separate file, and use it from Nix expressions
|
||||||
@@ -288,7 +344,7 @@ stdenv.mkDerivation {
|
|||||||
built-in). Therefore, it cannot refer to variables that are in
|
built-in). Therefore, it cannot refer to variables that are in
|
||||||
scope at the call site. For instance, if you have a calling
|
scope at the call site. For instance, if you have a calling
|
||||||
expression
|
expression
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
rec {
|
rec {
|
||||||
x = 123;
|
x = 123;
|
||||||
@@ -323,7 +379,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.intersectAttrs</function>
|
<varlistentry><term><function>builtins.intersectAttrs</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -332,8 +388,8 @@ x: x + 456</programlisting>
|
|||||||
exist in the set <replaceable>e1</replaceable>.</para></listitem>
|
exist in the set <replaceable>e1</replaceable>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isAttrs</function>
|
<varlistentry><term><function>builtins.isAttrs</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -343,7 +399,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isList</function>
|
<varlistentry><term><function>builtins.isList</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -353,7 +409,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isFunction</function>
|
<varlistentry><term><function>builtins.isFunction</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -363,7 +419,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isString</function>
|
<varlistentry><term><function>builtins.isString</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -373,17 +429,17 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isInt</function>
|
<varlistentry><term><function>builtins.isInt</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Return <literal>true</literal> if
|
<listitem><para>Return <literal>true</literal> if
|
||||||
<replaceable>e</replaceable> evaluates to a int, and
|
<replaceable>e</replaceable> evaluates to an int, and
|
||||||
<literal>false</literal> otherwise.</para></listitem>
|
<literal>false</literal> otherwise.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.isBool</function>
|
<varlistentry><term><function>builtins.isBool</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -393,7 +449,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>isNull</function>
|
<varlistentry><term><function>isNull</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -403,12 +459,12 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
<warning><para>This function is <emphasis>deprecated</emphasis>;
|
<warning><para>This function is <emphasis>deprecated</emphasis>;
|
||||||
just write <literal>e == null</literal> instead.</para></warning>
|
just write <literal>e == null</literal> instead.</para></warning>
|
||||||
|
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.length</function>
|
<varlistentry><term><function>builtins.length</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -417,7 +473,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.lessThan</function>
|
<varlistentry><term><function>builtins.lessThan</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -430,7 +486,7 @@ x: x + 456</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.listToAttrs</function>
|
<varlistentry><term><function>builtins.listToAttrs</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -457,7 +513,7 @@ builtins.listToAttrs
|
|||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry><term><function>map</function>
|
<varlistentry><term><function>map</function>
|
||||||
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
|
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
|
||||||
|
|
||||||
@@ -470,10 +526,10 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
|
|||||||
|
|
||||||
evaluates to <literal>[ "foobar" "foobla" "fooabc"
|
evaluates to <literal>[ "foobar" "foobla" "fooabc"
|
||||||
]</literal>.</para></listitem>
|
]</literal>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.mul</function>
|
<varlistentry><term><function>builtins.mul</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -483,7 +539,7 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.parseDrvName</function>
|
<varlistentry><term><function>builtins.parseDrvName</function>
|
||||||
<replaceable>s</replaceable></term>
|
<replaceable>s</replaceable></term>
|
||||||
|
|
||||||
@@ -498,7 +554,7 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.pathExists</function>
|
<varlistentry><term><function>builtins.pathExists</function>
|
||||||
<replaceable>path</replaceable></term>
|
<replaceable>path</replaceable></term>
|
||||||
|
|
||||||
@@ -531,7 +587,7 @@ in config.someSetting</programlisting>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.readFile</function>
|
<varlistentry><term><function>builtins.readFile</function>
|
||||||
<replaceable>path</replaceable></term>
|
<replaceable>path</replaceable></term>
|
||||||
|
|
||||||
@@ -539,8 +595,8 @@ in config.someSetting</programlisting>
|
|||||||
<replaceable>path</replaceable> as a string.</para></listitem>
|
<replaceable>path</replaceable> as a string.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>removeAttrs</function>
|
<varlistentry><term><function>removeAttrs</function>
|
||||||
<replaceable>attrs</replaceable> <replaceable>list</replaceable></term>
|
<replaceable>attrs</replaceable> <replaceable>list</replaceable></term>
|
||||||
|
|
||||||
@@ -556,7 +612,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.stringLength</function>
|
<varlistentry><term><function>builtins.stringLength</function>
|
||||||
<replaceable>e</replaceable></term>
|
<replaceable>e</replaceable></term>
|
||||||
|
|
||||||
@@ -566,7 +622,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.sub</function>
|
<varlistentry><term><function>builtins.sub</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -576,7 +632,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.substring</function>
|
<varlistentry><term><function>builtins.substring</function>
|
||||||
<replaceable>start</replaceable> <replaceable>len</replaceable>
|
<replaceable>start</replaceable> <replaceable>len</replaceable>
|
||||||
<replaceable>s</replaceable></term>
|
<replaceable>s</replaceable></term>
|
||||||
@@ -594,7 +650,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.tail</function>
|
<varlistentry><term><function>builtins.tail</function>
|
||||||
<replaceable>list</replaceable></term>
|
<replaceable>list</replaceable></term>
|
||||||
|
|
||||||
@@ -604,7 +660,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>throw</function>
|
<varlistentry><term><function>throw</function>
|
||||||
<replaceable>s</replaceable></term>
|
<replaceable>s</replaceable></term>
|
||||||
|
|
||||||
@@ -618,7 +674,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry
|
<varlistentry
|
||||||
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
|
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
|
||||||
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
|
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
|
||||||
@@ -636,7 +692,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
|||||||
|
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
name = "hello-2.1.1";
|
name = "hello-2.1.1";
|
||||||
|
|
||||||
builder = builtins.toFile "builder.sh" "
|
builder = builtins.toFile "builder.sh" "
|
||||||
source $stdenv/setup
|
source $stdenv/setup
|
||||||
|
|
||||||
@@ -655,7 +711,7 @@ stdenv.mkDerivation {
|
|||||||
};
|
};
|
||||||
inherit perl;
|
inherit perl;
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>It is even possible for one file to refer to another, e.g.,
|
<para>It is even possible for one file to refer to another, e.g.,
|
||||||
@@ -693,7 +749,7 @@ in foo</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
|
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Convert the string value
|
<listitem><para>Convert the string value
|
||||||
@@ -706,7 +762,7 @@ in foo</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
|
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Convert the expression
|
<listitem><para>Convert the expression
|
||||||
@@ -718,7 +774,7 @@ in foo</programlisting>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
|
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Return a string containing an XML representation
|
<listitem><para>Return a string containing an XML representation
|
||||||
@@ -763,7 +819,7 @@ in foo</programlisting>
|
|||||||
|
|
||||||
<example xml:id='ex-toxml'><title>Passing information to a builder
|
<example xml:id='ex-toxml'><title>Passing information to a builder
|
||||||
using <function>toXML</function></title>
|
using <function>toXML</function></title>
|
||||||
|
|
||||||
<programlisting><![CDATA[
|
<programlisting><![CDATA[
|
||||||
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
|
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
|
||||||
|
|
||||||
@@ -771,7 +827,7 @@ stdenv.mkDerivation (rec {
|
|||||||
name = "web-server";
|
name = "web-server";
|
||||||
|
|
||||||
buildInputs = [ libxslt ];
|
buildInputs = [ libxslt ];
|
||||||
|
|
||||||
builder = builtins.toFile "builder.sh" "
|
builder = builtins.toFile "builder.sh" "
|
||||||
source $stdenv/setup
|
source $stdenv/setup
|
||||||
mkdir $out
|
mkdir $out
|
||||||
@@ -804,7 +860,7 @@ stdenv.mkDerivation (rec {
|
|||||||
|
|
||||||
<example xml:id='ex-toxml-result'><title>XML representation produced by
|
<example xml:id='ex-toxml-result'><title>XML representation produced by
|
||||||
<function>toXML</function></title>
|
<function>toXML</function></title>
|
||||||
|
|
||||||
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
||||||
<expr>
|
<expr>
|
||||||
<list>
|
<list>
|
||||||
@@ -833,7 +889,7 @@ stdenv.mkDerivation (rec {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><function>builtins.trace</function>
|
<varlistentry><term><function>builtins.trace</function>
|
||||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||||
|
|
||||||
@@ -844,7 +900,7 @@ stdenv.mkDerivation (rec {
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+197
-52
@@ -1,38 +1,50 @@
|
|||||||
<section xmlns="http://docbook.org/ns/docbook"
|
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xml:id="sec-conf-file">
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||||
|
xml:id="sec-conf-file">
|
||||||
|
|
||||||
<title>Nix configuration file</title>
|
<refmeta>
|
||||||
|
<refentrytitle>nix.conf</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum>
|
||||||
|
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||||
|
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>nix.conf</refname>
|
||||||
|
<refpurpose>Nix configuration file</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsection><title>Description</title>
|
||||||
|
|
||||||
<para>A number of persistent settings of Nix are stored in the file
|
<para>A number of persistent settings of Nix are stored in the file
|
||||||
<filename><replaceable>sysconfdir</replaceable>/nix/nix.conf</filename>.
|
<filename><replaceable>sysconfdir</replaceable>/nix/nix.conf</filename>.
|
||||||
This file is a list of <literal><replaceable>name</replaceable> =
|
This file is a list of <literal><replaceable>name</replaceable> =
|
||||||
<replaceable>value</replaceable></literal> pairs, one per line.
|
<replaceable>value</replaceable></literal> pairs, one per line.
|
||||||
Comments start with a <literal>#</literal> character. An example
|
Comments start with a <literal>#</literal> character. Here is an example
|
||||||
configuration file is shown in <xref linkend="ex-nix-conf" />.</para>
|
configuration file:</para>
|
||||||
|
|
||||||
<example xml:id='ex-nix-conf'><title>Nix configuration file</title>
|
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
gc-keep-outputs = true # Nice for developers
|
gc-keep-outputs = true # Nice for developers
|
||||||
gc-keep-derivations = true # Idem
|
gc-keep-derivations = true # Idem
|
||||||
env-keep-derivations = false
|
env-keep-derivations = false
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</example>
|
|
||||||
|
|
||||||
<para>The following variables are currently available:
|
<para>You can override settings using the <option>--option</option>
|
||||||
|
flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
|
||||||
|
|
||||||
|
<para>The following settings are currently available:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-gc-keep-outputs"><term><literal>gc-keep-outputs</literal></term>
|
<varlistentry xml:id="conf-gc-keep-outputs"><term><literal>gc-keep-outputs</literal></term>
|
||||||
|
|
||||||
<listitem><para>If <literal>true</literal>, the garbage collector
|
<listitem><para>If <literal>true</literal>, the garbage collector
|
||||||
will keep the outputs of non-garbage derivations. If
|
will keep the outputs of non-garbage derivations. If
|
||||||
<literal>false</literal> (default), outputs will be deleted unless
|
<literal>false</literal> (default), outputs will be deleted unless
|
||||||
they are GC roots themselves (or reachable from other roots).</para>
|
they are GC roots themselves (or reachable from other roots).</para>
|
||||||
|
|
||||||
<para>In general, outputs must be registered as roots separately.
|
<para>In general, outputs must be registered as roots separately.
|
||||||
However, even if the output of a derivation is registered as a
|
However, even if the output of a derivation is registered as a
|
||||||
root, the collector will still delete store paths that are used
|
root, the collector will still delete store paths that are used
|
||||||
@@ -41,7 +53,7 @@ env-keep-derivations = false
|
|||||||
this option to <literal>true</literal>.</para></listitem>
|
this option to <literal>true</literal>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-gc-keep-derivations"><term><literal>gc-keep-derivations</literal></term>
|
<varlistentry xml:id="conf-gc-keep-derivations"><term><literal>gc-keep-derivations</literal></term>
|
||||||
|
|
||||||
@@ -59,7 +71,7 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><literal>env-keep-derivations</literal></term>
|
<varlistentry><term><literal>env-keep-derivations</literal></term>
|
||||||
|
|
||||||
<listitem><para>If <literal>false</literal> (default), derivations
|
<listitem><para>If <literal>false</literal> (default), derivations
|
||||||
@@ -83,14 +95,14 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-build-max-jobs"><term><literal>build-max-jobs</literal></term>
|
<varlistentry xml:id="conf-build-max-jobs"><term><literal>build-max-jobs</literal></term>
|
||||||
|
|
||||||
<listitem><para>This option defines the maximum number of jobs
|
<listitem><para>This option defines the maximum number of jobs
|
||||||
that Nix will try to build in parallel. The default is
|
that Nix will try to build in parallel. The default is
|
||||||
<literal>1</literal>. You should generally set it to the number
|
<literal>1</literal>. You should generally set it to the number
|
||||||
of CPUs in your system (e.g., <literal>2</literal> on a Athlon 64
|
of CPUs in your system (e.g., <literal>2</literal> on an Athlon 64
|
||||||
X2). It can be overriden using the <option
|
X2). It can be overridden using the <option
|
||||||
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
|
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
|
||||||
command line switch.</para></listitem>
|
command line switch.</para></listitem>
|
||||||
|
|
||||||
@@ -107,7 +119,7 @@ env-keep-derivations = false
|
|||||||
<varname>enableParallelBuilding</varname> is set to
|
<varname>enableParallelBuilding</varname> is set to
|
||||||
<literal>true</literal>, the builder passes the
|
<literal>true</literal>, the builder passes the
|
||||||
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
|
<option>-j<replaceable>N</replaceable></option> flag to GNU Make.
|
||||||
It can be overriden using the <option
|
It can be overridden using the <option
|
||||||
linkend='opt-cores'>--cores</option> command line switch and
|
linkend='opt-cores'>--cores</option> command line switch and
|
||||||
defaults to <literal>1</literal>. The value <literal>0</literal>
|
defaults to <literal>1</literal>. The value <literal>0</literal>
|
||||||
means that the builder should use all available CPU cores in the
|
means that the builder should use all available CPU cores in the
|
||||||
@@ -122,10 +134,10 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
<para>This option defines the maximum number of seconds that a
|
<para>This option defines the maximum number of seconds that a
|
||||||
builder can go without producing any data on standard output or
|
builder can go without producing any data on standard output or
|
||||||
standard error. This is useful (for instance in a automated
|
standard error. This is useful (for instance in an automated
|
||||||
build system) to catch builds that are stuck in an infinite
|
build system) to catch builds that are stuck in an infinite
|
||||||
loop, or to catch remote builds that are hanging due to network
|
loop, or to catch remote builds that are hanging due to network
|
||||||
problems. It can be overriden using the <option
|
problems. It can be overridden using the <option
|
||||||
linkend="opt-max-silent-time">--max-silent-time</option> command
|
linkend="opt-max-silent-time">--max-silent-time</option> command
|
||||||
line switch.</para>
|
line switch.</para>
|
||||||
|
|
||||||
@@ -136,15 +148,16 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
|
<varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|
||||||
<para>This option defines the maximum number of seconds that a
|
<para>This option defines the maximum number of seconds that a
|
||||||
builder can run. This is useful (for instance in a automated
|
builder can run. This is useful (for instance in an automated
|
||||||
build system) to catch builds that are stuck in an infinite loop
|
build system) to catch builds that are stuck in an infinite loop
|
||||||
but keep writing to their standard output or standard error. It
|
but keep writing to their standard output or standard error. It
|
||||||
can be overriden using the <option
|
can be overridden using the <option
|
||||||
linkend="opt-timeout">--timeout</option> command line
|
linkend="opt-timeout">--timeout</option> command line
|
||||||
switch.</para>
|
switch.</para>
|
||||||
|
|
||||||
@@ -156,6 +169,20 @@ env-keep-derivations = false
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry xml:id="conf-build-max-log-size"><term><literal>build-max-log-size</literal></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
|
||||||
|
<para>This option defines the maximum number of bytes that a
|
||||||
|
builder can write to its stdout/stderr. If the builder exceeds
|
||||||
|
this limit, it’s killed. A value of <literal>0</literal> (the
|
||||||
|
default) means that there is no limit.</para>
|
||||||
|
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
|
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
|
||||||
|
|
||||||
<listitem><para>This options specifies the Unix group containing
|
<listitem><para>This options specifies the Unix group containing
|
||||||
@@ -189,10 +216,8 @@ env-keep-derivations = false
|
|||||||
under the uid of the Nix process (that is, the uid of the caller
|
under the uid of the Nix process (that is, the uid of the caller
|
||||||
if <envar>NIX_REMOTE</envar> is empty, the uid under which the Nix
|
if <envar>NIX_REMOTE</envar> is empty, the uid under which the Nix
|
||||||
daemon runs if <envar>NIX_REMOTE</envar> is
|
daemon runs if <envar>NIX_REMOTE</envar> is
|
||||||
<literal>daemon</literal>, or the uid that owns the setuid
|
<literal>daemon</literal>). Obviously, this should not be used in
|
||||||
<command>nix-worker</command> program if <envar>NIX_REMOTE</envar>
|
multi-user settings with untrusted users.</para>
|
||||||
is <literal>slave</literal>). Obviously, this should not be used
|
|
||||||
in multi-user settings with untrusted users.</para>
|
|
||||||
|
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@@ -224,7 +249,27 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry xml:id="conf-build-chroot-dirs"><term><literal>build-chroot-dirs</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>When builds are performed in a chroot environment,
|
||||||
|
Nix will mount some directories from the normal file system
|
||||||
|
hierarchy inside the chroot. These are the Nix store, the
|
||||||
|
temporary build directory (usually
|
||||||
|
<filename>/tmp/nix-build-<replaceable>drvname</replaceable>-<replaceable>number</replaceable></filename>),
|
||||||
|
the <literal>/proc</literal> filesystem, and the directories
|
||||||
|
listed here. The default is <literal>/dev /dev/pts</literal>,
|
||||||
|
since these contain files needed by many builds (such as
|
||||||
|
<filename>/dev/null</filename>). You can use the syntax
|
||||||
|
<literal><replaceable>target</replaceable>=<replaceable>source</replaceable></literal>
|
||||||
|
to mount a path in a different location in the chroot; for
|
||||||
|
instance, <literal>/bin=/nix-bin</literal> will mount the
|
||||||
|
directory <literal>/nix-bin</literal> as <literal>/bin</literal>
|
||||||
|
inside the chroot.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><literal>build-use-substitutes</literal></term>
|
<varlistentry><term><literal>build-use-substitutes</literal></term>
|
||||||
|
|
||||||
<listitem><para>If set to <literal>true</literal> (default), Nix
|
<listitem><para>If set to <literal>true</literal> (default), Nix
|
||||||
@@ -233,34 +278,17 @@ env-keep-derivations = false
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry xml:id="conf-build-chroot-dirs"><term><literal>build-chroot-dirs</literal></term>
|
|
||||||
|
|
||||||
<listitem><para>When builds are performed in a chroot environment,
|
<varlistentry><term><literal>build-fallback</literal></term>
|
||||||
Nix will mount (using <command>mount --bind</command> on Linux)
|
|
||||||
some directories from the normal file system hierarchy inside the
|
|
||||||
chroot. These are the Nix store, the temporary build directory
|
|
||||||
(usually
|
|
||||||
<filename>/tmp/nix-<replaceable>pid</replaceable>-<replaceable>number</replaceable></filename>)
|
|
||||||
and the directories listed here. The default is <literal>dev
|
|
||||||
/proc</literal>. Files in <filename>/dev</filename> (such as
|
|
||||||
<filename>/dev/null</filename>) are needed by many builds, and
|
|
||||||
some files in <filename>/proc</filename> may also be needed
|
|
||||||
occasionally.</para>
|
|
||||||
|
|
||||||
<para>The value used on NixOS is
|
<listitem><para>If set to <literal>true</literal>, Nix will fall
|
||||||
|
back to building from source if a binary substitute fails. This
|
||||||
<programlisting>
|
is equivalent to the <option>--fallback</option> flag. The
|
||||||
build-use-chroot = /dev /proc /bin</programlisting>
|
default is <literal>false</literal>.</para></listitem>
|
||||||
|
|
||||||
to make the <filename>/bin/sh</filename> symlink available (which
|
|
||||||
is still needed by many builders).</para>
|
|
||||||
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><literal>build-cache-failures</literal></term>
|
<varlistentry><term><literal>build-cache-failures</literal></term>
|
||||||
|
|
||||||
<listitem><para>If set to <literal>true</literal>, Nix will
|
<listitem><para>If set to <literal>true</literal>, Nix will
|
||||||
@@ -276,6 +304,108 @@ build-use-chroot = /dev /proc /bin</programlisting>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>build-keep-log</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>If set to <literal>true</literal> (the default),
|
||||||
|
Nix will write the build log of a derivation (i.e. the standard
|
||||||
|
output and error of its builder) to the directory
|
||||||
|
<filename>/nix/var/log/nix/drvs</filename>. The build log can be
|
||||||
|
retrieved using the command <command>nix-store -l
|
||||||
|
<replaceable>path</replaceable></command>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>build-compress-log</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>If set to <literal>true</literal> (the default),
|
||||||
|
build logs written to <filename>/nix/var/log/nix/drvs</filename>
|
||||||
|
will be compressed on the fly using bzip2. Otherwise, they will
|
||||||
|
not be compressed.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>use-binary-caches</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>If set to <literal>true</literal> (the default),
|
||||||
|
Nix will check the binary caches specified by
|
||||||
|
<option>binary-caches</option> and related options to obtain
|
||||||
|
binary substitutes.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>binary-caches</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>A list of URLs of binary caches, separated by
|
||||||
|
whitespace. The default is
|
||||||
|
<literal>http://cache.nixos.org</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>binary-caches-files</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>A list of names of files that will be read to
|
||||||
|
obtain additional binary cache URLs. The default is
|
||||||
|
<literal>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/channels/binary-caches/*</literal>.
|
||||||
|
Note that when you’re using the Nix daemon,
|
||||||
|
<replaceable>username</replaceable> is always equal to
|
||||||
|
<literal>root</literal>, so Nix will only use the binary caches
|
||||||
|
provided by the channels installed by root. Do not set this
|
||||||
|
option to read files created by untrusted users!</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>trusted-binary-caches</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>A list of URLs of binary caches, separated by
|
||||||
|
whitespace. These are not used by default, but can be enabled by
|
||||||
|
users of the Nix daemon by specifying <literal>--option
|
||||||
|
binary-caches <replaceable>urls</replaceable></literal> on the
|
||||||
|
command line. Unprivileged users are only allowed to pass a
|
||||||
|
subset of the URLs listed in <literal>binary-caches</literal> and
|
||||||
|
<literal>trusted-binary-caches</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>extra-binary-caches</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>Additional binary caches appended to those
|
||||||
|
specified in <option>binary-caches</option> and
|
||||||
|
<option>binary-caches-files</option>. When used by unprivileged
|
||||||
|
users, untrusted binary caches (i.e. those not listed in
|
||||||
|
<option>trusted-binary-caches</option>) are silently
|
||||||
|
ignored.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>binary-caches-parallel-connections</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The maximum number of parallel HTTP connections
|
||||||
|
used by the binary cache substituter to get NAR info files. This
|
||||||
|
number should be high to minimise latency. It defaults to
|
||||||
|
150.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>force-manifest</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>If this option is set to <literal>false</literal>
|
||||||
|
(default) and a Nix channel provides both a manifest and a binary
|
||||||
|
cache, only the binary cache will be used. If set to
|
||||||
|
<literal>true</literal>, the manifest will be fetched as well.
|
||||||
|
This is useful if you want to use binary patches (which are
|
||||||
|
currently not supported by binary caches).</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><literal>system</literal></term>
|
<varlistentry><term><literal>system</literal></term>
|
||||||
|
|
||||||
<listitem><para>This option specifies the canonical Nix system
|
<listitem><para>This option specifies the canonical Nix system
|
||||||
@@ -306,10 +436,25 @@ build-use-chroot = /dev /proc /bin</programlisting>
|
|||||||
<literal>true</literal>.</para></listitem>
|
<literal>true</literal>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><literal>auto-optimise-store</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>If set to <literal>true</literal>, Nix
|
||||||
|
automatically detects files in the store that have identical
|
||||||
|
contents, and replaces them with hard links to a single copy.
|
||||||
|
This saves disk space. If set to <literal>false</literal> (the
|
||||||
|
default), you can still run <command>nix-store
|
||||||
|
--optimise</command> to get rid of duplicate
|
||||||
|
files.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
</section>
|
</refentry>
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
|||||||
|
|
||||||
<listitem><para>This variable should be set to
|
<listitem><para>This variable should be set to
|
||||||
<literal>daemon</literal> if you want to use the Nix daemon to
|
<literal>daemon</literal> if you want to use the Nix daemon to
|
||||||
executed Nix operations, which is necessary in <link
|
execute Nix operations. This is necessary in <link
|
||||||
linkend="ssec-multi-user">multi-user Nix installations</link>.
|
linkend="ssec-multi-user">multi-user Nix installations</link>.
|
||||||
Otherwise, it should be left unset.</para></listitem>
|
Otherwise, it should be left unset.</para></listitem>
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
|||||||
<varlistentry xml:id="envar-other-stores"><term><envar>NIX_OTHER_STORES</envar></term>
|
<varlistentry xml:id="envar-other-stores"><term><envar>NIX_OTHER_STORES</envar></term>
|
||||||
|
|
||||||
<listitem><para>This variable contains the paths of remote Nix
|
<listitem><para>This variable contains the paths of remote Nix
|
||||||
installations from whichs paths can be copied, separated by colons.
|
installations from which packages can be copied, separated by colons.
|
||||||
<phrase condition="manual">See <xref linkend="sec-sharing-packages"
|
<phrase condition="manual">See <xref linkend="sec-sharing-packages"
|
||||||
/> for details.</phrase> Each path should be the
|
/> for details.</phrase> Each path should be the
|
||||||
<filename>/nix</filename> directory of a remote Nix installation
|
<filename>/nix</filename> directory of a remote Nix installation
|
||||||
@@ -304,9 +304,9 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
|||||||
<literal>/var/run/nix/remote-stores</literal>.</para>
|
<literal>/var/run/nix/remote-stores</literal>.</para>
|
||||||
|
|
||||||
<para>Note that if you’re building through the <link
|
<para>Note that if you’re building through the <link
|
||||||
linkend="sec-nix-worker">Nix daemon</link>, the only setting for
|
linkend="sec-nix-daemon">Nix daemon</link>, the only setting for
|
||||||
this variable that matters is the one that the
|
this variable that matters is the one that the
|
||||||
<command>nix-worker</command> process uses. So if you want to
|
<command>nix-daemon</command> process uses. So if you want to
|
||||||
change it, you have to restart the daemon.</para></listitem>
|
change it, you have to restart the daemon.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
@@ -160,6 +160,18 @@
|
|||||||
</glossentry>
|
</glossentry>
|
||||||
|
|
||||||
|
|
||||||
|
<glossentry xml:id="gloss-nar"><glossterm>NAR</glossterm>
|
||||||
|
|
||||||
|
<glossdef><para>A <emphasis>N</emphasis>ix
|
||||||
|
<emphasis>AR</emphasis>chive. This is a serialisation of a path in
|
||||||
|
the Nix store. It can contain regular files, directories and
|
||||||
|
symbolic links. NARs are generated and unpacked using
|
||||||
|
<command>nix-store --dump</command> and <command>nix-store
|
||||||
|
--restore</command>.</para></glossdef>
|
||||||
|
|
||||||
|
</glossentry>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</glosslist>
|
</glosslist>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<appendix xmlns="http://docbook.org/ns/docbook"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xml:id="chap-hacking">
|
||||||
|
|
||||||
|
<title>Hacking</title>
|
||||||
|
|
||||||
|
<para>This section provides some notes on how to hack on Nix. To get
|
||||||
|
the latest version of Nix from GitHub:
|
||||||
|
<screen>
|
||||||
|
$ git clone git://github.com/NixOS/nix.git
|
||||||
|
$ cd hydra
|
||||||
|
</screen>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>To build it and its dependencies:
|
||||||
|
<screen>
|
||||||
|
$ nix-build release.nix -A build.x86_64-linux
|
||||||
|
</screen>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>To build all dependencies and start a shell in which all
|
||||||
|
environment variables are set up so that those dependencies can be
|
||||||
|
found:
|
||||||
|
<screen>
|
||||||
|
$ ./dev-shell
|
||||||
|
</screen>
|
||||||
|
To build Nix itself in this shell:
|
||||||
|
<screen>
|
||||||
|
[nix-shell]$ ./bootstrap
|
||||||
|
[nix-shell]$ configurePhase
|
||||||
|
[nix-shell]$ make
|
||||||
|
</screen>
|
||||||
|
To test it:
|
||||||
|
<screen>
|
||||||
|
[nix-shell]$ make install
|
||||||
|
[nix-shell]$ make installcheck
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</appendix>
|
||||||
+157
-103
@@ -40,11 +40,156 @@ platforms as well.</para>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<section><title>Obtaining Nix</title>
|
<section><title>Installing a binary distribution</title>
|
||||||
|
|
||||||
<para>The easiest way to obtain Nix is to download a <link
|
<para>The easiest way to install Nix is to use a binary package.
|
||||||
xlink:href="http://nixos.org/">source distribution</link>. RPMs
|
Binary packages of the latest stable release are available for Fedora,
|
||||||
for Red Hat, SuSE, and Fedora Core are also available.</para>
|
Debian, Ubuntu, Mac OS X and various other systems from the <link
|
||||||
|
xlink:href="http://nixos.org/nix/download.html">Nix homepage</link>.
|
||||||
|
You can also get builds of the latest development release from our
|
||||||
|
<link
|
||||||
|
xlink:href="http://hydra.nixos.org/view/nix/trunk/latest">continuous
|
||||||
|
build system</link>.</para>
|
||||||
|
|
||||||
|
<para>For Fedora, RPM packages are available. These can be installed
|
||||||
|
or upgraded using <command>rpm -U</command>. For example,
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ rpm -U nix-1.0-1.i386.rpm</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>For Debian and Ubuntu, you can download a Deb package and
|
||||||
|
install it like this:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ dpkg -i nix_1.0-1_amd64.deb</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>For other platforms, including Mac OS X (Darwin), FreeBSD and
|
||||||
|
other Linux distributions, you can download a binary tarball. It
|
||||||
|
contains Nix and all its dependencies. You should unpack it in the
|
||||||
|
root directory, then run <command>nix-finish-install</command>:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ cd /
|
||||||
|
$ tar xfj nix-1.1-x86_64-darwin.tar.bz2
|
||||||
|
$ nix-finish-install
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
After this you can delete
|
||||||
|
<filename>/usr/bin/nix-finish-install</filename>.</para>
|
||||||
|
|
||||||
|
<para>If you plan to use Nix from a single non-root user account, it’s
|
||||||
|
probably convenient to change the ownership of the entire Nix store
|
||||||
|
and database to that user account. In that case, install as follows:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
alice$ cd /
|
||||||
|
alice$ sudo tar xfj nix-1.1-x86_64-darwin.tar.bz2
|
||||||
|
alice$ sudo chown -R alice /nix
|
||||||
|
alice$ nix-finish-install
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>Nix can be uninstalled using <command>rpm -e nix</command> or
|
||||||
|
<command>dpkg -r nix</command> on RPM- and Dpkg-based systems,
|
||||||
|
respectively. After this you should manually remove the Nix store and
|
||||||
|
other auxiliary data, if desired:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ rm -rf /nix</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section><title>Installing Nix from source</title>
|
||||||
|
|
||||||
|
<para>If no binary package is available, you can download and compile
|
||||||
|
a source distribution.</para>
|
||||||
|
|
||||||
|
<section><title>Prerequisites</title>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem><para>GNU Make.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>A fairly recent version of GCC/G++. Version 2.95
|
||||||
|
and higher should work. Clang will also work.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>Perl 5.8 or higher.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para><command>pkg-config</command> to locate
|
||||||
|
dependencies. If your distribution does not provide it, you can get
|
||||||
|
it from <link
|
||||||
|
xlink:href="http://www.freedesktop.org/wiki/Software/pkg-config"
|
||||||
|
/>.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The bzip2 compressor program and the
|
||||||
|
<literal>libbz2</literal> library. Thus you must have bzip2
|
||||||
|
installed, including development headers and libraries. If your
|
||||||
|
distribution does not provide these, you can obtain bzip2 from <link
|
||||||
|
xlink:href="http://www.bzip.org/"/>.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The SQLite embedded database library, version 3.6.19
|
||||||
|
or higher. If your distribution does not provide it, please install
|
||||||
|
it from <link xlink:href="http://www.sqlite.org/" />.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The Perl DBI and DBD::SQLite libraries, which are
|
||||||
|
available from <link
|
||||||
|
xlink:href="http://search.cpan.org/">CPAN</link> if your
|
||||||
|
distribution does not provide them.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The <link
|
||||||
|
xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm
|
||||||
|
garbage collector</link> to reduce the evaluator’s memory
|
||||||
|
consumption (optional). To enable it, install
|
||||||
|
<literal>pkgconfig</literal> and the Boehm garbage collector, and
|
||||||
|
pass the flag <option>--enable-gc</option> to
|
||||||
|
<command>configure</command>.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The <command>xmllint</command> and
|
||||||
|
<command>xsltproc</command> programs to build this manual and the
|
||||||
|
man-pages. These are part of the <literal>libxml2</literal> and
|
||||||
|
<literal>libxslt</literal> packages, respectively. You also need
|
||||||
|
the <link
|
||||||
|
xlink:href="http://docbook.sourceforge.net/projects/xsl/">DocBook
|
||||||
|
XSL stylesheets</link> and optionally the <link
|
||||||
|
xlink:href="http://www.docbook.org/schemas/5x"> DocBook 5.0 RELAX NG
|
||||||
|
schemas</link>. Note that these are only required if you modify the
|
||||||
|
manual sources or when you are building from the Git
|
||||||
|
repository.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>Recent versions of Bison and Flex to build the
|
||||||
|
parser. (This is because Nix needs GLR support in Bison and
|
||||||
|
reentrancy support in Flex.) For Bison, you need version 2.6, which
|
||||||
|
can be obtained from the <link
|
||||||
|
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP
|
||||||
|
server</link>. For Flex, you need version 2.5.35, which is
|
||||||
|
available on <link
|
||||||
|
xlink:href="http://lex.sourceforge.net/">SourceForge</link>.
|
||||||
|
Slightly older versions may also work, but ancient versions like the
|
||||||
|
ubiquitous 2.5.4a won't. Note that these are only required if you
|
||||||
|
modify the parser or when you are building from the Git
|
||||||
|
repository.</para></listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section><title>Obtaining a source distribution</title>
|
||||||
|
|
||||||
|
<para>The source tarball of the most recent stable release can be
|
||||||
|
downloaded from the <link
|
||||||
|
xlink:href="http://nixos.org/nix/download.html">Nix homepage</link>.
|
||||||
|
You can also grab the <link
|
||||||
|
xlink:href="http://hydra.nixos.org/view/nix/trunk/latest/tarball/download-by-type/file/source-dist">most
|
||||||
|
recent development release</link>.</para>
|
||||||
|
|
||||||
<para>Alternatively, the most recent sources of Nix can be obtained
|
<para>Alternatively, the most recent sources of Nix can be obtained
|
||||||
from its <link
|
from its <link
|
||||||
@@ -63,71 +208,6 @@ repository.</para>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<section><title>Prerequisites</title>
|
|
||||||
|
|
||||||
<para><emphasis>The following prerequisites only apply when you build
|
|
||||||
from source</emphasis>. Binary releases (e.g., RPMs) have no
|
|
||||||
prerequisites.</para>
|
|
||||||
|
|
||||||
<para>A fairly recent version of GCC/G++ is required. Version 2.95
|
|
||||||
and higher should work. Clang will also work.</para>
|
|
||||||
|
|
||||||
<para>Nix requires Perl, version 5.8 or higher.</para>
|
|
||||||
|
|
||||||
<para>Nix requires <command>pkg-config</command> to locate its
|
|
||||||
dependencies. If your distribution does not provide it, you can get
|
|
||||||
it from <link
|
|
||||||
xlink:href="http://www.freedesktop.org/wiki/Software/pkg-config"
|
|
||||||
/>.</para>
|
|
||||||
|
|
||||||
<para>Nix requires the bzip2 compressor program and the
|
|
||||||
<literal>libbz2</literal> library. Thus you must have bzip2
|
|
||||||
installed, including development headers and libraries. If your
|
|
||||||
distribution does not provide these, you can obtain bzip2 from <link
|
|
||||||
xlink:href="http://www.bzip.org/"/>.</para>
|
|
||||||
|
|
||||||
<para>Nix requires the SQLite embedded database library, version
|
|
||||||
3.6.19 or higher. If your distribution does not provide it, please
|
|
||||||
install it from <link xlink:href="http://www.sqlite.org/" />.</para>
|
|
||||||
|
|
||||||
<para>Nix requires the Perl DBI and DBD::SQLite libraries, which are
|
|
||||||
available from <link xlink:href="http://search.cpan.org/">CPAN</link>
|
|
||||||
if your distribution does not provide them.</para>
|
|
||||||
|
|
||||||
<para>Nix can optionally use the <link
|
|
||||||
xlink:href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm
|
|
||||||
garbage collector</link> to reduce the evaluator’s memory consumption.
|
|
||||||
To enable it, install <literal>pkgconfig</literal> and the Boehm
|
|
||||||
garbage collector, and pass the flag <option>--enable-gc</option> to
|
|
||||||
<command>configure</command>.</para>
|
|
||||||
|
|
||||||
<para>To build this manual and the man-pages you need the
|
|
||||||
<command>xmllint</command> and <command>xsltproc</command> programs,
|
|
||||||
which are part of the <literal>libxml2</literal> and
|
|
||||||
<literal>libxslt</literal> packages, respectively. You also need the
|
|
||||||
<link
|
|
||||||
xlink:href="http://docbook.sourceforge.net/projects/xsl/">DocBook XSL
|
|
||||||
stylesheets</link> and optionally the <link
|
|
||||||
xlink:href="http://www.docbook.org/schemas/5x"> DocBook 5.0 RELAX NG
|
|
||||||
schemas</link>. Note that these are only required if you modify the
|
|
||||||
manual sources or when you are building from the Git
|
|
||||||
repository.</para>
|
|
||||||
|
|
||||||
<para>To build the parser, very <emphasis>recent</emphasis> versions
|
|
||||||
of Bison and Flex are required. (This is because Nix needs GLR
|
|
||||||
support in Bison and reentrancy support in Flex.) For Bison, you need
|
|
||||||
version 2.3 or higher (1.875 does <emphasis>not</emphasis> work),
|
|
||||||
which can be obtained from the <link
|
|
||||||
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP server</link>.
|
|
||||||
For Flex, you need version 2.5.33, which is available on <link
|
|
||||||
xlink:href="http://lex.sourceforge.net/">SourceForge</link>. Slightly
|
|
||||||
older versions may also work, but ancient versions like the ubiquitous
|
|
||||||
2.5.4a won't. Note that these are only required if you modify the
|
|
||||||
parser or when you are building from the Git repository.</para>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<section><title>Building Nix from source</title>
|
<section><title>Building Nix from source</title>
|
||||||
|
|
||||||
<para>After unpacking or checking out the Nix sources, issue the
|
<para>After unpacking or checking out the Nix sources, issue the
|
||||||
@@ -138,7 +218,8 @@ $ ./configure <replaceable>options...</replaceable>
|
|||||||
$ make
|
$ make
|
||||||
$ make install</screen>
|
$ make install</screen>
|
||||||
|
|
||||||
</para>
|
Nix requires GNU Make so you may need to invoke
|
||||||
|
<command>gmake</command> instead.</para>
|
||||||
|
|
||||||
<para>When building from the Git repository, these should be preceded
|
<para>When building from the Git repository, these should be preceded
|
||||||
by the command:
|
by the command:
|
||||||
@@ -180,33 +261,6 @@ options.</para>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<section><title>Installing a binary distribution</title>
|
|
||||||
|
|
||||||
<para>RPM and Deb packages of Nix for a number of different versions
|
|
||||||
of Fedora, openSUSE, Debian and Ubuntu can be downloaded from <link
|
|
||||||
xlink:href="http://nixos.org/" />. Once downloaded, the RPMs can be
|
|
||||||
installed or upgraded using <command>rpm -U</command>. For example,
|
|
||||||
|
|
||||||
<screen>
|
|
||||||
$ rpm -U nix-0.13pre18104-1.i386.rpm</screen>
|
|
||||||
|
|
||||||
Likewise, for a Deb package:
|
|
||||||
|
|
||||||
<screen>
|
|
||||||
$ dpkg -i nix_0.13pre18104-1_amd64.deb</screen>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>Nix can be uninstalled using <command>rpm -e nix</command> or
|
|
||||||
<command>dpkg -r nix</command>. After this you should manually remove
|
|
||||||
the Nix store and other auxiliary data, if desired:
|
|
||||||
|
|
||||||
<screen>
|
|
||||||
$ rm -rf /nix/store
|
|
||||||
$ rm -rf /nix/var</screen>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
@@ -357,11 +411,11 @@ $ chown -R root /nix/store /nix/var/nix</screen>
|
|||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>The <link linkend="sec-nix-worker">Nix daemon</link> should be
|
<para>The <link linkend="sec-nix-daemon">Nix daemon</link> should be
|
||||||
started as follows (as <literal>root</literal>):
|
started as follows (as <literal>root</literal>):
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-worker --daemon</screen>
|
$ nix-daemon</screen>
|
||||||
|
|
||||||
You’ll want to put that line somewhere in your system’s boot
|
You’ll want to put that line somewhere in your system’s boot
|
||||||
scripts.</para>
|
scripts.</para>
|
||||||
@@ -395,11 +449,11 @@ named anything. It should own the Nix store and database:
|
|||||||
<screen>
|
<screen>
|
||||||
$ chown -R nix /nix/store /nix/var/nix</screen>
|
$ chown -R nix /nix/store /nix/var/nix</screen>
|
||||||
|
|
||||||
and of course <command>nix-worker --daemon</command> should be started
|
and of course <command>nix-daemon</command> should be started under
|
||||||
under that user, e.g.,
|
that user, e.g.,
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ su - nix -c "exec /nix/bin/nix-worker --daemon"</screen>
|
$ su - nix -c "exec /nix/bin/nix-daemon"</screen>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -484,7 +538,7 @@ a symbolic link to the current <emphasis>user environment</emphasis>
|
|||||||
installed packages). The simplest way to set the required environment
|
installed packages). The simplest way to set the required environment
|
||||||
variables is to include the file
|
variables is to include the file
|
||||||
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
|
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
|
||||||
in your <filename>~/.bashrc</filename> (or similar), like this:</para>
|
in your <filename>~/.profile</filename> (or similar), like this:</para>
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
source <replaceable>prefix</replaceable>/etc/profile.d/nix.sh</screen>
|
source <replaceable>prefix</replaceable>/etc/profile.d/nix.sh</screen>
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ href="docs/papers.html#servicecm">SCM-12 paper</a>.</para>
|
|||||||
<simplesect><title>Portability</title>
|
<simplesect><title>Portability</title>
|
||||||
|
|
||||||
<para>Nix should run on most Unix systems, including Linux, FreeBSD and
|
<para>Nix should run on most Unix systems, including Linux, FreeBSD and
|
||||||
Mac OS X. It is also supported on Windows using Cygwin.</para>
|
Mac OS X.<!-- It is also supported on Windows using Cygwin.--></para>
|
||||||
|
|
||||||
</simplesect>
|
</simplesect>
|
||||||
|
|
||||||
|
|||||||
+15
-9
@@ -19,15 +19,15 @@
|
|||||||
</author>
|
</author>
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2004-2012</year>
|
<year>2004-2013</year>
|
||||||
<holder>Eelco Dolstra</holder>
|
<holder>Eelco Dolstra</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
<date>May 2012</date>
|
<date>July 2013</date>
|
||||||
|
|
||||||
</info>
|
</info>
|
||||||
|
|
||||||
|
|
||||||
<xi:include href="introduction.xml" />
|
<xi:include href="introduction.xml" />
|
||||||
<xi:include href="quick-start.xml" />
|
<xi:include href="quick-start.xml" />
|
||||||
<xi:include href="installation.xml" />
|
<xi:include href="installation.xml" />
|
||||||
@@ -40,18 +40,18 @@
|
|||||||
<title>Command Reference</title>
|
<title>Command Reference</title>
|
||||||
<xi:include href="opt-common.xml" />
|
<xi:include href="opt-common.xml" />
|
||||||
<xi:include href="env-common.xml" />
|
<xi:include href="env-common.xml" />
|
||||||
<xi:include href="conf-file.xml" />
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Main commands</title>
|
<title>Main commands</title>
|
||||||
<xi:include href="nix-env.xml" />
|
<xi:include href="nix-env.xml" />
|
||||||
<xi:include href="nix-instantiate.xml" />
|
<xi:include href="nix-instantiate.xml" />
|
||||||
<xi:include href="nix-store.xml" />
|
<xi:include href="nix-store.xml" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Utilities</title>
|
<title>Utilities</title>
|
||||||
<xi:include href="nix-build.xml" />
|
<xi:include href="nix-build.xml" />
|
||||||
|
<xi:include href="nix-shell.xml" />
|
||||||
<xi:include href="nix-channel.xml" />
|
<xi:include href="nix-channel.xml" />
|
||||||
<xi:include href="nix-collect-garbage.xml" />
|
<xi:include href="nix-collect-garbage.xml" />
|
||||||
<xi:include href="nix-copy-closure.xml" />
|
<xi:include href="nix-copy-closure.xml" />
|
||||||
@@ -60,7 +60,12 @@
|
|||||||
<xi:include href="nix-prefetch-url.xml" />
|
<xi:include href="nix-prefetch-url.xml" />
|
||||||
<xi:include href="nix-pull.xml" />
|
<xi:include href="nix-pull.xml" />
|
||||||
<xi:include href="nix-push.xml" />
|
<xi:include href="nix-push.xml" />
|
||||||
<xi:include href="nix-worker.xml" />
|
<xi:include href="nix-daemon.xml" />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Files</title>
|
||||||
|
<xi:include href="conf-file.xml" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</appendix>
|
</appendix>
|
||||||
@@ -68,11 +73,12 @@
|
|||||||
<xi:include href="troubleshooting.xml" />
|
<xi:include href="troubleshooting.xml" />
|
||||||
<!-- <xi:include href="bugs.xml" /> -->
|
<!-- <xi:include href="bugs.xml" /> -->
|
||||||
<xi:include href="glossary.xml" />
|
<xi:include href="glossary.xml" />
|
||||||
|
<xi:include href="hacking.xml" />
|
||||||
|
|
||||||
<appendix>
|
<appendix>
|
||||||
<title>Nix Release Notes</title>
|
<title>Nix Release Notes</title>
|
||||||
<xi:include href="release-notes.xml"
|
<xi:include href="release-notes.xml"
|
||||||
xpointer="xmlns(x=http://docbook.org/ns/docbook)xpointer(x:article/x:section)" />
|
xpointer="xmlns(x=http://docbook.org/ns/docbook)xpointer(x:article/x:section)" />
|
||||||
</appendix>
|
</appendix>
|
||||||
|
|
||||||
</book>
|
</book>
|
||||||
|
|||||||
+25
-52
@@ -38,11 +38,6 @@
|
|||||||
</group>
|
</group>
|
||||||
<replaceable>outlink</replaceable>
|
<replaceable>outlink</replaceable>
|
||||||
</arg>
|
</arg>
|
||||||
<arg>
|
|
||||||
<option>--run-env</option>
|
|
||||||
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
|
|
||||||
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
|
|
||||||
</arg>
|
|
||||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
@@ -75,13 +70,6 @@ a root of the Nix garbage collector. This root disappears
|
|||||||
automatically when the <filename>result</filename> symlink is deleted
|
automatically when the <filename>result</filename> symlink is deleted
|
||||||
or renamed. So don’t rename the symlink.</para></warning>
|
or renamed. So don’t rename the symlink.</para></warning>
|
||||||
|
|
||||||
<para>The subcommand <command>nix-build --run-env</command> will build
|
|
||||||
the dependencies of the derivation, but not the derivation itself. It
|
|
||||||
will then start an interactive shell in which all environment
|
|
||||||
variables defined by the derivation have been set to their
|
|
||||||
corresponding values. This is useful for reproducing the environment
|
|
||||||
of a derivation for development.</para>
|
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
@@ -96,7 +84,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
|
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Add a symlink named
|
<listitem><para>Add a symlink named
|
||||||
<replaceable>drvlink</replaceable> to the store derivation
|
<replaceable>drvlink</replaceable> to the store derivation
|
||||||
produced by <command>nix-instantiate</command>. The derivation is
|
produced by <command>nix-instantiate</command>. The derivation is
|
||||||
@@ -108,14 +96,14 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry><term><option>--add-drv-link</option></term>
|
<varlistentry><term><option>--add-drv-link</option></term>
|
||||||
|
|
||||||
<listitem><para>Shorthand for <option>--drv-link</option>
|
<listitem><para>Shorthand for <option>--drv-link</option>
|
||||||
<filename>./derivation</filename>.</para></listitem>
|
<filename>./derivation</filename>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry><term><option>--no-out-link</option></term>
|
<varlistentry><term><option>--no-out-link</option></term>
|
||||||
|
|
||||||
<listitem><para>Do not create a symlink to the output path. Note
|
<listitem><para>Do not create a symlink to the output path. Note
|
||||||
that as a result the output does not become a root of the garbage
|
that as a result the output does not become a root of the garbage
|
||||||
collector, and so might be deleted by <command>nix-store
|
collector, and so might be deleted by <command>nix-store
|
||||||
@@ -125,7 +113,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
|
|
||||||
<varlistentry xml:id='opt-out-link'><term><option>--out-link</option> /
|
<varlistentry xml:id='opt-out-link'><term><option>--out-link</option> /
|
||||||
<option>-o</option> <replaceable>outlink</replaceable></term>
|
<option>-o</option> <replaceable>outlink</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Change the name of the symlink to the output path
|
<listitem><para>Change the name of the symlink to the output path
|
||||||
created from <filename>result</filename> to
|
created from <filename>result</filename> to
|
||||||
<replaceable>outlink</replaceable>.</para></listitem>
|
<replaceable>outlink</replaceable>.</para></listitem>
|
||||||
@@ -134,32 +122,12 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
<para>The following common options are supported:</para>
|
||||||
|
|
||||||
<variablelist condition="manpage">
|
<variablelist condition="manpage">
|
||||||
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
|
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>The following options apply to <command>nix-build --run-env</command>.</para>
|
|
||||||
|
|
||||||
<variablelist>
|
|
||||||
|
|
||||||
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
|
|
||||||
|
|
||||||
<listitem><para>In the environment of the derivation, executeq the
|
|
||||||
command <replaceable>cmd</replaceable> instead of the default
|
|
||||||
interactive shell.</para></listitem>
|
|
||||||
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
|
|
||||||
|
|
||||||
<listitem><para>Do not build any dependencies whose store path
|
|
||||||
matches the regular expression <replaceable>regexp</replaceable>.
|
|
||||||
This option may be specified multiple times.</para></listitem>
|
|
||||||
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
@@ -176,20 +144,25 @@ lrwxrwxrwx <replaceable>...</replaceable> result -> /nix/store/d18hyl92g30l...
|
|||||||
$ ls ./result/bin/
|
$ ls ./result/bin/
|
||||||
firefox firefox-config</screen>
|
firefox firefox-config</screen>
|
||||||
|
|
||||||
<para>To build the dependencies of the package Pan, and start an
|
<para>If a derivation has multiple outputs,
|
||||||
interactive shell in which to build it:
|
<command>nix-build</command> will build the default (first) output.
|
||||||
|
You can also build all outputs:
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-build '<nixpkgs>' --run-env -A pan
|
$ nix-build '<nixpkgs>' -A openssl.all
|
||||||
$ tar xf $src
|
|
||||||
$ cd pan-*
|
|
||||||
$ ./configure
|
|
||||||
$ make
|
|
||||||
$ ./pan/gui/pan
|
|
||||||
</screen>
|
</screen>
|
||||||
|
This will create a symlink for each output named
|
||||||
</para>
|
<filename>result-<replaceable>outputname</replaceable></filename>.
|
||||||
|
The suffix is omitted if the output name is <literal>out</literal>.
|
||||||
|
So if <literal>openssl</literal> has outputs <literal>out</literal>,
|
||||||
|
<literal>bin</literal> and <literal>man</literal>,
|
||||||
|
<command>nix-build</command> will create symlinks
|
||||||
|
<literal>result</literal>, <literal>result-bin</literal> and
|
||||||
|
<literal>result-man</literal>. It’s also possible to build a specific
|
||||||
|
output:
|
||||||
|
<screen>
|
||||||
|
$ nix-build '<nixpkgs>' -A openssl.man
|
||||||
|
</screen>
|
||||||
|
This will create a symlink <literal>result-man</literal>.</para>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
@@ -201,6 +174,6 @@ $ ./pan/gui/pan
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ respectively.</para>
|
|||||||
<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para>
|
<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para>
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable
|
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable
|
||||||
$ nix-channel --update
|
$ nix-channel --update
|
||||||
$ nix-env -iA nixpkgs.hello</screen>
|
$ nix-env -iA nixpkgs.hello</screen>
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
<arg choice='plain'><option>--print-dead</option></arg>
|
<arg choice='plain'><option>--print-dead</option></arg>
|
||||||
<arg choice='plain'><option>--delete</option></arg>
|
<arg choice='plain'><option>--delete</option></arg>
|
||||||
</group>
|
</group>
|
||||||
|
<arg><option>--dry-run</option></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
<arg><option>--xz</option></arg>
|
<arg><option>--xz</option></arg>
|
||||||
<arg><option>--show-progress</option></arg>
|
<arg><option>--show-progress</option></arg>
|
||||||
<arg><option>--include-outputs</option></arg>
|
<arg><option>--include-outputs</option></arg>
|
||||||
|
<arg><option>--use-substitutes</option></arg>
|
||||||
|
<arg><option>-s</option></arg>
|
||||||
<arg choice='plain'>
|
<arg choice='plain'>
|
||||||
<replaceable>user@</replaceable><replaceable>machine</replaceable>
|
<replaceable>user@</replaceable><replaceable>machine</replaceable>
|
||||||
</arg>
|
</arg>
|
||||||
@@ -65,7 +67,7 @@ those paths. If this bothers you, use
|
|||||||
<refsection><title>Options</title>
|
<refsection><title>Options</title>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
<varlistentry><term><option>--to</option></term>
|
<varlistentry><term><option>--to</option></term>
|
||||||
|
|
||||||
<listitem><para>Copy the closure of
|
<listitem><para>Copy the closure of
|
||||||
@@ -119,10 +121,22 @@ those paths. If this bothers you, use
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry><term><option>--include-outputs</option></term>
|
<varlistentry><term><option>--include-outputs</option></term>
|
||||||
|
|
||||||
<listitem><para>Also copy the outputs of store derivations included
|
<listitem><para>Also copy the outputs of store derivations
|
||||||
in the closure.</para></listitem>
|
included in the closure.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--use-substitutes</option> / <option>-s</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Attempt to download missing paths on the target
|
||||||
|
machine using Nix’s substitute mechanism. Any paths that cannot
|
||||||
|
be substituted on the target are still copied normally from the
|
||||||
|
source. This is useful, for instance, if the connection between
|
||||||
|
the source and target machine is slow, but the connection between
|
||||||
|
the target machine and <literal>nixos.org</literal> (the default
|
||||||
|
binary cache server) is fast.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
@@ -140,7 +154,7 @@ those paths. If this bothers you, use
|
|||||||
<command>ssh</command> on the command line.</para></listitem>
|
<command>ssh</command> on the command line.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||||
xml:id="sec-nix-worker">
|
xml:id="sec-nix-daemon">
|
||||||
|
|
||||||
<refmeta>
|
<refmeta>
|
||||||
<refentrytitle>nix-worker</refentrytitle>
|
<refentrytitle>nix-daemon</refentrytitle>
|
||||||
<manvolnum>8</manvolnum>
|
<manvolnum>8</manvolnum>
|
||||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||||
</refmeta>
|
</refmeta>
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>nix-worker</refname>
|
<refname>nix-daemon</refname>
|
||||||
<refpurpose>Nix multi-user support daemon</refpurpose>
|
<refpurpose>Nix multi-user support daemon</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>nix-worker</command>
|
<command>nix-daemon</command>
|
||||||
<arg choice="plain"><option>--daemon</option></arg>
|
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
+32
-8
@@ -93,11 +93,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
|
|
||||||
<listitem><para>Specifies the profile to be used by those
|
<listitem><para>Specifies the profile to be used by those
|
||||||
operations that operate on a profile (designated below as the
|
operations that operate on a profile (designated below as the
|
||||||
<emphasis>active profile</emphasis>). A profile is sequence of
|
<emphasis>active profile</emphasis>). A profile is a sequence of
|
||||||
user environments called <emphasis>generations</emphasis>, one of
|
user environments called <emphasis>generations</emphasis>, one of
|
||||||
which is the <emphasis>current generation</emphasis>. The default
|
which is the <emphasis>current
|
||||||
profile is the target of the symbolic link
|
generation</emphasis>.</para></listitem>
|
||||||
<filename>~/.nix-profile</filename> (see below).</para></listitem>
|
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@@ -105,7 +104,8 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
|
|
||||||
<listitem><para>For the <option>--install</option>,
|
<listitem><para>For the <option>--install</option>,
|
||||||
<option>--upgrade</option>, <option>--uninstall</option>,
|
<option>--upgrade</option>, <option>--uninstall</option>,
|
||||||
<option>--switch-generation</option> and
|
<option>--switch-generation</option>,
|
||||||
|
<option>--delete-generations</option> and
|
||||||
<option>--rollback</option> operations, this flag will cause
|
<option>--rollback</option> operations, this flag will cause
|
||||||
<command>nix-env</command> to print what
|
<command>nix-env</command> to print what
|
||||||
<emphasis>would</emphasis> be done if this flag had not been
|
<emphasis>would</emphasis> be done if this flag had not been
|
||||||
@@ -209,6 +209,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
|||||||
<arg choice='plain'><option>--preserve-installed</option></arg>
|
<arg choice='plain'><option>--preserve-installed</option></arg>
|
||||||
<arg choice='plain'><option>-P</option></arg>
|
<arg choice='plain'><option>-P</option></arg>
|
||||||
</group>
|
</group>
|
||||||
|
<group choice='opt'>
|
||||||
|
<arg choice='plain'><option>--remove-all</option></arg>
|
||||||
|
<arg choice='plain'><option>-r</option></arg>
|
||||||
|
</group>
|
||||||
<arg choice='plain' rep='repeat'><replaceable>args</replaceable></arg>
|
<arg choice='plain' rep='repeat'><replaceable>args</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
|
|
||||||
@@ -272,7 +276,7 @@ number of possible ways:
|
|||||||
linkend="ss-functions">functions</link> that are called with the
|
linkend="ss-functions">functions</link> that are called with the
|
||||||
active Nix expression as their single argument. The derivations
|
active Nix expression as their single argument. The derivations
|
||||||
returned by those function calls are installed. This allows
|
returned by those function calls are installed. This allows
|
||||||
derivations to be specified in a unambiguous way, which is necessary
|
derivations to be specified in an unambiguous way, which is necessary
|
||||||
if there are multiple derivations with the same
|
if there are multiple derivations with the same
|
||||||
name.</para></listitem>
|
name.</para></listitem>
|
||||||
|
|
||||||
@@ -318,6 +322,16 @@ number of possible ways:
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--remove-all</option></term>
|
||||||
|
<term><option>-r</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Remove all previously installed packages first.
|
||||||
|
This is equivalent to running <literal>nix-env -e '*'</literal>
|
||||||
|
first, except that everything happens in a single
|
||||||
|
transaction.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
@@ -692,7 +706,7 @@ firefox-2.0.0.9 <lineannotation>(the current one)</lineannotation>
|
|||||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
||||||
installing `firefox-2.0.0.11'
|
installing `firefox-2.0.0.11'
|
||||||
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
|
||||||
Collission between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
|
collision between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
|
||||||
and `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.9/bin/firefox'.
|
and `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.9/bin/firefox'.
|
||||||
<lineannotation>(i.e., can’t have two active at the same time)</lineannotation>
|
<lineannotation>(i.e., can’t have two active at the same time)</lineannotation>
|
||||||
|
|
||||||
@@ -1244,7 +1258,7 @@ wrapper around <option>--list-generations</option> and
|
|||||||
$ nix-env --rollback
|
$ nix-env --rollback
|
||||||
switching from generation 92 to 91
|
switching from generation 92 to 91
|
||||||
|
|
||||||
$ nix-env --rolback
|
$ nix-env --rollback
|
||||||
error: no generation older than the current (91) exists</screen>
|
error: no generation older than the current (91) exists</screen>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
@@ -1255,6 +1269,16 @@ error: no generation older than the current (91) exists</screen>
|
|||||||
<refsection condition="manpage"><title>Environment variables</title>
|
<refsection condition="manpage"><title>Environment variables</title>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><envar>NIX_PROFILE</envar></term>
|
||||||
|
|
||||||
|
<listitem><para>Location of the Nix profile. Defaults to the
|
||||||
|
target of the symlink <filename>~/.nix-profile</filename>, if it
|
||||||
|
exists, or <filename>/nix/var/nix/profiles/default</filename>
|
||||||
|
otherwise.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
|
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,9 @@ cryptographic hash as <literal>nix-store --dump
|
|||||||
|
|
||||||
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
|
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Specify a cryptographic hash, which can be one of
|
<listitem><para>Use the specified cryptographic hash algorithm,
|
||||||
<literal>md5</literal>, <literal>sha1</literal>, and
|
which can be one of <literal>md5</literal>,
|
||||||
|
<literal>sha1</literal>, and
|
||||||
<literal>sha256</literal>.</para></listitem>
|
<literal>sha256</literal>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>nix-prefetch-url</command>
|
<command>nix-prefetch-url</command>
|
||||||
|
<arg><option>--type</option> <replaceable>hashAlgo</replaceable></arg>
|
||||||
<arg choice='plain'><replaceable>url</replaceable></arg>
|
<arg choice='plain'><replaceable>url</replaceable></arg>
|
||||||
<arg><replaceable>hash</replaceable></arg>
|
<arg><replaceable>hash</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
@@ -45,11 +46,6 @@ download it again when you build your Nix expression. Since
|
|||||||
as <command>nix-prefetch-url</command>, the redundant download can be
|
as <command>nix-prefetch-url</command>, the redundant download can be
|
||||||
avoided.</para>
|
avoided.</para>
|
||||||
|
|
||||||
<para>The environment variable <envar>NIX_HASH_ALGO</envar> specifies
|
|
||||||
which hash algorithm to use. It can be either <literal>md5</literal>,
|
|
||||||
<literal>sha1</literal>, or <literal>sha256</literal>. The default is
|
|
||||||
<literal>sha256</literal>.</para>
|
|
||||||
|
|
||||||
<para>If <replaceable>hash</replaceable> is specified, then a download
|
<para>If <replaceable>hash</replaceable> is specified, then a download
|
||||||
is not performed if the Nix store already contains a file with the
|
is not performed if the Nix store already contains a file with the
|
||||||
same hash and base name. Otherwise, the file is downloaded, and an
|
same hash and base name. Otherwise, the file is downloaded, and an
|
||||||
@@ -63,6 +59,24 @@ of the downloaded file in the Nix store is also printed.</para>
|
|||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<refsection><title>Options</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Use the specified cryptographic hash algorithm,
|
||||||
|
which can be one of <literal>md5</literal>,
|
||||||
|
<literal>sha1</literal>, and
|
||||||
|
<literal>sha256</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
<refsection><title>Examples</title>
|
<refsection><title>Examples</title>
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
|
|||||||
+345
-76
@@ -12,24 +12,20 @@
|
|||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>nix-push</refname>
|
<refname>nix-push</refname>
|
||||||
<refpurpose>push store paths onto a network cache</refpurpose>
|
<refpurpose>generate a binary cache</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>nix-push</command>
|
<command>nix-push</command>
|
||||||
<group choice='req'>
|
<arg choice='plain'><option>--dest</option> <replaceable>dest-dir</replaceable></arg>
|
||||||
<arg choice='req'>
|
<arg><option>--bzip2</option></arg>
|
||||||
<arg choice='plain'><replaceable>archivesPutURL</replaceable></arg>
|
<arg><option>--none</option></arg>
|
||||||
<arg choice='plain'><replaceable>archivesGetURL</replaceable></arg>
|
<arg><option>--force</option></arg>
|
||||||
<arg choice='plain'><replaceable>manifestPutURL</replaceable></arg>
|
<arg><option>--link</option></arg>
|
||||||
</arg>
|
<arg><option>--manifest</option></arg>
|
||||||
<arg choice='req'>
|
<arg><option>--manifest-path</option> <replaceable>filename</replaceable></arg>
|
||||||
<arg choice='plain'><option>--copy</option></arg>
|
<arg><option>--url-prefix</option> <replaceable>url</replaceable></arg>
|
||||||
<arg choice='plain'><replaceable>archivesDir</replaceable></arg>
|
|
||||||
<arg choice='plain'><replaceable>manifestFile</replaceable></arg>
|
|
||||||
</arg>
|
|
||||||
</group>
|
|
||||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
@@ -37,93 +33,366 @@
|
|||||||
|
|
||||||
<refsection><title>Description</title>
|
<refsection><title>Description</title>
|
||||||
|
|
||||||
<para>The command <command>nix-push</command> builds a set of store
|
<para>The command <command>nix-push</command> produces a
|
||||||
paths (if necessary), and then packages and uploads all store paths in
|
<emphasis>binary cache</emphasis>, a directory containing compressed
|
||||||
the resulting closures to a server. A network cache thus populated
|
Nix archives (NARs) plus some metadata of the closure of the specified
|
||||||
can subsequently be used to speed up software deployment on other
|
store paths. This directory can then be made available through a web
|
||||||
machines using the <command>nix-pull</command> command.</para>
|
server to other Nix installations, allowing them to skip building from
|
||||||
|
source and instead download binaries from the cache
|
||||||
|
automatically.</para>
|
||||||
|
|
||||||
<para><command>nix-push</command> performs the following actions.
|
<para><command>nix-push</command> performs the following actions.
|
||||||
|
|
||||||
<orderedlist>
|
<orderedlist>
|
||||||
|
|
||||||
<listitem><para>Each path in <replaceable>paths</replaceable> is
|
<listitem><para>Each path in <replaceable>paths</replaceable> is
|
||||||
realised (using <link
|
built (using <link
|
||||||
linkend='rsec-nix-store-realise'><literal>nix-store
|
linkend='rsec-nix-store-realise'><command>nix-store
|
||||||
--realise</literal></link>).</para></listitem>
|
--realise</command></link>).</para></listitem>
|
||||||
|
|
||||||
<listitem><para>All paths in the closure of the store expressions
|
<listitem><para>All paths in the closure of
|
||||||
stored in <replaceable>paths</replaceable> are determined (using
|
<replaceable>paths</replaceable> are determined (using
|
||||||
<literal>nix-store --query --requisites
|
<command>nix-store --query --requisites
|
||||||
--include-outputs</literal>). It should be noted that since the
|
--include-outputs</command>). Note that since the
|
||||||
<option>--include-outputs</option> flag is used, you get a combined
|
<option>--include-outputs</option> flag is used, if
|
||||||
source/binary distribution.</para></listitem>
|
<replaceable>paths</replaceable> includes a store derivation, you
|
||||||
|
get a combined source/binary distribution (e.g., source tarballs
|
||||||
|
will be included).</para></listitem>
|
||||||
|
|
||||||
<listitem><para>All store paths determined in the previous step are
|
<listitem><para>All store paths determined in the previous step are
|
||||||
packaged and compressed into a <command>bzip</command>ped NAR
|
packaged into a NAR (using <command>nix-store --dump</command>) and
|
||||||
archive (extension <filename>.nar.bz2</filename>).</para></listitem>
|
compressed using <command>xz</command> or <command>bzip2</command>.
|
||||||
|
The resulting files have the extension <filename>.nar.xz</filename>
|
||||||
|
or <filename>.nar.bz2</filename>. Also for each store path, Nix
|
||||||
|
generates a file with extension <filename>.narinfo</filename>
|
||||||
|
containing metadata such as the references, cryptographic hash and
|
||||||
|
size of each path.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>A <emphasis>manifest</emphasis> is created that
|
<listitem><para>Optionally, a single <emphasis>manifest</emphasis>
|
||||||
contains information on the store paths, their eventual URLs in the
|
file is created that contains the same metadata as the
|
||||||
cache, and cryptographic hashes of the contents of the NAR
|
<filename>.narinfo</filename> files. This is for compatibility with
|
||||||
archives.</para></listitem>
|
Nix versions prior to 1.2 (see <command>nix-pull</command> for
|
||||||
|
details).</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Each store path is uploaded to the remote directory
|
<listitem><para>A file named <option>nix-cache-info</option> is
|
||||||
specified by <replaceable>archivesPutURL</replaceable>. HTTP PUT
|
placed in the destination directory. The existence of this file
|
||||||
requests are used to do this. However, before a file
|
marks the directory as a binary cache.</para></listitem>
|
||||||
<varname>x</varname> is uploaded to
|
|
||||||
<literal><replaceable>archivesPutURL</replaceable>/</literal><varname>x</varname>,
|
|
||||||
<command>nix-push</command> first determines whether this upload is
|
|
||||||
unnecessary by issuing a HTTP HEAD request on
|
|
||||||
<literal><replaceable>archivesGetURL</replaceable>/</literal><varname>x</varname>.
|
|
||||||
This allows a cache to be shared between many partially overlapping
|
|
||||||
<command>nix-push</command> invocations. (We use two URLs because
|
|
||||||
the upload URL typically refers to a CGI script, while the download
|
|
||||||
URL just refers to a file system directory on the
|
|
||||||
server.)</para></listitem>
|
|
||||||
|
|
||||||
<listitem><para>The manifest is uploaded using an HTTP PUT request
|
|
||||||
to <replaceable>manifestPutURL</replaceable>. The corresponding
|
|
||||||
URL to download the manifest can then be used by
|
|
||||||
<command>nix-pull</command>.</para></listitem>
|
|
||||||
|
|
||||||
</orderedlist>
|
</orderedlist>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!--
|
</refsection>
|
||||||
<para>TODO: <option>- -copy</option></para>
|
|
||||||
-->
|
|
||||||
|
<refsection><title>Options</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--dest</option> <replaceable>dest-dir</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Set the destination directory to
|
||||||
|
<replaceable>dir</replaceable>, which is created if it does not
|
||||||
|
exist. This flag is required.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--bzip2</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Compress NARs using <command>bzip2</command>
|
||||||
|
instead of <command>xz -9</command>. The latter compresses about
|
||||||
|
30% better on typical archives, decompresses about twice as fast,
|
||||||
|
but compresses a lot slower and is not supported by Nix prior to
|
||||||
|
version 1.2.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--none</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Do not compress NARs.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--force</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Overwrite <filename>.narinfo</filename> files if
|
||||||
|
they already exist.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--link</option></term>
|
||||||
|
|
||||||
|
<listitem><para>By default, NARs are generated in the Nix store
|
||||||
|
and then copied to <replaceable>dest-dir</replaceable>. If this
|
||||||
|
option is given, hard links are used instead. This only works if
|
||||||
|
<replaceable>dest-dir</replaceable> is on the same filesystem as
|
||||||
|
the Nix store.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--manifest</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Force the generation of a manifest suitable for
|
||||||
|
use by <command>nix-pull</command>. The manifest is stored as
|
||||||
|
<filename><replaceable>dest-dir</replaceable>/MANIFEST</filename>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--manifest-path</option> <replaceable>filename</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Like <option>--manifest</option>, but store the
|
||||||
|
manifest in <replaceable>filename</replaceable>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--url-prefix</option> <replaceable>url</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Manifests are expected to contain the absolute
|
||||||
|
URLs of NARs. For generating these URLs, the prefix
|
||||||
|
<replaceable>url</replaceable> is used. It defaults to
|
||||||
|
<uri>file://<replaceable>dest-dir</replaceable></uri>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
<refsection><title>Examples</title>
|
<refsection><title>Examples</title>
|
||||||
|
|
||||||
<para>To upload files there typically is some CGI script on the server
|
<para>To add the closure of Thunderbird to a binary cache:
|
||||||
side. This script should be be protected with a password. The
|
|
||||||
following example uploads the store paths resulting from building the
|
|
||||||
Nix expressions in <filename>foo.nix</filename>, passing appropriate
|
|
||||||
authentication information:
|
|
||||||
|
|
||||||
<screen>
|
|
||||||
$ nix-push \
|
|
||||||
http://foo@bar:server.domain/cgi-bin/upload.pl/cache \
|
|
||||||
http://server.domain/cache \
|
|
||||||
http://foo@bar:server.domain/cgi-bin/upload.pl/MANIFEST \
|
|
||||||
$(nix-instantiate foo.nix)</screen>
|
|
||||||
|
|
||||||
This will push both sources and binaries (and any build-time
|
|
||||||
dependencies used in the build, such as compilers).</para>
|
|
||||||
|
|
||||||
<para>If we just want to push binaries, not sources and build-time
|
|
||||||
dependencies, we can do:
|
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-push <replaceable>urls</replaceable> $(nix-store -r $(nix-instantiate foo.nix))</screen>
|
$ nix-push --dest /tmp/cache $(nix-build -A thunderbird)
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
Assuming that <filename>/tmp/cache</filename> is exported by a web
|
||||||
|
server as <uri>http://example.org/cache</uri>, you can then use this
|
||||||
|
cache on another machine to speed up the installation of Thunderbird:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-build -A thunderbird --option binary-caches http://example.org/cache
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
Alternatively, you could add <literal>binary-caches =
|
||||||
|
http://example.org/cache</literal> to
|
||||||
|
<filename>nix.conf</filename>.</para>
|
||||||
|
|
||||||
|
<para>To also include build-time dependencies (such as source
|
||||||
|
tarballs):
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-push --dest /tmp/cache $(nix-instantiate -A thunderbird)
|
||||||
|
</screen>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>To generate a manifest suitable for <command>nix-pull</command>:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-push --dest /tmp/cache $(nix-build -A thunderbird) --manifest
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
On another machine you can then do:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-pull http://example.org/cache
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
to cause the binaries to be used by subsequent Nix operations.</para>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<refsection><title>Binary cache format and operation</title>
|
||||||
|
|
||||||
|
<para>A binary cache with URL <replaceable>url</replaceable> only
|
||||||
|
denotes a valid binary cache if the file
|
||||||
|
<uri><replaceable>url</replaceable>/nix-cache-info</uri> exists. If
|
||||||
|
this file does not exist (or cannot be downloaded), the cache is
|
||||||
|
ignored. If it does exist, it must be a text file containing cache
|
||||||
|
properties. Here’s an example:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
StoreDir: /nix/store
|
||||||
|
WantMassQuery: 1
|
||||||
|
Priority: 10
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
The properties that are currently supported are:
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>StoreDir</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The path of the Nix store to which this binary
|
||||||
|
cache applies. Binaries are not relocatable — a binary built for
|
||||||
|
<filename>/nix/store</filename> won’t generally work in
|
||||||
|
<filename>/home/alice/store</filename> — so to prevent binaries
|
||||||
|
from being used in a wrong store, a binary cache is only used if
|
||||||
|
its <literal>StoreDir</literal> matches the local Nix
|
||||||
|
configuration. The default is
|
||||||
|
<filename>/nix/store</filename>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>WantMassQuery</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>Query operations such as <command>nix-env
|
||||||
|
-qas</command> can cause thousands of cache queries, and thus
|
||||||
|
thousands of HTTP requests, to determine which packages are
|
||||||
|
available in binary form. While these requests are small, not
|
||||||
|
every server may appreciate a potential onslaught of queries. If
|
||||||
|
<literal>WantMassQuery</literal> is set to <literal>0</literal>
|
||||||
|
(default), “mass queries” such as <command>nix-env -qas</command>
|
||||||
|
will skip this cache. Thus a package may appear not to have a
|
||||||
|
binary substitute. However, the binary will still be used when
|
||||||
|
you actually install the package. If
|
||||||
|
<literal>WantMassQuery</literal> is set to <literal>1</literal>,
|
||||||
|
mass queries will use this cache.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>Priority</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>Each binary cache has a priority (defaulting to
|
||||||
|
50). Binary caches are checked for binaries in order of ascending
|
||||||
|
priority; thus a higher number denotes a lower priority. The
|
||||||
|
binary cache <uri>http://cache.nixos.org</uri> has priority
|
||||||
|
40.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>Every time Nix needs to build some store path
|
||||||
|
<replaceable>p</replaceable>, it will check each configured binary
|
||||||
|
cache to see if it has a NAR file for <replaceable>p</replaceable>,
|
||||||
|
until it finds one. If no cache has a NAR, Nix will fall back to
|
||||||
|
building the path from source (if applicable). To see if a cache with
|
||||||
|
URL <replaceable>url</replaceable> has a binary for
|
||||||
|
<replaceable>p</replaceable>, Nix fetches
|
||||||
|
<replaceable>url/h</replaceable>, where <replaceable>h</replaceable>
|
||||||
|
is the hash part of <replaceable>p</replaceable>. Thus, if we have a
|
||||||
|
cache <uri>http://cache.nixos.org</uri> and we want to obtain
|
||||||
|
the store path
|
||||||
|
<screen>
|
||||||
|
/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
|
||||||
|
</screen>
|
||||||
|
then Nix will attempt to fetch
|
||||||
|
<screen>
|
||||||
|
http://cache.nixos.org/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
|
||||||
|
</screen>
|
||||||
|
(Commands such as <command>nix-env -qas</command> will issue an HTTP
|
||||||
|
HEAD request, since it only needs to know if the
|
||||||
|
<filename>.narinfo</filename> file exists.) The
|
||||||
|
<filename>.narinfo</filename> file is a simple text file that looks
|
||||||
|
like this:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
StorePath: /nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
|
||||||
|
URL: nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
|
||||||
|
Compression: bzip2
|
||||||
|
FileHash: sha256:0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70
|
||||||
|
FileSize: 24473768
|
||||||
|
NarHash: sha256:0s491y1h9hxj5ghiizlxk7ax6jwbha00zwn7lpyd5xg5bhf60vzg
|
||||||
|
NarSize: 109521136
|
||||||
|
References: 2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16 ...
|
||||||
|
Deriver: 7akyyc87ka32xwmqza9dvyg5pwx3j212-glibc-2.7.drv
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
The fields are as follows:
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>StorePath</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The full store path, including the name part
|
||||||
|
(e.g., <literal>glibc-2.7</literal>). It must match the
|
||||||
|
requested store path.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>URL</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The URL of the NAR, relative to the binary cache
|
||||||
|
URL.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>Compression</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The compression method; either
|
||||||
|
<literal>xz</literal> or
|
||||||
|
<literal>bzip2</literal>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>FileHash</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The SHA-256 hash of the compressed
|
||||||
|
NAR.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>FileSize</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The size of the compressed NAR.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>NarHash</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The SHA-256 hash of the uncompressed NAR. This is
|
||||||
|
equal to the hash of the store path as returned by
|
||||||
|
<command>nix-store -q --hash
|
||||||
|
<replaceable>p</replaceable></command>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>NarSize</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The size of the uncompressed NAR.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>References</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The references of the store path, without the Nix
|
||||||
|
store prefix.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>Deriver</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The deriver of the store path, without the Nix
|
||||||
|
store prefix. This field is optional.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><literal>System</literal></term>
|
||||||
|
|
||||||
|
<listitem><para>The Nix platform type of this binary, if known.
|
||||||
|
This field is optional.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>Thus, in our example, after recursively ensuring that the
|
||||||
|
references exist (e.g.,
|
||||||
|
<filename>/nix/store/2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16</filename>),
|
||||||
|
Nix will fetch <screen>
|
||||||
|
http://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
|
||||||
|
</screen> and decompress and unpack it to
|
||||||
|
<filename>/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7</filename>.</para>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||||
|
xml:id="sec-nix-shell">
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>nix-shell</refentrytitle>
|
||||||
|
<manvolnum>1</manvolnum>
|
||||||
|
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||||
|
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>nix-shell</refname>
|
||||||
|
<refpurpose>start an interactive shell based on a Nix expression</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>nix-shell</command>
|
||||||
|
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
|
||||||
|
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||||
|
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||||
|
<arg>
|
||||||
|
<group choice='req'>
|
||||||
|
<arg choice='plain'><option>--attr</option></arg>
|
||||||
|
<arg choice='plain'><option>-A</option></arg>
|
||||||
|
</group>
|
||||||
|
<replaceable>attrPath</replaceable>
|
||||||
|
</arg>
|
||||||
|
<arg><option>--command</option> <replaceable>cmd</replaceable></arg>
|
||||||
|
<arg><option>--exclude</option> <replaceable>regexp</replaceable></arg>
|
||||||
|
<arg><option>--pure</option></arg>
|
||||||
|
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsection><title>Description</title>
|
||||||
|
|
||||||
|
<para>The command <command>nix-shell</command> will build
|
||||||
|
the dependencies of the specified derivation, but not the derivation
|
||||||
|
itself. It will then start an interactive shell in which all
|
||||||
|
environment variables defined by the derivation have been set to their
|
||||||
|
corresponding values, and the script <literal>$stdenv/setup</literal>
|
||||||
|
has been sourced. This is useful for reproducing the environment of a
|
||||||
|
derivation for development.</para>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<refsection><title>Options</title>
|
||||||
|
|
||||||
|
<para>All options not listed here are passed to <command>nix-store
|
||||||
|
--realise</command>, except for <option>--arg</option> and
|
||||||
|
<option>--attr</option> / <option>-A</option> which are passed to
|
||||||
|
<command>nix-instantiate</command>. <phrase condition="manual">See
|
||||||
|
also <xref linkend="sec-common-options" />.</phrase></para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--command</option> <replaceable>cmd</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>In the environment of the derivation, run the
|
||||||
|
shell command <replaceable>cmd</replaceable> instead of starting
|
||||||
|
an interactive shell. However, if you end the shell command with
|
||||||
|
<literal>return</literal>, you still get an interactive shell.
|
||||||
|
This can be useful for doing any additional
|
||||||
|
initialisation.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--exclude</option> <replaceable>regexp</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Do not build any dependencies whose store path
|
||||||
|
matches the regular expression <replaceable>regexp</replaceable>.
|
||||||
|
This option may be specified multiple times.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--pure</option></term>
|
||||||
|
|
||||||
|
<listitem><para>If this flag is specified, the environment is
|
||||||
|
almost entirely cleared before the interactive shell is started,
|
||||||
|
so you get an environment that more closely corresponds to the
|
||||||
|
“real” Nix build. A few variables, in particular
|
||||||
|
<envar>HOME</envar>, <envar>USER</envar> and
|
||||||
|
<envar>DISPLAY</envar>, are retained. Note that
|
||||||
|
<filename>~/.bashrc</filename> and (depending on your Bash
|
||||||
|
installation) <filename>/etc/bashrc</filename> are still sourced,
|
||||||
|
so any variables set there will affect the interactive
|
||||||
|
shell.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<para>The following common options are supported:</para>
|
||||||
|
|
||||||
|
<variablelist condition="manpage">
|
||||||
|
<xi:include href="opt-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='opt-common']/*)" />
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<refsection><title>Examples</title>
|
||||||
|
|
||||||
|
<para>To build the dependencies of the package Pan, and start an
|
||||||
|
interactive shell in which to build it:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-shell '<nixpkgs>' -A pan
|
||||||
|
$ unpackPhase
|
||||||
|
$ cd pan-*
|
||||||
|
$ configurePhase
|
||||||
|
$ buildPhase
|
||||||
|
$ ./pan/gui/pan
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
To clear the environment first, and do some additional automatic
|
||||||
|
initialisation of the interactive shell:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-shell '<nixpkgs>' -A pan --pure \
|
||||||
|
--command 'export NIX_DEBUG=1; export NIX_CORES=8; return'
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<refsection condition="manpage"><title>Environment variables</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<xi:include href="env-common.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(//db:variablelist[@xml:id='env-common']/*)" />
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
</refentry>
|
||||||
+84
-11
@@ -164,7 +164,7 @@ the specified store paths. Realisation is a somewhat overloaded term:
|
|||||||
exist in the file system). If the path is already valid, we are
|
exist in the file system). If the path is already valid, we are
|
||||||
done immediately. Otherwise, the path and any missing paths in its
|
done immediately. Otherwise, the path and any missing paths in its
|
||||||
closure may be produced through substitutes. If there are no
|
closure may be produced through substitutes. If there are no
|
||||||
(succesful) subsitutes, realisation fails.</para></listitem>
|
(successful) subsitutes, realisation fails.</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
@@ -174,10 +174,26 @@ the specified store paths. Realisation is a somewhat overloaded term:
|
|||||||
output. (For non-derivations argument, the argument itself is
|
output. (For non-derivations argument, the argument itself is
|
||||||
printed.)</para>
|
printed.)</para>
|
||||||
|
|
||||||
<para>If the <option>--dry-run</option> option is used, then
|
<para>The following flags are available:</para>
|
||||||
<command>nix-store</command> will print on standard error a
|
|
||||||
description of what packages would be built or downloaded, and then
|
<variablelist>
|
||||||
quit.</para>
|
|
||||||
|
<varlistentry><term><option>--dry-run</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Print on standard error a description of what
|
||||||
|
packages would be built or downloaded, without actually performing
|
||||||
|
the operation.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--ignore-unknown</option></term>
|
||||||
|
|
||||||
|
<listitem><para>If a non-derivation path does not have a
|
||||||
|
substitute, then silently ignore it.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
@@ -773,6 +789,7 @@ $ nix-store --add ./foo.c
|
|||||||
<command>nix-store</command>
|
<command>nix-store</command>
|
||||||
<arg choice='plain'><option>--verify</option></arg>
|
<arg choice='plain'><option>--verify</option></arg>
|
||||||
<arg><option>--check-contents</option></arg>
|
<arg><option>--check-contents</option></arg>
|
||||||
|
<arg><option>--repair</option></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
@@ -785,7 +802,7 @@ automatically repaired. Inconsistencies are generally the result of
|
|||||||
the Nix store or database being modified by non-Nix tools, or of bugs
|
the Nix store or database being modified by non-Nix tools, or of bugs
|
||||||
in Nix itself.</para>
|
in Nix itself.</para>
|
||||||
|
|
||||||
<para>There is one option:
|
<para>This operation has the following options:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
@@ -800,6 +817,16 @@ in Nix itself.</para>
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry><term><option>--repair</option></term>
|
||||||
|
|
||||||
|
<listitem><para>If any valid path is missing from the store, or
|
||||||
|
(if <option>--check-contents</option> is given) the contents of a
|
||||||
|
valid path has been modified, then try to repair the path by
|
||||||
|
redownloading it. See <command>nix-store --repair-path</command>
|
||||||
|
for details.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
@@ -825,7 +852,7 @@ in Nix itself.</para>
|
|||||||
|
|
||||||
<refsection><title>Description</title>
|
<refsection><title>Description</title>
|
||||||
|
|
||||||
<para>The operation <option>--verify-paths</option> compares the
|
<para>The operation <option>--verify-path</option> compares the
|
||||||
contents of the given store paths to their cryptographic hashes stored
|
contents of the given store paths to their cryptographic hashes stored
|
||||||
in Nix’s database. For every changed path, it prints a warning
|
in Nix’s database. For every changed path, it prints a warning
|
||||||
message. The exit status is 0 if no path has changed, and 1
|
message. The exit status is 0 if no path has changed, and 1
|
||||||
@@ -848,6 +875,52 @@ $ nix-store --verify-path $(nix-store -qR $(which svn))
|
|||||||
</refsection>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
<!--######################################################################-->
|
||||||
|
|
||||||
|
<refsection><title>Operation <option>--repair-path</option></title>
|
||||||
|
|
||||||
|
<refsection>
|
||||||
|
<title>Synopsis</title>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>nix-store</command>
|
||||||
|
<arg choice='plain'><option>--repair-path</option></arg>
|
||||||
|
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
<refsection><title>Description</title>
|
||||||
|
|
||||||
|
<para>The operation <option>--repair-path</option> attempts to
|
||||||
|
“repair” the specified paths by redownloading them using the available
|
||||||
|
substituters. If no substitutes are available, then repair is not
|
||||||
|
possible.</para>
|
||||||
|
|
||||||
|
<warning><para>During repair, there is a very small time window during
|
||||||
|
which the old path (if it exists) is moved out of the way and replaced
|
||||||
|
with the new path. If repair is interrupted in between, then the
|
||||||
|
system may be left in a broken state (e.g., if the path contains a
|
||||||
|
critical system component like the GNU C Library).</para></warning>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
<refsection><title>Example</title>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-store --verify-path /nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13
|
||||||
|
path `/nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13' was modified!
|
||||||
|
expected hash `2db57715ae90b7e31ff1f2ecb8c12ec1cc43da920efcbe3b22763f36a1861588',
|
||||||
|
got `481c5aa5483ebc97c20457bb8bca24deea56550d3985cda0027f67fe54b808e4'
|
||||||
|
|
||||||
|
$ nix-store --repair-path /nix/store/dj7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13
|
||||||
|
fetching path `/nix/store/d7a81wsm1ijwwpkks3725661h3263p5-glibc-2.13'...
|
||||||
|
…
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
<!--######################################################################-->
|
<!--######################################################################-->
|
||||||
|
|
||||||
<refsection xml:id='refsec-nix-store-dump'><title>Operation <option>--dump</option></title>
|
<refsection xml:id='refsec-nix-store-dump'><title>Operation <option>--dump</option></title>
|
||||||
@@ -1169,9 +1242,9 @@ variable <envar>_args</envar>.</para>
|
|||||||
$ nix-store --print-env $(nix-instantiate '<nixpkgs>' -A firefox)
|
$ nix-store --print-env $(nix-instantiate '<nixpkgs>' -A firefox)
|
||||||
<replaceable>…</replaceable>
|
<replaceable>…</replaceable>
|
||||||
export src; src='/nix/store/plpj7qrwcz94z2psh6fchsi7s8yihc7k-firefox-12.0.source.tar.bz2'
|
export src; src='/nix/store/plpj7qrwcz94z2psh6fchsi7s8yihc7k-firefox-12.0.source.tar.bz2'
|
||||||
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnm-stdenv'
|
export stdenv; stdenv='/nix/store/7c8asx3yfrg5dg1gzhzyq2236zfgibnn-stdenv'
|
||||||
export system; system='x86_64-linux'
|
export system; system='x86_64-linux'
|
||||||
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh'
|
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25c-default-builder.sh'
|
||||||
</screen>
|
</screen>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
@@ -1246,8 +1319,8 @@ paths.</para>
|
|||||||
<refsection><title>Example</title>
|
<refsection><title>Example</title>
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-store --clear-failed-path /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
|
$ nix-store --clear-failed-paths /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
|
||||||
$ nix-store --clear-failed-path *
|
$ nix-store --clear-failed-paths *
|
||||||
</screen>
|
</screen>
|
||||||
|
|
||||||
</refsection>
|
</refsection>
|
||||||
|
|||||||
@@ -37,6 +37,11 @@
|
|||||||
<option>-I</option>
|
<option>-I</option>
|
||||||
<replaceable>path</replaceable>
|
<replaceable>path</replaceable>
|
||||||
</arg>
|
</arg>
|
||||||
|
<arg>
|
||||||
|
<option>--option</option>
|
||||||
|
<replaceable>name</replaceable>
|
||||||
|
<replaceable>value</replaceable>
|
||||||
|
</arg>
|
||||||
<sbr />
|
<sbr />
|
||||||
|
|
||||||
</nop>
|
</nop>
|
||||||
|
|||||||
@@ -181,7 +181,7 @@
|
|||||||
from, say, a network repository. If the repository is down, the
|
from, say, a network repository. If the repository is down, the
|
||||||
realisation of the derivation will fail. When this option is
|
realisation of the derivation will fail. When this option is
|
||||||
specified, Nix will build the derivation instead. Thus,
|
specified, Nix will build the derivation instead. Thus,
|
||||||
installation from binaries falls back on nstallation from source.
|
installation from binaries falls back on installation from source.
|
||||||
This option is not the default since it is generally not desirable
|
This option is not the default since it is generally not desirable
|
||||||
for a transient failure in obtaining the substitutes to lead to a
|
for a transient failure in obtaining the substitutes to lead to a
|
||||||
full build from source (with the related consumption of
|
full build from source (with the related consumption of
|
||||||
@@ -236,7 +236,7 @@
|
|||||||
interpreted by the <command>nix-log2xml</command> tool in the
|
interpreted by the <command>nix-log2xml</command> tool in the
|
||||||
Nix source distribution. The resulting XML file can be fed into
|
Nix source distribution. The resulting XML file can be fed into
|
||||||
the <command>log2html.xsl</command> stylesheet to create an HTML
|
the <command>log2html.xsl</command> stylesheet to create an HTML
|
||||||
file that can be browsed interactively, using Javascript to
|
file that can be browsed interactively, using JavaScript to
|
||||||
expand and collapse parts of the output.</para></listitem>
|
expand and collapse parts of the output.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -337,20 +337,42 @@
|
|||||||
|
|
||||||
<listitem><para>Causes Nix to print out a stack trace in case of Nix
|
<listitem><para>Causes Nix to print out a stack trace in case of Nix
|
||||||
expression evaluation errors.</para></listitem>
|
expression evaluation errors.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><option>-I</option> <replaceable>path</replaceable></term>
|
<varlistentry><term><option>-I</option> <replaceable>path</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Add a path to the Nix expression search path. See
|
<listitem><para>Add a path to the Nix expression search path. This
|
||||||
the <envar>NIX_PATH</envar> environment variable for details. Paths
|
option may be given multiple times. See the <envar>NIX_PATH</envar>
|
||||||
added through <option>-I</option> take precedence over
|
environment variable for information on the semantics of the Nix
|
||||||
<envar>NIX_PATH</envar>.</para></listitem>
|
search path. Paths added through <option>-I</option> take
|
||||||
|
precedence over <envar>NIX_PATH</envar>.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><option>--option</option> <replaceable>name</replaceable> <replaceable>value</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Set the Nix configuration option
|
||||||
|
<replaceable>name</replaceable> to <replaceable>value</replaceable>.
|
||||||
|
This overrides settings in the Nix configuration file (see
|
||||||
|
<citerefentry><refentrytitle>nix.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry><term><option>--repair</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Fix corrupted or missing store paths by
|
||||||
|
redownloading or rebuilding them. Note that this is slow because it
|
||||||
|
requires computing a cryptographic hash of the contents of every
|
||||||
|
path in the closure of the build. Also note the warning under
|
||||||
|
<command>nix-store --repair-path</command>.</para></listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ downloading binaries from <systemitem
|
|||||||
class='fqdomainname'>nixos.org</systemitem>, instead of building
|
class='fqdomainname'>nixos.org</systemitem>, instead of building
|
||||||
them from source. This might still take a while since all
|
them from source. This might still take a while since all
|
||||||
dependencies must be downloaded, but on a reasonably fast connection
|
dependencies must be downloaded, but on a reasonably fast connection
|
||||||
such as an DSL line it’s on the order of a few minutes.</para>
|
such as a DSL line it’s on the order of a few minutes.</para>
|
||||||
|
|
||||||
<para>Naturally, packages can also be uninstalled:
|
<para>Naturally, packages can also be uninstalled:
|
||||||
|
|
||||||
@@ -175,21 +175,6 @@ upgrading `coreutils-5.0' to `coreutils-5.2.1'</screen>
|
|||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>If you grow bored of specifying the Nix expressions using
|
|
||||||
<parameter>-f</parameter> all the time, you can set a default
|
|
||||||
location:
|
|
||||||
|
|
||||||
<screen>
|
|
||||||
$ nix-env -I nixpkgs-<replaceable>version</replaceable></screen>
|
|
||||||
|
|
||||||
After this you can just say, for instance, <literal>nix-env -u
|
|
||||||
'*'</literal>.<footnote><para>Setting a default using
|
|
||||||
<parameter>-I</parameter> currently clashes with using Nix channels,
|
|
||||||
since <literal>nix-channel --update</literal> calls <literal>nix-env
|
|
||||||
-I</literal> to set the default to the Nix expressions it downloaded
|
|
||||||
from the channel, replacing whatever default you had
|
|
||||||
set.</para></footnote></para>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
@@ -240,7 +225,7 @@ uses is to create directory trees of symlinks to
|
|||||||
themselves (though automatically generated by
|
themselves (though automatically generated by
|
||||||
<command>nix-env</command>), so they too reside in the Nix store. For
|
<command>nix-env</command>), so they too reside in the Nix store. For
|
||||||
instance, in <xref linkend='fig-user-environments' /> the user
|
instance, in <xref linkend='fig-user-environments' /> the user
|
||||||
environment <filename>/nix/store/5mq2jcn36ldl...-user-env</filename>
|
environment <filename>/nix/store/0c1p5z4kda11...-user-env</filename>
|
||||||
contains a symlink to just Subversion 1.1.2 (arrows in the figure
|
contains a symlink to just Subversion 1.1.2 (arrows in the figure
|
||||||
indicate symlinks). This would be what we would obtain if we had done
|
indicate symlinks). This would be what we would obtain if we had done
|
||||||
|
|
||||||
@@ -458,7 +443,7 @@ URL.</para>
|
|||||||
<command>nix-channel --add</command>, e.g.,
|
<command>nix-channel --add</command>, e.g.,
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
|
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable</screen>
|
||||||
|
|
||||||
subscribes you to a channel that always contains that latest version
|
subscribes you to a channel that always contains that latest version
|
||||||
of the Nix Packages collection. (Instead of
|
of the Nix Packages collection. (Instead of
|
||||||
@@ -553,7 +538,7 @@ dependencies) to a file, and then unpack that file into another Nix
|
|||||||
store. For example,
|
store. For example,
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-store --export $(type -p firefox) > firefox.closure</screen>
|
$ nix-store --export $(nix-store -qR $(type -p firefox)) > firefox.closure</screen>
|
||||||
|
|
||||||
writes the closure of Firefox to a file. You can then copy this file
|
writes the closure of Firefox to a file. You can then copy this file
|
||||||
to another machine and install the closure:
|
to another machine and install the closure:
|
||||||
@@ -567,7 +552,7 @@ another command, e.g. to copy and install a closure directly to/on
|
|||||||
another machine:
|
another machine:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-store --export $(type -p firefox) | bzip2 | \
|
$ nix-store --export $(nix-store -qR $(type -p firefox)) | bzip2 | \
|
||||||
ssh alice@itchy.example.org "bunzip2 | nix-store --import"</screen>
|
ssh alice@itchy.example.org "bunzip2 | nix-store --import"</screen>
|
||||||
|
|
||||||
But note that <command>nix-copy-closure</command> is generally more
|
But note that <command>nix-copy-closure</command> is generally more
|
||||||
@@ -598,7 +583,7 @@ $ nix-env -i firefox</screen>
|
|||||||
and Nix has to build a path that it sees is already present in
|
and Nix has to build a path that it sees is already present in
|
||||||
<filename>/mnt/nix</filename>, then it will just copy from there
|
<filename>/mnt/nix</filename>, then it will just copy from there
|
||||||
instead of building it from source.</para>
|
instead of building it from source.</para>
|
||||||
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ to the following chapters.</para>
|
|||||||
<listitem><para>Download a source tarball or RPM or Debian/Ubuntu
|
<listitem><para>Download a source tarball or RPM or Debian/Ubuntu
|
||||||
package from <link xlink:href='http://nixos.org/'/>. Build source
|
package from <link xlink:href='http://nixos.org/'/>. Build source
|
||||||
distributions using the regular sequence:
|
distributions using the regular sequence:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
|
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
|
||||||
|
$ cd nix-<replaceable>version</replaceable>
|
||||||
$ ./configure
|
$ ./configure
|
||||||
$ make
|
$ make
|
||||||
$ make install <lineannotation>(as root)</lineannotation></screen>
|
$ make install <lineannotation>(as root)</lineannotation></screen>
|
||||||
@@ -35,13 +36,13 @@ changed using
|
|||||||
|
|
||||||
<listitem><para>You should add
|
<listitem><para>You should add
|
||||||
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
|
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
|
||||||
to your <filename>~/.bashrc</filename> (or some other login
|
to your <filename>~/.profile</filename> (or some other login
|
||||||
file).</para></listitem>
|
file).</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Subscribe to the Nix Packages channel.
|
<listitem><para>Subscribe to the Nix Packages channel.
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
|
$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable</screen>
|
||||||
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ libxslt-1.1.0
|
|||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Install some packages from the channel:
|
<listitem><para>Install some packages from the channel:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
|
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ $ firefox
|
|||||||
<lineannotation>(read Slashdot or something)</lineannotation></screen>
|
<lineannotation>(read Slashdot or something)</lineannotation></screen>
|
||||||
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Uninstall a package:
|
<listitem><para>Uninstall a package:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
|
|||||||
@@ -6,6 +6,516 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.6.0"><title>Release 1.6.0 (September 10, 2013)</title>
|
||||||
|
|
||||||
|
<para>In addition to the usual bug fixes, this release has several new
|
||||||
|
features:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The command <command>nix-build --run-env</command> has been
|
||||||
|
renamed to <command>nix-shell</command>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><command>nix-shell</command> now sources
|
||||||
|
<filename>$stdenv/setup</filename> <emphasis>inside</emphasis> the
|
||||||
|
interactive shell, rather than in a parent shell. This ensures
|
||||||
|
that shell functions defined by <literal>stdenv</literal> can be
|
||||||
|
used in the interactive shell.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><command>nix-shell</command> has a new flag
|
||||||
|
<option>--pure</option> to clear the environment, so you get an
|
||||||
|
environment that more closely corresponds to the “real” Nix build.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><command>nix-shell</command> now sets the shell prompt
|
||||||
|
(<envar>PS1</envar>) to ensure that Nix shells are distinguishable
|
||||||
|
from your regular shells.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><command>nix-env</command> no longer requires a
|
||||||
|
<literal>*</literal> argument to match all packages, so
|
||||||
|
<literal>nix-env -qa</literal> is equivalent to <literal>nix-env
|
||||||
|
-qa '*'</literal>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><command>nix-env -i</command> has a new flag
|
||||||
|
<option>--remove-all</option> (<option>-r</option>) to remove all
|
||||||
|
previous packages from the profile. This makes it easier to do
|
||||||
|
declarative package management similar to NixOS’s
|
||||||
|
<option>environment.systemPackages</option>. For instance, if you
|
||||||
|
have a specification <filename>my-packages.nix</filename> like this:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
with import <nixpkgs> {};
|
||||||
|
[ thunderbird
|
||||||
|
geeqie
|
||||||
|
...
|
||||||
|
]
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
then after any change to this file, you can run:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ nix-env -f my-packages.nix -ir
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
to update your profile to match the specification.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The ‘<literal>with</literal>’ language construct is now more
|
||||||
|
lazy. It only evaluates its argument if a variable might actually
|
||||||
|
refer to an attribute in the argument. For instance, this now
|
||||||
|
works:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
let
|
||||||
|
pkgs = with pkgs; { foo = "old"; bar = foo; } // overrides;
|
||||||
|
overrides = { foo = "new"; };
|
||||||
|
in pkgs.bar
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
This evaluates to <literal>"new"</literal>, while previously it
|
||||||
|
gave an “infinite recursion” error.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Nix now has proper integer arithmetic operators. For
|
||||||
|
instance, you can write <literal>x + y</literal> instead of
|
||||||
|
<literal>builtins.add x y</literal>, or <literal>x <
|
||||||
|
y</literal> instead of <literal>builtins.lessThan x y</literal>.
|
||||||
|
The comparison operators also work on strings.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>On 64-bit systems, Nix integers are now 64 bits rather than
|
||||||
|
32 bits.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>When using the Nix daemon, the <command>nix-daemon</command>
|
||||||
|
worker process now runs on the same CPU as the client, on systems
|
||||||
|
that support setting CPU affinity. This gives a significant speedup
|
||||||
|
on some systems.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>If a stack overflow occurs in the Nix evaluator, you now get
|
||||||
|
a proper error message (rather than “Segmentation fault”) on some
|
||||||
|
systems.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>In addition to directories, you can now bind-mount regular
|
||||||
|
files in chroots through the (now misnamed) option
|
||||||
|
<option>build-chroot-dirs</option>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>This release has contributions from Domen Kožar, Eelco Dolstra,
|
||||||
|
Florian Friesdorf, Gergely Risko, Ivan Kozik, Ludovic Courtès and Shea
|
||||||
|
Levy.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.5.3"><title>Release 1.5.3 (June 17, 2013)</title>
|
||||||
|
|
||||||
|
<para>This is primarily a bug fix release. The following changes are
|
||||||
|
noteworthy:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Yet another security bug involving hard links to files
|
||||||
|
outside the store was fixed. This bug only affected multi-user
|
||||||
|
installations that do not have hard link restrictions
|
||||||
|
enabled. (NixOS is thus not vulnerable.)</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The default binary cache URL has changed from
|
||||||
|
<uri>http://nixos.org/binary-cache</uri> to
|
||||||
|
<uri>http://cache.nixos.org</uri>. The latter is hosted on Amazon
|
||||||
|
CloudFront (courtesy of <link
|
||||||
|
xlink:href="http://www.logicblox.com/">LogicBlox</link>) and
|
||||||
|
should provide better performance for users in both Europe and
|
||||||
|
North America.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The binary cache substituter now prints a warning message if
|
||||||
|
fetching information from the cache takes more than five seconds.
|
||||||
|
Thus network or server problems no longer make Nix appear to just
|
||||||
|
hang.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Stack traces now show function names, e.g.
|
||||||
|
<screen>
|
||||||
|
while evaluating `concatMapStrings' at `<replaceable>...</replaceable>/nixpkgs/pkgs/lib/strings.nix:18:25':
|
||||||
|
</screen>
|
||||||
|
Also, if a function is called with an unexpected argument, Nix
|
||||||
|
now shows the name of the argument.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.5.2"><title>Release 1.5.2 (May 13, 2013)</title>
|
||||||
|
|
||||||
|
<para>This is primarily a bug fix release. It has contributions from
|
||||||
|
Eelco Dolstra, Lluís Batlle i Rossell and Shea Levy.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.5.1"><title>Release 1.5.1 (February 28, 2013)</title>
|
||||||
|
|
||||||
|
<para>The bug fix to the bug fix had a bug itself, of course. But
|
||||||
|
this time it will work for sure!</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.5"><title>Release 1.5 (February 27, 2013)</title>
|
||||||
|
|
||||||
|
<para>This is a brown paper bag release to fix a regression introduced
|
||||||
|
by the hard link security fix in 1.4.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.4"><title>Release 1.4 (February 26, 2013)</title>
|
||||||
|
|
||||||
|
<para>This release fixes a security bug in multi-user operation. It
|
||||||
|
was possible for derivations to cause the mode of files outside of the
|
||||||
|
Nix store to be changed to 444 (read-only but world-readable) by
|
||||||
|
creating hard links to those files (<link
|
||||||
|
xlink:href="https://github.com/NixOS/nix/commit/5526a282b5b44e9296e61e07d7d2626a79141ac4">details</link>).</para>
|
||||||
|
|
||||||
|
<para>There are also the following improvements:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem><para>New built-in function:
|
||||||
|
<function>builtins.hashString</function>.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>Build logs are now stored in
|
||||||
|
<filename>/nix/var/log/nix/drvs/<replaceable>XX</replaceable>/</filename>,
|
||||||
|
where <replaceable>XX</replaceable> is the first two characters of
|
||||||
|
the derivation. This is useful on machines that keep a lot of build
|
||||||
|
logs (such as Hydra servers).</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The function <function>corepkgs/fetchurl</function>
|
||||||
|
can now make the downloaded file executable. This will allow
|
||||||
|
getting rid of all bootstrap binaries in the Nixpkgs source
|
||||||
|
tree.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>Language change: The expression <literal>"${./path}
|
||||||
|
..."</literal> now evaluates to a string instead of a
|
||||||
|
path.</para></listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 4, 2013)</title>
|
||||||
|
|
||||||
|
<para>This is primarily a bug fix release. When this version is first
|
||||||
|
run on Linux, it removes any immutable bits from the Nix store and
|
||||||
|
increases the schema version of the Nix store. (The previous release
|
||||||
|
removed support for setting the immutable bit; this release clears any
|
||||||
|
remaining immutable bits to make certain operations more
|
||||||
|
efficient.)</para>
|
||||||
|
|
||||||
|
<para>This release has contributions from Eelco Dolstra and Stuart
|
||||||
|
Pernsteiner.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.2"><title>Release 1.2 (December 6, 2012)</title>
|
||||||
|
|
||||||
|
<para>This release has the following improvements and changes:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Nix has a new binary substituter mechanism: the
|
||||||
|
<emphasis>binary cache</emphasis>. A binary cache contains
|
||||||
|
pre-built binaries of Nix packages. Whenever Nix wants to build a
|
||||||
|
missing Nix store path, it will check a set of binary caches to
|
||||||
|
see if any of them has a pre-built binary of that path. The
|
||||||
|
configuration setting <option>binary-caches</option> contains a
|
||||||
|
list of URLs of binary caches. For instance, doing
|
||||||
|
<screen>
|
||||||
|
$ nix-env -i thunderbird --option binary-caches http://cache.nixos.org
|
||||||
|
</screen>
|
||||||
|
will install Thunderbird and its dependencies, using the available
|
||||||
|
pre-built binaries in <uri>http://cache.nixos.org</uri>.
|
||||||
|
The main advantage over the old “manifest”-based method of getting
|
||||||
|
pre-built binaries is that you don’t have to worry about your
|
||||||
|
manifest being in sync with the Nix expressions you’re installing
|
||||||
|
from; i.e., you don’t need to run <command>nix-pull</command> to
|
||||||
|
update your manifest. It’s also more scalable because you don’t
|
||||||
|
need to redownload a giant manifest file every time.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>A Nix channel can provide a binary cache URL that will be
|
||||||
|
used automatically if you subscribe to that channel. If you use
|
||||||
|
the Nixpkgs or NixOS channels
|
||||||
|
(<uri>http://nixos.org/channels</uri>) you automatically get the
|
||||||
|
cache <uri>http://cache.nixos.org</uri>.</para>
|
||||||
|
|
||||||
|
<para>Binary caches are created using <command>nix-push</command>.
|
||||||
|
For details on the operation and format of binary caches, see the
|
||||||
|
<command>nix-push</command> manpage. More details are provided in
|
||||||
|
<link xlink:href="http://lists.science.uu.nl/pipermail/nix-dev/2012-September/009826.html">this
|
||||||
|
nix-dev posting</link>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Multiple output support should now be usable. A derivation
|
||||||
|
can declare that it wants to produce multiple store paths by
|
||||||
|
saying something like
|
||||||
|
<programlisting>
|
||||||
|
outputs = [ "lib" "headers" "doc" ];
|
||||||
|
</programlisting>
|
||||||
|
This will cause Nix to pass the intended store path of each output
|
||||||
|
to the builder through the environment variables
|
||||||
|
<literal>lib</literal>, <literal>headers</literal> and
|
||||||
|
<literal>doc</literal>. Other packages can refer to a specific
|
||||||
|
output by referring to
|
||||||
|
<literal><replaceable>pkg</replaceable>.<replaceable>output</replaceable></literal>,
|
||||||
|
e.g.
|
||||||
|
<programlisting>
|
||||||
|
buildInputs = [ pkg.lib pkg.headers ];
|
||||||
|
</programlisting>
|
||||||
|
If you install a package with multiple outputs using
|
||||||
|
<command>nix-env</command>, each output path will be symlinked
|
||||||
|
into the user environment.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Dashes are now valid as part of identifiers and attribute
|
||||||
|
names.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The new operation <command>nix-store --repair-path</command>
|
||||||
|
allows corrupted or missing store paths to be repaired by
|
||||||
|
redownloading them. <command>nix-store --verify --check-contents
|
||||||
|
--repair</command> will scan and repair all paths in the Nix
|
||||||
|
store. Similarly, <command>nix-env</command>,
|
||||||
|
<command>nix-build</command>, <command>nix-instantiate</command>
|
||||||
|
and <command>nix-store --realise</command> have a
|
||||||
|
<option>--repair</option> flag to detect and fix bad paths by
|
||||||
|
rebuilding or redownloading them.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Nix no longer sets the immutable bit on files in the Nix
|
||||||
|
store. Instead, the recommended way to guard the Nix store
|
||||||
|
against accidental modification on Linux is to make it a read-only
|
||||||
|
bind mount, like this:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
$ mount --bind /nix/store /nix/store
|
||||||
|
$ mount -o remount,ro,bind /nix/store
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
Nix will automatically make <filename>/nix/store</filename>
|
||||||
|
writable as needed (using a private mount namespace) to allow
|
||||||
|
modifications.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Store optimisation (replacing identical files in the store
|
||||||
|
with hard links) can now be done automatically every time a path
|
||||||
|
is added to the store. This is enabled by setting the
|
||||||
|
configuration option <literal>auto-optimise-store</literal> to
|
||||||
|
<literal>true</literal> (disabled by default).</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Nix now supports <command>xz</command> compression for NARs
|
||||||
|
in addition to <command>bzip2</command>. It compresses about 30%
|
||||||
|
better on typical archives and decompresses about twice as
|
||||||
|
fast.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Basic Nix expression evaluation profiling: setting the
|
||||||
|
environment variable <envar>NIX_COUNT_CALLS</envar> to
|
||||||
|
<literal>1</literal> will cause Nix to print how many times each
|
||||||
|
primop or function was executed.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>New primops: <varname>concatLists</varname>,
|
||||||
|
<varname>elem</varname>, <varname>elemAt</varname> and
|
||||||
|
<varname>filter</varname>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The command <command>nix-copy-closure</command> has a new
|
||||||
|
flag <option>--use-substitutes</option> (<option>-s</option>) to
|
||||||
|
download missing paths on the target machine using the substitute
|
||||||
|
mechanism.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The command <command>nix-worker</command> has been renamed
|
||||||
|
to <command>nix-daemon</command>. Support for running the Nix
|
||||||
|
worker in “slave” mode has been removed.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The <option>--help</option> flag of every Nix command now
|
||||||
|
invokes <command>man</command>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Chroot builds are now supported on systemd machines.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>This release has contributions from Eelco Dolstra, Florian
|
||||||
|
Friesdorf, Mats Erik Andersson and Shea Levy.</para>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-1.1"><title>Release 1.1 (July 18, 2012)</title>
|
||||||
|
|
||||||
|
<para>This release has the following improvements:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>On Linux, when doing a chroot build, Nix now uses various
|
||||||
|
namespace features provided by the Linux kernel to improve
|
||||||
|
build isolation. Namely:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>The private network namespace ensures that
|
||||||
|
builders cannot talk to the outside world (or vice versa): each
|
||||||
|
build only sees a private loopback interface. This also means
|
||||||
|
that two concurrent builds can listen on the same port (e.g. as
|
||||||
|
part of a test) without conflicting with each
|
||||||
|
other.</para></listitem>
|
||||||
|
<listitem><para>The PID namespace causes each build to start as
|
||||||
|
PID 1. Processes outside of the chroot are not visible to those
|
||||||
|
on the inside. On the other hand, processes inside the chroot
|
||||||
|
<emphasis>are</emphasis> visible from the outside (though with
|
||||||
|
different PIDs).</para></listitem>
|
||||||
|
<listitem><para>The IPC namespace prevents the builder from
|
||||||
|
communicating with outside processes using SysV IPC mechanisms
|
||||||
|
(shared memory, message queues, semaphores). It also ensures
|
||||||
|
that all IPC objects are destroyed when the builder
|
||||||
|
exits.</para></listitem>
|
||||||
|
<listitem><para>The UTS namespace ensures that builders see a
|
||||||
|
hostname of <literal>localhost</literal> rather than the actual
|
||||||
|
hostname.</para></listitem>
|
||||||
|
<listitem><para>The private mount namespace was already used by
|
||||||
|
Nix to ensure that the bind-mounts used to set up the chroot are
|
||||||
|
cleaned up automatically.</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Build logs are now compressed using
|
||||||
|
<command>bzip2</command>. The command <command>nix-store
|
||||||
|
-l</command> decompresses them on the fly. This can be disabled
|
||||||
|
by setting the option <literal>build-compress-log</literal> to
|
||||||
|
<literal>false</literal>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>The creation of build logs in
|
||||||
|
<filename>/nix/var/log/nix/drvs</filename> can be disabled by
|
||||||
|
setting the new option <literal>build-keep-log</literal> to
|
||||||
|
<literal>false</literal>. This is useful, for instance, for Hydra
|
||||||
|
build machines.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Nix now reserves some space in
|
||||||
|
<filename>/nix/var/nix/db/reserved</filename> to ensure that the
|
||||||
|
garbage collector can run successfully if the disk is full. This
|
||||||
|
is necessary because SQLite transactions fail if the disk is
|
||||||
|
full.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Added a basic <function>fetchurl</function> function. This
|
||||||
|
is not intended to replace the <function>fetchurl</function> in
|
||||||
|
Nixpkgs, but is useful for bootstrapping; e.g., it will allow us
|
||||||
|
to get rid of the bootstrap binaries in the Nixpkgs source tree
|
||||||
|
and download them instead. You can use it by doing
|
||||||
|
<literal>import <nix/fetchurl.nix> { url =
|
||||||
|
<replaceable>url</replaceable>; sha256 =
|
||||||
|
"<replaceable>hash</replaceable>"; }</literal>. (Shea Levy)</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Improved RPM spec file. (Michel Alexandre Salim)</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Support for on-demand socket-based activation in the Nix
|
||||||
|
daemon with <command>systemd</command>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>Added a manpage for
|
||||||
|
<citerefentry><refentrytitle>nix.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>When using the Nix daemon, the <option>-s</option> flag in
|
||||||
|
<command>nix-env -qa</command> is now much faster.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<!--==================================================================-->
|
<!--==================================================================-->
|
||||||
|
|
||||||
<section xml:id="ssec-relnotes-1.0"><title>Release 1.0 (May 11, 2012)</title>
|
<section xml:id="ssec-relnotes-1.0"><title>Release 1.0 (May 11, 2012)</title>
|
||||||
@@ -936,7 +1446,7 @@ irreversible.</para></warning>
|
|||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
<listitem><para>You can now unambigously specify which derivation to
|
<listitem><para>You can now unambiguously specify which derivation to
|
||||||
build or install in <command>nix-env</command>,
|
build or install in <command>nix-env</command>,
|
||||||
<command>nix-instantiate</command> and <command>nix-build</command>
|
<command>nix-instantiate</command> and <command>nix-build</command>
|
||||||
using the <option>--attr</option> / <option>-A</option> flags, which
|
using the <option>--attr</option> / <option>-A</option> flags, which
|
||||||
@@ -1076,7 +1586,7 @@ irreversible.</para></warning>
|
|||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem><para>Make sure that the garbage collector can run
|
<listitem><para>Make sure that the garbage collector can run
|
||||||
succesfully when the disk is full
|
successfully when the disk is full
|
||||||
(<literal>NIX-18</literal>).</para></listitem>
|
(<literal>NIX-18</literal>).</para></listitem>
|
||||||
|
|
||||||
<listitem><para><command>nix-env</command> now locks the profile
|
<listitem><para><command>nix-env</command> now locks the profile
|
||||||
@@ -1431,7 +1941,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
|
|||||||
</itemizedlist></para></listitem>
|
</itemizedlist></para></listitem>
|
||||||
|
|
||||||
<listitem><para>A hash of the contents of a store path is now stored
|
<listitem><para>A hash of the contents of a store path is now stored
|
||||||
in the database after a succesful build. This allows you to check
|
in the database after a successful build. This allows you to check
|
||||||
whether store paths have been tampered with: <command>nix-store
|
whether store paths have been tampered with: <command>nix-store
|
||||||
--verify --check-contents</command>.</para></listitem>
|
--verify --check-contents</command>.</para></listitem>
|
||||||
|
|
||||||
@@ -1595,7 +2105,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
|
|||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem><para>Derivations for other platforms are filtered out
|
<listitem><para>Derivations for other platforms are filtered out
|
||||||
(which can be overriden using
|
(which can be overridden using
|
||||||
<option>--system-filter</option>).</para></listitem>
|
<option>--system-filter</option>).</para></listitem>
|
||||||
|
|
||||||
<listitem><para><option>--install</option> by default now
|
<listitem><para><option>--install</option> by default now
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ bug tracker</link> for a list of currently known issues.</para>
|
|||||||
$ nix-env -i docbook-xml
|
$ nix-env -i docbook-xml
|
||||||
...
|
...
|
||||||
adding /nix/store/s5hyxgm62gk2...-docbook-xml-4.2
|
adding /nix/store/s5hyxgm62gk2...-docbook-xml-4.2
|
||||||
collission between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
|
collision between `/nix/store/s5hyxgm62gk2...-docbook-xml-4.2/xml/dtd/docbook/calstblx.dtd'
|
||||||
and `/nix/store/06h377hr4b33...-docbook-xml-4.3/xml/dtd/docbook/calstblx.dtd'
|
and `/nix/store/06h377hr4b33...-docbook-xml-4.3/xml/dtd/docbook/calstblx.dtd'
|
||||||
at /nix/store/...-builder.pl line 62.</screen>
|
at /nix/store/...-builder.pl line 62.</screen>
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ in <filename>/nix/store</filename>, as can be seen using <command>ls
|
|||||||
$ ls -l /nix/store
|
$ ls -l /nix/store
|
||||||
drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
|
drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
|
||||||
|
|
||||||
The <literal>ext2</literal> file system is limited to a inode link
|
The <literal>ext2</literal> file system is limited to an inode link
|
||||||
count of 32,000 (each subdirectory increasing the count by one).
|
count of 32,000 (each subdirectory increasing the count by one).
|
||||||
Furthermore, the <literal>st_nlink</literal> field of the
|
Furthermore, the <literal>st_nlink</literal> field of the
|
||||||
<function>stat</function> system call is a 16-bit value.</para>
|
<function>stat</function> system call is a 16-bit value.</para>
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ the single Nix expression in that directory
|
|||||||
here, the entire remainder of the file is the body of the
|
here, the entire remainder of the file is the body of the
|
||||||
function; when given the required arguments, the body should
|
function; when given the required arguments, the body should
|
||||||
describe how to build an instance of the Hello package.</para>
|
describe how to build an instance of the Hello package.</para>
|
||||||
|
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
<callout arearefs='ex-hello-nix-co-2'>
|
<callout arearefs='ex-hello-nix-co-2'>
|
||||||
@@ -190,7 +190,7 @@ perl = perl;</programlisting>
|
|||||||
with the same name happen to be in scope.</para>
|
with the same name happen to be in scope.</para>
|
||||||
|
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
</calloutlist>
|
</calloutlist>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
@@ -301,7 +301,7 @@ steps:</para>
|
|||||||
(<literal>make install</literal>).</para>
|
(<literal>make install</literal>).</para>
|
||||||
|
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
</calloutlist>
|
</calloutlist>
|
||||||
|
|
||||||
<para>If you are wondering about the absence of error checking on the
|
<para>If you are wondering about the absence of error checking on the
|
||||||
@@ -321,7 +321,7 @@ error check.</para>
|
|||||||
...
|
...
|
||||||
|
|
||||||
rec { <co xml:id='ex-hello-composition-co-1' />
|
rec { <co xml:id='ex-hello-composition-co-1' />
|
||||||
|
|
||||||
hello = import ../applications/misc/hello/ex-1 <co xml:id='ex-hello-composition-co-2' /> { <co xml:id='ex-hello-composition-co-3' />
|
hello = import ../applications/misc/hello/ex-1 <co xml:id='ex-hello-composition-co-2' /> { <co xml:id='ex-hello-composition-co-3' />
|
||||||
inherit fetchurl stdenv perl;
|
inherit fetchurl stdenv perl;
|
||||||
};
|
};
|
||||||
@@ -330,10 +330,10 @@ rec { <co xml:id='ex-hello-composition-co-1' />
|
|||||||
inherit fetchurl stdenv;
|
inherit fetchurl stdenv;
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchurl = import ../build-support/fetchurl {
|
fetchurl = import ../build-support/fetchurl {
|
||||||
inherit stdenv; ...
|
inherit stdenv; ...
|
||||||
};
|
};
|
||||||
|
|
||||||
stdenv = ...;
|
stdenv = ...;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -476,8 +476,8 @@ that the path denoted by <envar>out</envar> is now
|
|||||||
will see that the path is already valid and finish immediately. If a
|
will see that the path is already valid and finish immediately. If a
|
||||||
build fails, either because it returns a non-zero exit code, because
|
build fails, either because it returns a non-zero exit code, because
|
||||||
Nix or the builder are killed, or because the machine crashes, then
|
Nix or the builder are killed, or because the machine crashes, then
|
||||||
the output path will not be registered as valid. If you try to build
|
the output paths will not be registered as valid. If you try to build
|
||||||
the derivation again, Nix will remove the output path if it exists
|
the derivation again, Nix will remove the output paths if they exist
|
||||||
(e.g., because the builder died half-way through <literal>make
|
(e.g., because the builder died half-way through <literal>make
|
||||||
install</literal>) and try again. Note that there is no
|
install</literal>) and try again. Note that there is no
|
||||||
<quote>negative caching</quote>: Nix doesn't remember that a build
|
<quote>negative caching</quote>: Nix doesn't remember that a build
|
||||||
@@ -543,7 +543,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
|
|||||||
<calloutlist>
|
<calloutlist>
|
||||||
|
|
||||||
<callout arearefs='ex-hello-builder2-co-1'>
|
<callout arearefs='ex-hello-builder2-co-1'>
|
||||||
|
|
||||||
<para>The <envar>buildInputs</envar> variable tells
|
<para>The <envar>buildInputs</envar> variable tells
|
||||||
<filename>setup</filename> to use the indicated packages as
|
<filename>setup</filename> to use the indicated packages as
|
||||||
<quote>inputs</quote>. This means that if a package provides a
|
<quote>inputs</quote>. This means that if a package provides a
|
||||||
@@ -568,7 +568,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
|
|||||||
the file <literal>$stdenv/setup</literal>.</para>
|
the file <literal>$stdenv/setup</literal>.</para>
|
||||||
|
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
<callout arearefs='ex-hello-builder2-co-3'>
|
<callout arearefs='ex-hello-builder2-co-3'>
|
||||||
|
|
||||||
<para>The final step calls the shell function
|
<para>The final step calls the shell function
|
||||||
@@ -580,7 +580,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
|
|||||||
see <xref linkend='sec-standard-environment' />.</para>
|
see <xref linkend='sec-standard-environment' />.</para>
|
||||||
|
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
</calloutlist>
|
</calloutlist>
|
||||||
|
|
||||||
<para>Discerning readers will note that the
|
<para>Discerning readers will note that the
|
||||||
@@ -617,7 +617,7 @@ Laziness means that arguments to functions are evaluated only when
|
|||||||
they are needed. Functional means that functions are
|
they are needed. Functional means that functions are
|
||||||
<quote>normal</quote> values that can be passed around and manipulated
|
<quote>normal</quote> values that can be passed around and manipulated
|
||||||
in interesting ways. The language is not a full-featured, general
|
in interesting ways. The language is not a full-featured, general
|
||||||
purpose language. It's main job is to describe packages,
|
purpose language. Its main job is to describe packages,
|
||||||
compositions of packages, and the variability within
|
compositions of packages, and the variability within
|
||||||
packages.</para>
|
packages.</para>
|
||||||
|
|
||||||
@@ -704,7 +704,7 @@ configureFlags = "
|
|||||||
the third line is indented three spaces. Thus, two spaces are
|
the third line is indented three spaces. Thus, two spaces are
|
||||||
stripped from each line, so the resulting string is
|
stripped from each line, so the resulting string is
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
"This is the first line.\nThis is the second line.\n This is the third line.\n"</programlisting>
|
"This is the first line.\nThis is the second line.\n This is the third line.\n"</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
@@ -714,19 +714,19 @@ configureFlags = "
|
|||||||
text on the initial line.</para>
|
text on the initial line.</para>
|
||||||
|
|
||||||
<para>Antiquotation
|
<para>Antiquotation
|
||||||
(<literal>${<replaceable>expr</replaceable>}}</literal>) is
|
(<literal>${<replaceable>expr</replaceable>}</literal>) is
|
||||||
supported in indented strings.</para>
|
supported in indented strings.</para>
|
||||||
|
|
||||||
<para>Since <literal>${</literal> and <literal>''</literal> have
|
<para>Since <literal>${</literal> and <literal>''</literal> have
|
||||||
special meaning in indented strings, you need a way to quote them.
|
special meaning in indented strings, you need a way to quote them.
|
||||||
<literal>${</literal> can be escaped by prefixing it with
|
<literal>${</literal> can be escaped by prefixing it with
|
||||||
<literal>''</literal>, i.e., <literal>''${</literal>.
|
<literal>''</literal> (that is, two single quotes), i.e.,
|
||||||
<literal>''</literal> can be escaped by prefixing it with
|
<literal>''${</literal>. <literal>''</literal> can be escaped by
|
||||||
<literal>'</literal>, i.e., <literal>'''</literal>. Finally,
|
prefixing it with <literal>'</literal>, i.e.,
|
||||||
linefeed, carriage-return and tab characters can be writted as
|
<literal>'''</literal>. Finally, linefeed, carriage-return and
|
||||||
<literal>''\n</literal>, <literal>''\r</literal>,
|
tab characters can be written as <literal>''\n</literal>,
|
||||||
<literal>''\t</literal>.</para>
|
<literal>''\r</literal>, <literal>''\t</literal>.</para>
|
||||||
|
|
||||||
<para>Indented strings are primarily useful in that they allow
|
<para>Indented strings are primarily useful in that they allow
|
||||||
multi-line string literals to follow the indentation of the
|
multi-line string literals to follow the indentation of the
|
||||||
enclosing Nix expression, and that less escaping is typically
|
enclosing Nix expression, and that less escaping is typically
|
||||||
@@ -745,7 +745,7 @@ stdenv.mkDerivation {
|
|||||||
${if enableBar then "cp bar $out/bin" else ""}
|
${if enableBar then "cp bar $out/bin" else ""}
|
||||||
'';
|
'';
|
||||||
<replaceable>...</replaceable>
|
<replaceable>...</replaceable>
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
@@ -775,13 +775,13 @@ stdenv.mkDerivation {
|
|||||||
absolute at parse time relative to the directory of the Nix
|
absolute at parse time relative to the directory of the Nix
|
||||||
expression that contained it. For instance, if a Nix expression in
|
expression that contained it. For instance, if a Nix expression in
|
||||||
<filename>/foo/bar/bla.nix</filename> refers to
|
<filename>/foo/bar/bla.nix</filename> refers to
|
||||||
<filename>../xyzzy/fnord.nix</filename>, the absolutised path is
|
<filename>../xyzzy/fnord.nix</filename>, the absolute path is
|
||||||
<filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
|
<filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
|
||||||
|
|
||||||
<listitem><para><emphasis>Booleans</emphasis> with values
|
<listitem><para><emphasis>Booleans</emphasis> with values
|
||||||
<literal>true</literal> and
|
<literal>true</literal> and
|
||||||
<literal>false</literal>.</para></listitem>
|
<literal>false</literal>.</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
@@ -931,7 +931,7 @@ propagate attributes). This can be shortened using the
|
|||||||
<literal>inherit</literal> keyword. For instance,
|
<literal>inherit</literal> keyword. For instance,
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
let x = 123; in
|
let x = 123; in
|
||||||
{ inherit x;
|
{ inherit x;
|
||||||
y = 456;
|
y = 456;
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
@@ -982,7 +982,7 @@ argument. There are three kinds of patterns:</para>
|
|||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
|
|
||||||
<listitem><para>If a pattern is a single identifier, then the
|
<listitem><para>If a pattern is a single identifier, then the
|
||||||
function matches any argument. Example:
|
function matches any argument. Example:
|
||||||
|
|
||||||
@@ -1002,7 +1002,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
|
|||||||
evaluates to <literal>[ "foobar" "foobla"
|
evaluates to <literal>[ "foobar" "foobla"
|
||||||
"fooabc" ]</literal>.</para></listitem>
|
"fooabc" ]</literal>.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
<listitem><para>An <emphasis>attribute set pattern</emphasis> of the
|
<listitem><para>An <emphasis>attribute set pattern</emphasis> of the
|
||||||
form <literal>{ name1, name2, …, nameN }</literal>
|
form <literal>{ name1, name2, …, nameN }</literal>
|
||||||
matches an attribute set containing the listed attributes, and binds
|
matches an attribute set containing the listed attributes, and binds
|
||||||
@@ -1016,7 +1016,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
|
|||||||
<varname>x</varname>, <varname>y</varname> and
|
<varname>x</varname>, <varname>y</varname> and
|
||||||
<varname>z</varname>. No other attributes are allowed. If you want
|
<varname>z</varname>. No other attributes are allowed. If you want
|
||||||
to allow additional arguments, you can use an ellipsis
|
to allow additional arguments, you can use an ellipsis
|
||||||
(<literal>...</literal>):
|
(<literal>...</literal>):
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
{ x, y, z, ... }: z + y + x</programlisting>
|
{ x, y, z, ... }: z + y + x</programlisting>
|
||||||
@@ -1164,7 +1164,7 @@ used in the Nix expression for Subversion.</para>
|
|||||||
</calloutlist>
|
</calloutlist>
|
||||||
|
|
||||||
</simplesect>
|
</simplesect>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<simplesect><title>With-expressions</title>
|
<simplesect><title>With-expressions</title>
|
||||||
@@ -1343,7 +1343,7 @@ set, the attributes of which specify the inputs of the build.</para>
|
|||||||
<listitem><para>There must be an attribute named
|
<listitem><para>There must be an attribute named
|
||||||
<varname>name</varname> whose value must be a string. This is used
|
<varname>name</varname> whose value must be a string. This is used
|
||||||
as a symbolic name for the package by <command>nix-env</command>,
|
as a symbolic name for the package by <command>nix-env</command>,
|
||||||
and it is appended to the hash in the output path of the
|
and it is appended to the output paths of the
|
||||||
derivation.</para></listitem>
|
derivation.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>There must be an attribute named
|
<listitem><para>There must be an attribute named
|
||||||
@@ -1358,7 +1358,7 @@ set, the attributes of which specify the inputs of the build.</para>
|
|||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem><para>Strings, URIs, and integers are just passed
|
<listitem><para>Strings and integers are just passed
|
||||||
verbatim.</para></listitem>
|
verbatim.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>A <emphasis>path</emphasis> (e.g.,
|
<listitem><para>A <emphasis>path</emphasis> (e.g.,
|
||||||
@@ -1369,8 +1369,8 @@ set, the attributes of which specify the inputs of the build.</para>
|
|||||||
should reside in the Nix store.</para></listitem>
|
should reside in the Nix store.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>A <emphasis>derivation</emphasis> causes that
|
<listitem><para>A <emphasis>derivation</emphasis> causes that
|
||||||
derivation to be built prior to the present derivation; the
|
derivation to be built prior to the present derivation; its
|
||||||
output path is put in the environment
|
default output path is put in the environment
|
||||||
variable.</para></listitem>
|
variable.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Lists of the previous types are also allowed.
|
<listitem><para>Lists of the previous types are also allowed.
|
||||||
@@ -1389,14 +1389,48 @@ set, the attributes of which specify the inputs of the build.</para>
|
|||||||
specifies command-line arguments to be passed to the builder. It
|
specifies command-line arguments to be passed to the builder. It
|
||||||
should be a list.</para></listitem>
|
should be a list.</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>The optional attribute <varname>outputs</varname>
|
||||||
|
specifies a list of symbolic outputs of the derivation. By default,
|
||||||
|
a derivation produces a single output path, denoted as
|
||||||
|
<literal>out</literal>. However, derivations can produce multiple
|
||||||
|
output paths. This is useful because it allows outputs to be
|
||||||
|
downloaded or garbage-collected separately. For instance, imagine a
|
||||||
|
library package that provides a dynamic library, header files, and
|
||||||
|
documentation. A program that links against the library doesn’t
|
||||||
|
need the header files and documentation at runtime, and it doesn’t
|
||||||
|
need the documentation at build time. Thus, the library package
|
||||||
|
could specify:
|
||||||
|
<programlisting>
|
||||||
|
outputs = [ "lib" "headers" "doc" ];
|
||||||
|
</programlisting>
|
||||||
|
This will cause Nix to pass environment variables
|
||||||
|
<literal>lib</literal>, <literal>headers</literal> and
|
||||||
|
<literal>doc</literal> to the builder containing the intended store
|
||||||
|
paths of each output. The builder would typically do something like
|
||||||
|
<programlisting>
|
||||||
|
./configure --libdir=$lib/lib --includedir=$headers/include --docdir=$doc/share/doc
|
||||||
|
</programlisting>
|
||||||
|
for an Autoconf-style package. You can refer to each output of a
|
||||||
|
derivation by selecting it as an attribute, e.g.
|
||||||
|
<programlisting>
|
||||||
|
buildInputs = [ pkg.lib pkg.headers ];
|
||||||
|
</programlisting>
|
||||||
|
The first element of <varname>output</varname> determines the
|
||||||
|
<emphasis>default output</emphasis>. Thus, you could also write
|
||||||
|
<programlisting>
|
||||||
|
buildInputs = [ pkg pkg.headers ];
|
||||||
|
</programlisting>
|
||||||
|
since <literal>pkg</literal> is equivalent to
|
||||||
|
<literal>pkg.lib</literal>.</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>(Note that <function>mkDerivation</function> in the standard
|
<para>The function <function>mkDerivation</function> in the standard
|
||||||
environment is a wrapper around <function>derivation</function> that
|
environment is a wrapper around <function>derivation</function> that
|
||||||
adds a default value for <varname>system</varname> and always uses
|
adds a default value for <varname>system</varname> and always uses
|
||||||
Bash as the builder, to which the supplied builder is passed as a
|
Bash as the builder, to which the supplied builder is passed as a
|
||||||
command-line argument. See <xref linkend='sec-standard-environment'
|
command-line argument. See <xref linkend='sec-standard-environment'
|
||||||
/>.)</para>
|
/>.</para>
|
||||||
|
|
||||||
<para>The builder is executed as follows:
|
<para>The builder is executed as follows:
|
||||||
|
|
||||||
@@ -1440,17 +1474,19 @@ command-line argument. See <xref linkend='sec-standard-environment'
|
|||||||
top-level Nix store directory (typically,
|
top-level Nix store directory (typically,
|
||||||
<filename>/nix/store</filename>).</para></listitem>
|
<filename>/nix/store</filename>).</para></listitem>
|
||||||
|
|
||||||
<listitem><para><envar>out</envar> is set to point to the output
|
<listitem><para>For each output declared in
|
||||||
path of the derivation, which is a subdirectory of the Nix store.
|
<varname>outputs</varname>, the corresponding environment variable
|
||||||
The output path is a concatenation of the cryptographic hash of
|
is set to point to the intended path in the Nix store for that
|
||||||
all build inputs, and the <varname>name</varname>
|
output. Each output path is a concatenation of the cryptographic
|
||||||
attribute.</para></listitem>
|
hash of all build inputs, the <varname>name</varname> attribute
|
||||||
|
and the output name. (The output name is omitted if it’s
|
||||||
|
<literal>out</literal>.)</para></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>If the output path already exists, it is removed.
|
<listitem><para>If an output path already exists, it is removed.
|
||||||
Also, locks are acquired to prevent multiple Nix instances from
|
Also, locks are acquired to prevent multiple Nix instances from
|
||||||
performing the same build at the same time.</para></listitem>
|
performing the same build at the same time.</para></listitem>
|
||||||
|
|
||||||
@@ -1464,14 +1500,11 @@ command-line argument. See <xref linkend='sec-standard-environment'
|
|||||||
<listitem><para>The temporary directory is removed (unless the
|
<listitem><para>The temporary directory is removed (unless the
|
||||||
<option>-K</option> option was specified).</para></listitem>
|
<option>-K</option> option was specified).</para></listitem>
|
||||||
|
|
||||||
<listitem><para>If the build was successful, Nix scans the output
|
<listitem><para>If the build was successful, Nix scans each output
|
||||||
for references to the paths of the inputs. These so-called
|
path for references to input paths by looking for the hash parts of
|
||||||
<emphasis>retained dependencies</emphasis> could be used when the
|
the input paths. Since these are potential runtime dependencies,
|
||||||
output of the derivation is used (e.g., when it's executed or used
|
Nix registers them as dependencies of the output
|
||||||
as input to another derivation), so if we deploy the derivation, we
|
paths.</para></listitem>
|
||||||
should copy the retained dependencies as well. The scan is
|
|
||||||
performed by looking for the hash parts of file names of the
|
|
||||||
inputs.</para></listitem>
|
|
||||||
|
|
||||||
<listitem><para>After the build, Nix sets the last-modified
|
<listitem><para>After the build, Nix sets the last-modified
|
||||||
timestamp on all files in the build result to 1 (00:00:01 1/1/1970
|
timestamp on all files in the build result to 1 (00:00:01 1/1/1970
|
||||||
@@ -1497,7 +1530,7 @@ attributes.</para>
|
|||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
<varlistentry><term><varname>allowedReferences</varname></term>
|
<varlistentry><term><varname>allowedReferences</varname></term>
|
||||||
|
|
||||||
<listitem><para>The optional attribute
|
<listitem><para>The optional attribute
|
||||||
<varname>allowedReferences</varname> specifies a list of legal
|
<varname>allowedReferences</varname> specifies a list of legal
|
||||||
references (dependencies) of the output of the builder. For
|
references (dependencies) of the output of the builder. For
|
||||||
@@ -1515,7 +1548,7 @@ allowedReferences = [];
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><varname>exportReferencesGraph</varname></term>
|
<varlistentry><term><varname>exportReferencesGraph</varname></term>
|
||||||
|
|
||||||
<listitem><para>This attribute allows builders access to the
|
<listitem><para>This attribute allows builders access to the
|
||||||
@@ -1626,7 +1659,7 @@ stdenv.mkDerivation {
|
|||||||
outputHashMode = "flat";
|
outputHashMode = "flat";
|
||||||
outputHashAlgo = "md5";
|
outputHashAlgo = "md5";
|
||||||
outputHash = md5;
|
outputHash = md5;
|
||||||
|
|
||||||
inherit url;
|
inherit url;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@@ -1655,7 +1688,7 @@ stdenv.mkDerivation {
|
|||||||
<para>This is the default.</para></listitem>
|
<para>This is the default.</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry><term><literal>"recursive"</literal></term>
|
<varlistentry><term><literal>"recursive"</literal></term>
|
||||||
|
|
||||||
<listitem><para>The hash is computed over the NAR archive dump
|
<listitem><para>The hash is computed over the NAR archive dump
|
||||||
@@ -1676,10 +1709,10 @@ stdenv.mkDerivation {
|
|||||||
linkend="sec-nix-hash"><command>nix-hash</command> command</link>
|
linkend="sec-nix-hash"><command>nix-hash</command> command</link>
|
||||||
for information about converting to and from base-32
|
for information about converting to and from base-32
|
||||||
notation.)</para></listitem>
|
notation.)</para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><varname>impureEnvVars</varname></term>
|
<varlistentry><term><varname>impureEnvVars</varname></term>
|
||||||
|
|
||||||
<listitem><para>This attribute allows you to specify a list of
|
<listitem><para>This attribute allows you to specify a list of
|
||||||
@@ -1706,7 +1739,7 @@ impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
|
|||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry><term><varname>preferLocalBuild</varname></term>
|
<varlistentry><term><varname>preferLocalBuild</varname></term>
|
||||||
|
|
||||||
<listitem><para>If this attribute is set to
|
<listitem><para>If this attribute is set to
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ The hook `nix-mode-hook' is run when Nix mode is started.
|
|||||||
("\\<isNull\\>" . font-lock-builtin-face)
|
("\\<isNull\\>" . font-lock-builtin-face)
|
||||||
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
|
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
|
||||||
. font-lock-constant-face)
|
. font-lock-constant-face)
|
||||||
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\.]*\\)[ \t]*="
|
("\\<\\([a-zA-Z_][a-zA-Z0-9_'\-\.]*\\)[ \t]*="
|
||||||
(1 font-lock-variable-name-face nil nil))
|
(1 font-lock-variable-name-face nil nil))
|
||||||
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
|
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
|
||||||
. font-lock-constant-face)
|
. font-lock-constant-face)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Helper daemon for managing secure, multi-user Nix stores
|
||||||
|
After=syslog.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/nix-daemon
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
### Option `gc-keep-outputs'
|
|
||||||
#
|
|
||||||
# If `true', the garbage collector will keep the outputs of
|
|
||||||
# non-garbage derivations. If `false' (default), outputs will be
|
|
||||||
# deleted unless they are GC roots themselves (or reachable from other
|
|
||||||
# roots).
|
|
||||||
#
|
|
||||||
# In general, outputs must be registered as roots separately.
|
|
||||||
# However, even if the output of a derivation is registered as a root,
|
|
||||||
# the collector will still delete store paths that are used only at
|
|
||||||
# build time (e.g., the C compiler, or source tarballs downloaded from
|
|
||||||
# the network). To prevent it from doing so, set this option to
|
|
||||||
# `true'.
|
|
||||||
#gc-keep-outputs = false
|
|
||||||
|
|
||||||
|
|
||||||
### Option `gc-keep-derivations'
|
|
||||||
#
|
|
||||||
# If `true' (default), the garbage collector will keep the derivations
|
|
||||||
# from which non-garbage store paths were built. If `false', they
|
|
||||||
# will be deleted unless explicitly registered as a root (or reachable
|
|
||||||
# from other roots).
|
|
||||||
#
|
|
||||||
# Keeping derivation around is useful for querying and traceability
|
|
||||||
# (e.g., it allows you to ask with what dependencies or options a
|
|
||||||
# store path was built), so by default this option is on. Turn it off
|
|
||||||
# to safe a bit of disk space (or a lot if `gc-keep-outputs' is also
|
|
||||||
# turned on).
|
|
||||||
#gc-keep-derivations = true
|
|
||||||
|
|
||||||
|
|
||||||
### Option `env-keep-derivations'
|
|
||||||
#
|
|
||||||
# If `false' (default), derivations are not stored in Nix user
|
|
||||||
# environments. That is, the derivation any build-time-only
|
|
||||||
# dependencies may be garbage-collected.
|
|
||||||
#
|
|
||||||
# If `true', when you add a Nix derivation to a user environment, the
|
|
||||||
# path of the derivation is stored in the user environment. Thus, the
|
|
||||||
# derivation will not be garbage-collected until the user environment
|
|
||||||
# generation is deleted (`nix-env --delete-generations'). To prevent
|
|
||||||
# build-time-only dependencies from being collected, you should also
|
|
||||||
# turn on `gc-keep-outputs'.
|
|
||||||
#
|
|
||||||
# The difference between this option and `gc-keep-derivations' is that
|
|
||||||
# this one is `sticky': it applies to any user environment created
|
|
||||||
# while this option was enabled, while `gc-keep-derivations' only
|
|
||||||
# applies at the moment the garbage collector is run.
|
|
||||||
#env-keep-derivations = false
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-max-jobs'
|
|
||||||
#
|
|
||||||
# This option defines the maximum number of jobs that Nix will try to
|
|
||||||
# build in parallel. The default is 1. You should generally set it
|
|
||||||
# to the number of CPUs in your system (e.g., 2 on a Athlon 64 X2).
|
|
||||||
# It can be overriden using the `--max-jobs' / `-j' command line
|
|
||||||
# switch.
|
|
||||||
#build-max-jobs = 1
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-cores'
|
|
||||||
#
|
|
||||||
# This option defines the number of CPU cores to utilize in parallel
|
|
||||||
# within a build job, i.e. by passing an appropriate `-jN' flag to GNU
|
|
||||||
# Make. The default is 1, meaning that parallel building within jobs
|
|
||||||
# is disabled. Passing the special value `0' causes Nix to try and
|
|
||||||
# auto-detect the number of available cores on the local host. This
|
|
||||||
# setting can be overridden using the `--cores' command line switch.
|
|
||||||
#build-cores = 1
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-max-silent-time'
|
|
||||||
#
|
|
||||||
# This option defines the maximum number of seconds that a builder can
|
|
||||||
# go without producing any data on standard output or standard error.
|
|
||||||
# This is useful (for instance in a automated build system) to catch
|
|
||||||
# builds that are stuck in an infinite loop, or to catch remote builds
|
|
||||||
# that are hanging due to network problems. It can be overriden using
|
|
||||||
# the `--max-silent-time' command line switch.
|
|
||||||
#
|
|
||||||
# The value 0 means that there is no timeout. This is also the
|
|
||||||
# default.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# build-max-silent-time = 600 # = 10 minutes
|
|
||||||
#build-max-silent-time = 0
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-users-group'
|
|
||||||
#
|
|
||||||
# This options specifies the Unix group containing the Nix build user
|
|
||||||
# accounts. In multi-user Nix installations, builds should not
|
|
||||||
# be performed by the Nix account since that would allow users to
|
|
||||||
# arbitrarily modify the Nix store and database by supplying specially
|
|
||||||
# crafted builders; and they cannot be performed by the calling user
|
|
||||||
# since that would allow him/her to influence the build result.
|
|
||||||
#
|
|
||||||
# Therefore, if this option is non-empty and specifies a valid group,
|
|
||||||
# builds will be performed under the user accounts that are a member
|
|
||||||
# of the group specified here (as listed in /etc/group). Those user
|
|
||||||
# accounts should not be used for any other purpose!
|
|
||||||
#
|
|
||||||
# Nix will never run two builds under the same user account at the
|
|
||||||
# same time. This is to prevent an obvious security hole: a malicious
|
|
||||||
# user writing a Nix expression that modifies the build result of a
|
|
||||||
# legitimate Nix expression being built by another user. Therefore it
|
|
||||||
# is good to have as many Nix build user accounts as you can spare.
|
|
||||||
# (Remember: uids are cheap.)
|
|
||||||
#
|
|
||||||
# The build users should have permission to create files in the Nix
|
|
||||||
# store, but not delete them. Therefore, /nix/store should be owned
|
|
||||||
# by the Nix account, its group should be the group specified here,
|
|
||||||
# and its mode should be 1775.
|
|
||||||
#
|
|
||||||
# If the build users group is empty, builds will be performed under
|
|
||||||
# the uid of the Nix process (that is, the uid of the caller if
|
|
||||||
# $NIX_REMOTE is empty, the uid under which the Nix daemon runs if
|
|
||||||
# $NIX_REMOTE is `daemon', or the uid that owns the setuid nix-worker
|
|
||||||
# program if $NIX_REMOTE is `slave'). Obviously, this should not be
|
|
||||||
# used in multi-user settings with untrusted users.
|
|
||||||
#
|
|
||||||
# The default is empty.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# build-users-group = nix-builders
|
|
||||||
#build-users-group =
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-use-chroot'
|
|
||||||
#
|
|
||||||
# If set to `true', builds will be performed in a chroot environment,
|
|
||||||
# i.e., the build will be isolated from the normal file system
|
|
||||||
# hierarchy and will only see the Nix store, the temporary build
|
|
||||||
# directory, and the directories configured with the
|
|
||||||
# `build-chroot-dirs' option (such as /proc and /dev). This is useful
|
|
||||||
# to prevent undeclared dependencies on files in directories such as
|
|
||||||
# /usr/bin.
|
|
||||||
#
|
|
||||||
# The use of a chroot requires that Nix is run as root (but you can
|
|
||||||
# still use the "build users" feature to perform builds under
|
|
||||||
# different users than root). Currently, chroot builds only work on
|
|
||||||
# Linux because Nix uses "bind mounts" to make the Nix store and other
|
|
||||||
# directories available inside the chroot.
|
|
||||||
#
|
|
||||||
# The default is `false'.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# build-use-chroot = true
|
|
||||||
#build-use-chroot = false
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-chroot-dirs'
|
|
||||||
#
|
|
||||||
# When builds are performed in a chroot environment, Nix will mount
|
|
||||||
# (using `mount --bind' on Linux) some directories from the normal
|
|
||||||
# file system hierarchy inside the chroot. These are the Nix store,
|
|
||||||
# the temporary build directory (usually /tmp/nix-<pid>-<number>) and
|
|
||||||
# the directories listed here. The default is "/dev /dev/pts /proc".
|
|
||||||
# Files in /dev (such as /dev/null) are needed by many builds, and
|
|
||||||
# some files in /proc may also be needed occasionally.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# build-use-chroot = /dev /proc /bin
|
|
||||||
#build-chroot-dirs = /dev /dev/pts /proc
|
|
||||||
|
|
||||||
|
|
||||||
### Option `build-cache-failure'
|
|
||||||
#
|
|
||||||
# If this option is enabled, Nix will do negative caching; that is, it
|
|
||||||
# will remember failed builds, and won't attempt to try to build them
|
|
||||||
# again if you ask for it. Negative caching is disabled by default
|
|
||||||
# because Nix cannot distinguish between permanent build errors (e.g.,
|
|
||||||
# a syntax error in a source file) and transient build errors (e.g., a
|
|
||||||
# full disk), as they both cause the builder to return a non-zero exit
|
|
||||||
# code. You can clear the cache by doing `rm -f
|
|
||||||
# /nix/var/nix/db/failed/*'.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# build-cache-failure = true
|
|
||||||
#build-cache-failure = false
|
|
||||||
+177
-51
@@ -1,29 +1,29 @@
|
|||||||
%define enable_setuid ""
|
%global nixbld_user "nix-builder-"
|
||||||
%define nix_user "nix"
|
%global nixbld_group "nix-builders"
|
||||||
%define nix_group "nix"
|
|
||||||
|
|
||||||
# If set, the Nix user and group will be created by the RPM
|
|
||||||
# pre-install script.
|
|
||||||
%define nix_user_uid ""
|
|
||||||
%define nix_group_gid ""
|
|
||||||
|
|
||||||
Summary: The Nix software deployment system
|
Summary: The Nix software deployment system
|
||||||
Name: nix
|
Name: nix
|
||||||
Version: @version@
|
Version: @version@
|
||||||
Release: 1
|
Release: 2%{?dist}
|
||||||
License: GPL
|
License: LGPLv2+
|
||||||
Group: Software Deployment
|
%if 0%{?rhel}
|
||||||
|
Group: Applications/System
|
||||||
|
%endif
|
||||||
URL: http://nixos.org/
|
URL: http://nixos.org/
|
||||||
Source0: %{name}-@version@.tar.bz2
|
Source0: %{name}-%{version}.tar.gz
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
%if 0%{?el5}
|
||||||
Prefix: /usr
|
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||||
|
%endif
|
||||||
|
BuildRequires: perl(DBD::SQLite)
|
||||||
|
BuildRequires: perl(DBI)
|
||||||
|
BuildRequires: perl(WWW::Curl)
|
||||||
|
BuildRequires: perl(ExtUtils::ParseXS)
|
||||||
Requires: /usr/bin/perl
|
Requires: /usr/bin/perl
|
||||||
Requires: curl
|
Requires: curl
|
||||||
Requires: perl-DBD-SQLite
|
Requires: perl-DBD-SQLite
|
||||||
Requires: perl-devel
|
|
||||||
Requires: bzip2
|
Requires: bzip2
|
||||||
Requires: bzip2-libs
|
Requires: gzip
|
||||||
Requires: sqlite
|
Requires: xz
|
||||||
BuildRequires: bzip2-devel
|
BuildRequires: bzip2-devel
|
||||||
BuildRequires: sqlite-devel
|
BuildRequires: sqlite-devel
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ BuildRequires: sqlite-devel
|
|||||||
Provides: perl(Nix::SSH)
|
Provides: perl(Nix::SSH)
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|
||||||
Nix is a purely functional package manager. It allows multiple
|
Nix is a purely functional package manager. It allows multiple
|
||||||
versions of a package to be installed side-by-side, ensures that
|
versions of a package to be installed side-by-side, ensures that
|
||||||
dependency specifications are complete, supports atomic upgrades and
|
dependency specifications are complete, supports atomic upgrades and
|
||||||
@@ -39,52 +38,179 @@ rollbacks, allows non-root users to install software, and has many
|
|||||||
other features. It is the basis of the NixOS Linux distribution, but
|
other features. It is the basis of the NixOS Linux distribution, but
|
||||||
it can be used equally well under other Unix systems.
|
it can be used equally well under other Unix systems.
|
||||||
|
|
||||||
|
%package devel
|
||||||
|
Summary: Development files for %{name}
|
||||||
|
%if 0%{?rhel}
|
||||||
|
Group: Development/Libraries
|
||||||
|
%endif
|
||||||
|
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description devel
|
||||||
|
The %{name}-devel package contains libraries and header files for
|
||||||
|
developing applications that use %{name}.
|
||||||
|
|
||||||
|
|
||||||
|
%package doc
|
||||||
|
Summary: Documentation files for %{name}
|
||||||
|
%if 0%{?rhel}
|
||||||
|
Group: Documentation
|
||||||
|
%endif
|
||||||
|
BuildArch: noarch
|
||||||
|
Requires: %{name} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description doc
|
||||||
|
The %{name}-doc package contains documentation files for %{name}.
|
||||||
|
|
||||||
|
|
||||||
|
%package -n emacs-%{name}
|
||||||
|
Summary: Nix mode for Emacs
|
||||||
|
%if 0%{?rhel}
|
||||||
|
Group: Applications/Editors
|
||||||
|
%endif
|
||||||
|
BuildArch: noarch
|
||||||
|
BuildRequires: emacs
|
||||||
|
Requires: emacs(bin) >= %{_emacs_version}
|
||||||
|
|
||||||
|
%description -n emacs-%{name}
|
||||||
|
This package provides a major mode for editing Nix expressions.
|
||||||
|
|
||||||
|
%package -n emacs-%{name}-el
|
||||||
|
Summary: Elisp source files for emacs-%{name}
|
||||||
|
%if 0%{?rhel}
|
||||||
|
Group: Applications/Editors
|
||||||
|
%endif
|
||||||
|
BuildArch: noarch
|
||||||
|
Requires: emacs-%{name} = %{version}-%{release}
|
||||||
|
|
||||||
|
%description -n emacs-%{name}-el
|
||||||
|
This package contains the elisp source file for the Nix major mode for
|
||||||
|
GNU Emacs. You do not need to install this package to run Nix. Install
|
||||||
|
the emacs-%{name} package to edit Nix expressions with GNU Emacs.
|
||||||
|
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q
|
%setup -q
|
||||||
|
# Install Perl modules to vendor_perl
|
||||||
|
# configure.ac need to be changed to make this global; however, this will
|
||||||
|
# also affect NixOS. Use discretion.
|
||||||
|
%{__sed} -i 's|perl5/site_perl/$perlversion/$perlarchname|perl5/vendor_perl|' \
|
||||||
|
configure
|
||||||
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
extraFlags=
|
extraFlags=
|
||||||
if test -n "%{enable_setuid}"; then
|
# - override docdir so large documentation files are owned by the
|
||||||
extraFlags="$extraFlags --enable-setuid"
|
# -doc subpackage
|
||||||
if test -n "%{nix_user}"; then
|
# - set localstatedir by hand to the preferred nix value
|
||||||
extraFlags="$extraFlags --with-nix-user=%{nix_user}"
|
%configure --localstatedir=/nix/var \
|
||||||
fi
|
--docdir=%{_defaultdocdir}/%{name}-doc-%{version} \
|
||||||
if test -n "%{nix_group}"; then
|
$extraFlags
|
||||||
extraFlags="$extraFlags --with-nix-group=%{nix_group}"
|
make %{?_smp_flags}
|
||||||
fi
|
%{_emacs_bytecompile} misc/emacs/nix-mode.el
|
||||||
fi
|
|
||||||
./configure --prefix=%{_prefix} --sysconfdir=/etc $extraFlags
|
|
||||||
make
|
|
||||||
make check
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
|
%if 0%{?el5}
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
%endif
|
||||||
make DESTDIR=$RPM_BUILD_ROOT install
|
make DESTDIR=$RPM_BUILD_ROOT install
|
||||||
rm $RPM_BUILD_ROOT/etc/nix/nix.conf
|
|
||||||
strip $RPM_BUILD_ROOT/%{_prefix}/bin/* || true
|
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
|
||||||
|
|
||||||
|
# Fix symlink: we want to link to the versioned soname, not to the
|
||||||
|
# unversioned one that'd be put in -devel
|
||||||
|
pushd $RPM_BUILD_ROOT%{perl_vendorarch}/auto/Nix/Store
|
||||||
|
ln -sf %{_libdir}/nix/libNixStore.so.0 Store.so
|
||||||
|
popd
|
||||||
|
|
||||||
|
# Specify build users group
|
||||||
|
echo "build-users-group = %{nixbld_group}" > $RPM_BUILD_ROOT%{_sysconfdir}/nix/nix.conf
|
||||||
|
|
||||||
|
# make per-user directories
|
||||||
|
for d in profiles gcroots;
|
||||||
|
do
|
||||||
|
mkdir $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
|
||||||
|
chmod 1777 $RPM_BUILD_ROOT/nix/var/nix/$d/per-user
|
||||||
|
done
|
||||||
|
|
||||||
|
# fix permission of nix profile
|
||||||
|
# (until this is fixed in the relevant Makefile)
|
||||||
|
chmod -x $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/nix.sh
|
||||||
|
|
||||||
|
# systemd not available on RHEL yet
|
||||||
|
%if ! 0%{?rhel}
|
||||||
|
# install systemd service descriptor
|
||||||
|
mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system
|
||||||
|
cp -p misc/systemd/nix-daemon.service \
|
||||||
|
$RPM_BUILD_ROOT%{_prefix}/lib/systemd/system/
|
||||||
|
%endif
|
||||||
|
|
||||||
|
# Copy the byte-compiled mode file by hand
|
||||||
|
cp -p misc/emacs/nix-mode.elc $RPM_BUILD_ROOT%{_emacs_sitelispdir}/
|
||||||
|
|
||||||
|
# we ship this file in the base package
|
||||||
|
rm $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}-doc-%{version}/README
|
||||||
|
|
||||||
|
|
||||||
|
%check
|
||||||
|
make check
|
||||||
|
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
|
||||||
%pre
|
%pre
|
||||||
if test -n "%{nix_group_gid}"; then
|
getent group %{nixbld_group} >/dev/null || groupadd -r %{nixbld_group}
|
||||||
/usr/sbin/groupadd -g %{nix_group_gid} %{nix_group} || true
|
for i in $(seq 10);
|
||||||
fi
|
do
|
||||||
if test -n "%{nix_user_uid}"; then
|
getent passwd %{nixbld_user}$i >/dev/null || \
|
||||||
/usr/sbin/useradd -c "Nix" -u %{nix_user_uid} \
|
useradd -r -g %{nixbld_group} -G %{nixbld_group} -d /var/empty \
|
||||||
-s /sbin/nologin -r -d /var/empty %{nix_user} \
|
-s %{_sbindir}/nologin \
|
||||||
-g %{nix_group} || true
|
-c "Nix build user $i" %{nixbld_user}$i
|
||||||
fi
|
done
|
||||||
|
|
||||||
|
%post
|
||||||
|
chgrp %{nixbld_group} /nix/store
|
||||||
|
chmod 1775 /nix/store
|
||||||
|
%if ! 0%{?rhel}
|
||||||
|
# Enable and start Nix worker
|
||||||
|
systemctl enable nix-daemon.service
|
||||||
|
systemctl start nix-daemon.service
|
||||||
|
%endif
|
||||||
|
|
||||||
%files
|
%files
|
||||||
#%defattr(-,root,root)
|
%doc COPYING AUTHORS README
|
||||||
%{_prefix}/bin
|
%{_bindir}/nix-*
|
||||||
%{_prefix}/lib
|
%dir %{_libdir}/nix
|
||||||
%{_prefix}/libexec
|
%{_libdir}/nix/*.so.*
|
||||||
%{_prefix}/include
|
%{perl_vendorarch}/*
|
||||||
%{_prefix}/share
|
%exclude %dir %{perl_vendorarch}/auto/
|
||||||
/etc/profile.d/nix.sh
|
%{_prefix}/libexec/*
|
||||||
/nix/var
|
%if ! 0%{?rhel}
|
||||||
/nix/store
|
%{_prefix}/lib/systemd/system/nix-daemon.service
|
||||||
%config
|
%endif
|
||||||
/etc/nix
|
%{_datadir}/emacs/site-lisp/nix-mode.el
|
||||||
|
%{_datadir}/nix
|
||||||
|
%{_mandir}/man1/*.1*
|
||||||
|
%{_mandir}/man5/*.5*
|
||||||
|
%{_mandir}/man8/*.8*
|
||||||
|
%config(noreplace) %{_sysconfdir}/profile.d/nix.sh
|
||||||
|
/nix
|
||||||
|
%dir %{_sysconfdir}/nix
|
||||||
|
%config(noreplace) %{_sysconfdir}/nix/nix.conf
|
||||||
|
|
||||||
|
%files devel
|
||||||
|
%{_includedir}/nix
|
||||||
|
%{_libdir}/nix/*.so
|
||||||
|
|
||||||
|
%files doc
|
||||||
|
%docdir %{_defaultdocdir}/%{name}-doc-%{version}
|
||||||
|
%{_defaultdocdir}/%{name}-doc-%{version}
|
||||||
|
|
||||||
|
%files -n emacs-%{name}
|
||||||
|
%{_emacs_sitelispdir}/*.elc
|
||||||
|
#{_emacs_sitestartdir}/*.el
|
||||||
|
|
||||||
|
%files -n emacs-%{name}-el
|
||||||
|
%{_emacs_sitelispdir}/*.el
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/CopyClosure.pm lib/Nix/Config.pm.in
|
PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/CopyClosure.pm lib/Nix/Config.pm.in lib/Nix/Utils.pm
|
||||||
|
|
||||||
all: $(PERL_MODULES:.in=)
|
all: $(PERL_MODULES:.in=)
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ AM_CXXFLAGS = \
|
|||||||
-D_FILE_OFFSET_BITS=64
|
-D_FILE_OFFSET_BITS=64
|
||||||
|
|
||||||
lib/Nix/Store.cc: lib/Nix/Store.xs
|
lib/Nix/Store.cc: lib/Nix/Store.xs
|
||||||
|
$(INSTALL) -d lib/Nix
|
||||||
xsubpp $^ -output $@
|
xsubpp $^ -output $@
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,27 +1,39 @@
|
|||||||
package Nix::Config;
|
package Nix::Config;
|
||||||
|
|
||||||
|
$version = "@version@";
|
||||||
|
|
||||||
$binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
$binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||||
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@";
|
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@";
|
||||||
$stateDir = $ENV{"NIX_STATE_DIR"} || "@localstatedir@/nix";
|
$stateDir = $ENV{"NIX_STATE_DIR"} || "@localstatedir@/nix";
|
||||||
$manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests";
|
$manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests";
|
||||||
$logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix";
|
$logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix";
|
||||||
$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix";
|
$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix";
|
||||||
|
$storeDir = $ENV{"NIX_STORE_DIR"} || "@storedir@";
|
||||||
|
|
||||||
$bzip2 = $ENV{"NIX_BZIP2"} || "@bzip2@";
|
$bzip2 = "@bzip2@";
|
||||||
|
$xz = "@xz@";
|
||||||
$curl = "@curl@";
|
$curl = "@curl@";
|
||||||
|
|
||||||
$useBindings = "@perlbindings@" eq "yes";
|
$useBindings = "@perlbindings@" eq "yes";
|
||||||
|
|
||||||
|
%config = ();
|
||||||
|
|
||||||
sub readConfig {
|
sub readConfig {
|
||||||
my %config;
|
if (defined $ENV{'_NIX_OPTIONS'}) {
|
||||||
my $config = "@sysconfdir@/nix/nix.conf";
|
foreach my $s (split '\n', $ENV{'_NIX_OPTIONS'}) {
|
||||||
|
my ($n, $v) = split '=', $s, 2;
|
||||||
|
$config{$n} = $v;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $config = "$confDir/nix.conf";
|
||||||
return unless -f $config;
|
return unless -f $config;
|
||||||
|
|
||||||
open CONFIG, "<$config" or die "cannot open `$config'";
|
open CONFIG, "<$config" or die "cannot open `$config'";
|
||||||
while (<CONFIG>) {
|
while (<CONFIG>) {
|
||||||
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
|
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
|
||||||
$config{$1} = $2;
|
$config{$1} = $2;
|
||||||
print "|$1| -> |$2|\n";
|
|
||||||
}
|
}
|
||||||
close CONFIG;
|
close CONFIG;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,39 +3,50 @@ package Nix::CopyClosure;
|
|||||||
use strict;
|
use strict;
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
|
use List::Util qw(sum);
|
||||||
|
|
||||||
|
|
||||||
sub copyTo {
|
sub copyTo {
|
||||||
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer) = @_;
|
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor,
|
||||||
|
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes) = @_;
|
||||||
$compressor = "$compressor |" if $compressor ne "";
|
|
||||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
|
||||||
$progressViewer = "$progressViewer |" if $progressViewer ne "";
|
|
||||||
|
|
||||||
# Get the closure of this path.
|
# Get the closure of this path.
|
||||||
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
|
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
|
||||||
map { followLinksToStorePath $_ } @{$storePaths})));
|
map { followLinksToStorePath $_ } @{$storePaths})));
|
||||||
|
|
||||||
|
# Optionally use substitutes on the remote host.
|
||||||
|
if (!$dryRun && $useSubstitutes) {
|
||||||
|
system "ssh $sshHost @{$sshOpts} nix-store -r --ignore-unknown @closure";
|
||||||
|
# Ignore exit status because this is just an optimisation.
|
||||||
|
}
|
||||||
|
|
||||||
# Ask the remote host which paths are invalid. Because of limits
|
# Ask the remote host which paths are invalid. Because of limits
|
||||||
# to the command line length, do this in chunks. Eventually,
|
# to the command line length, do this in chunks. Eventually,
|
||||||
# we'll want to use ‘--from-stdin’, but we can't rely on the
|
# we'll want to use ‘--from-stdin’, but we can't rely on the
|
||||||
# target having this option yet.
|
# target having this option yet.
|
||||||
my @missing = ();
|
my @missing = ();
|
||||||
|
my $missingSize = 0;
|
||||||
while (scalar(@closure) > 0) {
|
while (scalar(@closure) > 0) {
|
||||||
my @ps = splice(@closure, 0, 1500);
|
my @ps = splice(@closure, 0, 1500);
|
||||||
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
|
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
|
||||||
while (<READ>) {
|
while (<READ>) {
|
||||||
chomp;
|
chomp;
|
||||||
push @missing, $_;
|
push @missing, $_;
|
||||||
|
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($_, 1);
|
||||||
|
$missingSize += $narSize;
|
||||||
}
|
}
|
||||||
close READ or die;
|
close READ or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$compressor = "$compressor |" if $compressor ne "";
|
||||||
|
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||||
|
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
|
||||||
|
|
||||||
# Export the store paths and import them on the remote machine.
|
# Export the store paths and import them on the remote machine.
|
||||||
if (scalar @missing > 0) {
|
if (scalar @missing > 0) {
|
||||||
print STDERR "copying ", scalar @missing, " missing paths to ‘$sshHost’...\n";
|
print STDERR "copying ", scalar @missing, " missing paths to ‘$sshHost’...\n";
|
||||||
unless ($dryRun) {
|
unless ($dryRun) {
|
||||||
open SSH, "| $compressor $progressViewer ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
|
open SSH, "| $progressViewer $compressor ssh $sshHost @{$sshOpts} '$decompressor nix-store --import' > /dev/null" or die;
|
||||||
exportPaths(fileno(SSH), $sign, @missing);
|
exportPaths(fileno(SSH), $sign, @missing);
|
||||||
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
|
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||||
}
|
}
|
||||||
|
|||||||
+93
-28
@@ -9,12 +9,12 @@ use Fcntl ':flock';
|
|||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch);
|
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch deleteOldManifests parseNARInfo);
|
||||||
|
|
||||||
|
|
||||||
sub addNAR {
|
sub addNAR {
|
||||||
my ($narFiles, $storePath, $info) = @_;
|
my ($narFiles, $storePath, $info) = @_;
|
||||||
|
|
||||||
$$narFiles{$storePath} = []
|
$$narFiles{$storePath} = []
|
||||||
unless defined $$narFiles{$storePath};
|
unless defined $$narFiles{$storePath};
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ sub addNAR {
|
|||||||
foreach my $narFile (@{$narFileList}) {
|
foreach my $narFile (@{$narFileList}) {
|
||||||
$found = 1 if $narFile->{url} eq $info->{url};
|
$found = 1 if $narFile->{url} eq $info->{url};
|
||||||
}
|
}
|
||||||
|
|
||||||
push @{$narFileList}, $info if !$found;
|
push @{$narFileList}, $info if !$found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ sub addPatch {
|
|||||||
$patch2->{url} eq $patch->{url} &&
|
$patch2->{url} eq $patch->{url} &&
|
||||||
$patch2->{basePath} eq $patch->{basePath};
|
$patch2->{basePath} eq $patch->{basePath};
|
||||||
}
|
}
|
||||||
|
|
||||||
push @{$patchList}, $patch if !$found;
|
push @{$patchList}, $patch if !$found;
|
||||||
|
|
||||||
return !$found;
|
return !$found;
|
||||||
@@ -68,7 +68,7 @@ sub readManifest_ {
|
|||||||
my $manifestVersion = 2;
|
my $manifestVersion = 2;
|
||||||
|
|
||||||
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
|
my ($storePath, $url, $hash, $size, $basePath, $baseHash, $patchType);
|
||||||
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system);
|
my ($narHash, $narSize, $references, $deriver, $copyFrom, $system, $compressionType);
|
||||||
|
|
||||||
while (<MANIFEST>) {
|
while (<MANIFEST>) {
|
||||||
chomp;
|
chomp;
|
||||||
@@ -93,10 +93,11 @@ sub readManifest_ {
|
|||||||
undef $system;
|
undef $system;
|
||||||
$references = "";
|
$references = "";
|
||||||
$deriver = "";
|
$deriver = "";
|
||||||
}
|
$compressionType = "bzip2";
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (/^\}$/) {
|
if (/^\}$/) {
|
||||||
$inside = 0;
|
$inside = 0;
|
||||||
|
|
||||||
@@ -107,6 +108,7 @@ sub readManifest_ {
|
|||||||
, references => $references
|
, references => $references
|
||||||
, deriver => $deriver
|
, deriver => $deriver
|
||||||
, system => $system
|
, system => $system
|
||||||
|
, compressionType => $compressionType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,11 +122,12 @@ sub readManifest_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
|
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
|
||||||
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
|
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
|
||||||
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
|
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
|
||||||
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
|
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
|
||||||
|
elsif (/^\s*Compression:\s*(\S+)\s*$/) { $compressionType = $1; }
|
||||||
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
|
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
|
||||||
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
|
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
|
||||||
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
|
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
|
||||||
@@ -172,6 +175,7 @@ sub writeManifest {
|
|||||||
print MANIFEST "{\n";
|
print MANIFEST "{\n";
|
||||||
print MANIFEST " StorePath: $storePath\n";
|
print MANIFEST " StorePath: $storePath\n";
|
||||||
print MANIFEST " NarURL: $narFile->{url}\n";
|
print MANIFEST " NarURL: $narFile->{url}\n";
|
||||||
|
print MANIFEST " Compression: $narFile->{compressionType}\n";
|
||||||
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
|
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
|
||||||
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
|
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
|
||||||
print MANIFEST " NarHash: $narFile->{narHash}\n";
|
print MANIFEST " NarHash: $narFile->{narHash}\n";
|
||||||
@@ -184,7 +188,7 @@ sub writeManifest {
|
|||||||
print MANIFEST "}\n";
|
print MANIFEST "}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $storePath (sort (keys %{$patches})) {
|
foreach my $storePath (sort (keys %{$patches})) {
|
||||||
my $patchList = $$patches{$storePath};
|
my $patchList = $$patches{$storePath};
|
||||||
foreach my $patch (@{$patchList}) {
|
foreach my $patch (@{$patchList}) {
|
||||||
@@ -201,8 +205,8 @@ sub writeManifest {
|
|||||||
print MANIFEST "}\n";
|
print MANIFEST "}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
close MANIFEST;
|
close MANIFEST;
|
||||||
|
|
||||||
rename("$manifest.tmp", $manifest)
|
rename("$manifest.tmp", $manifest)
|
||||||
@@ -211,11 +215,11 @@ sub writeManifest {
|
|||||||
|
|
||||||
# Create a bzipped manifest.
|
# Create a bzipped manifest.
|
||||||
unless (defined $noCompress) {
|
unless (defined $noCompress) {
|
||||||
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
|
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
|
||||||
or die "cannot compress manifest";
|
or die "cannot compress manifest";
|
||||||
|
|
||||||
rename("$manifest.bz2.tmp", "$manifest.bz2")
|
rename("$manifest.bz2.tmp", "$manifest.bz2")
|
||||||
or die "cannot rename $manifest.bz2.tmp: $!";
|
or die "cannot rename $manifest.bz2.tmp: $!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,9 +227,13 @@ sub writeManifest {
|
|||||||
sub updateManifestDB {
|
sub updateManifestDB {
|
||||||
my $manifestDir = $Nix::Config::manifestDir;
|
my $manifestDir = $Nix::Config::manifestDir;
|
||||||
|
|
||||||
|
my @manifests = glob "$manifestDir/*.nixmanifest";
|
||||||
|
return undef if scalar @manifests == 0;
|
||||||
|
|
||||||
mkpath($manifestDir);
|
mkpath($manifestDir);
|
||||||
|
|
||||||
my $dbPath = "$manifestDir/cache.sqlite";
|
unlink "$manifestDir/cache.sqlite"; # remove obsolete cache
|
||||||
|
my $dbPath = "$manifestDir/cache-v2.sqlite";
|
||||||
|
|
||||||
# Open/create the database.
|
# Open/create the database.
|
||||||
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
|
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
|
||||||
@@ -245,13 +253,14 @@ sub updateManifestDB {
|
|||||||
timestamp integer not null
|
timestamp integer not null
|
||||||
);
|
);
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
$dbh->do(<<EOF);
|
$dbh->do(<<EOF);
|
||||||
create table if not exists NARs (
|
create table if not exists NARs (
|
||||||
id integer primary key autoincrement not null,
|
id integer primary key autoincrement not null,
|
||||||
manifest integer not null,
|
manifest integer not null,
|
||||||
storePath text not null,
|
storePath text not null,
|
||||||
url text not null,
|
url text not null,
|
||||||
|
compressionType text not null,
|
||||||
hash text,
|
hash text,
|
||||||
size integer,
|
size integer,
|
||||||
narHash text,
|
narHash text,
|
||||||
@@ -292,8 +301,8 @@ EOF
|
|||||||
flock(MAINLOCK, LOCK_EX) or die;
|
flock(MAINLOCK, LOCK_EX) or die;
|
||||||
|
|
||||||
our $insertNAR = $dbh->prepare(
|
our $insertNAR = $dbh->prepare(
|
||||||
"insert into NARs(manifest, storePath, url, hash, size, narHash, " .
|
"insert into NARs(manifest, storePath, url, compressionType, hash, size, narHash, " .
|
||||||
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
|
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
|
||||||
|
|
||||||
our $insertPatch = $dbh->prepare(
|
our $insertPatch = $dbh->prepare(
|
||||||
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
|
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
|
||||||
@@ -304,8 +313,8 @@ EOF
|
|||||||
# Read each manifest in $manifestDir and add it to the database,
|
# Read each manifest in $manifestDir and add it to the database,
|
||||||
# unless we've already done so on a previous run.
|
# unless we've already done so on a previous run.
|
||||||
my %seen;
|
my %seen;
|
||||||
|
|
||||||
for my $manifestLink (glob "$manifestDir/*.nixmanifest") {
|
for my $manifestLink (@manifests) {
|
||||||
my $manifest = Cwd::abs_path($manifestLink);
|
my $manifest = Cwd::abs_path($manifestLink);
|
||||||
next unless -f $manifest;
|
next unless -f $manifest;
|
||||||
my $timestamp = lstat($manifest)->mtime;
|
my $timestamp = lstat($manifest)->mtime;
|
||||||
@@ -316,9 +325,9 @@ EOF
|
|||||||
{}, $manifest, $timestamp)} == 1;
|
{}, $manifest, $timestamp)} == 1;
|
||||||
|
|
||||||
print STDERR "caching $manifest...\n";
|
print STDERR "caching $manifest...\n";
|
||||||
|
|
||||||
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
|
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
|
||||||
|
|
||||||
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)",
|
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)",
|
||||||
{}, $manifest, $timestamp);
|
{}, $manifest, $timestamp);
|
||||||
|
|
||||||
@@ -327,11 +336,11 @@ EOF
|
|||||||
sub addNARToDB {
|
sub addNARToDB {
|
||||||
my ($storePath, $narFile) = @_;
|
my ($storePath, $narFile) = @_;
|
||||||
$insertNAR->execute(
|
$insertNAR->execute(
|
||||||
$id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size},
|
$id, $storePath, $narFile->{url}, $narFile->{compressionType}, $narFile->{hash},
|
||||||
$narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
|
$narFile->{size}, $narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
|
||||||
$narFile->{deriver}, $narFile->{system});
|
$narFile->{deriver}, $narFile->{system});
|
||||||
};
|
};
|
||||||
|
|
||||||
sub addPatchToDB {
|
sub addPatchToDB {
|
||||||
my ($storePath, $patch) = @_;
|
my ($storePath, $patch) = @_;
|
||||||
$insertPatch->execute(
|
$insertPatch->execute(
|
||||||
@@ -341,7 +350,7 @@ EOF
|
|||||||
};
|
};
|
||||||
|
|
||||||
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
|
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
|
||||||
|
|
||||||
if ($version < 3) {
|
if ($version < 3) {
|
||||||
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it\n";
|
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it\n";
|
||||||
}
|
}
|
||||||
@@ -364,4 +373,60 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Delete all old manifests downloaded from a given URL.
|
||||||
|
sub deleteOldManifests {
|
||||||
|
my ($url, $curUrlFile) = @_;
|
||||||
|
for my $urlFile (glob "$Nix::Config::manifestDir/*.url") {
|
||||||
|
next if defined $curUrlFile && $urlFile eq $curUrlFile;
|
||||||
|
open URL, "<$urlFile" or die;
|
||||||
|
my $url2 = <URL>;
|
||||||
|
chomp $url2;
|
||||||
|
close URL;
|
||||||
|
next unless $url eq $url2;
|
||||||
|
my $base = $urlFile; $base =~ s/.url$//;
|
||||||
|
unlink "${base}.url";
|
||||||
|
unlink "${base}.nixmanifest";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Parse a NAR info file.
|
||||||
|
sub parseNARInfo {
|
||||||
|
my ($storePath, $content) = @_;
|
||||||
|
|
||||||
|
my ($storePath2, $url, $fileHash, $fileSize, $narHash, $narSize, $deriver, $system);
|
||||||
|
my $compression = "bzip2";
|
||||||
|
my @refs;
|
||||||
|
|
||||||
|
foreach my $line (split "\n", $content) {
|
||||||
|
return undef unless $line =~ /^(.*): (.*)$/;
|
||||||
|
if ($1 eq "StorePath") { $storePath2 = $2; }
|
||||||
|
elsif ($1 eq "URL") { $url = $2; }
|
||||||
|
elsif ($1 eq "Compression") { $compression = $2; }
|
||||||
|
elsif ($1 eq "FileHash") { $fileHash = $2; }
|
||||||
|
elsif ($1 eq "FileSize") { $fileSize = int($2); }
|
||||||
|
elsif ($1 eq "NarHash") { $narHash = $2; }
|
||||||
|
elsif ($1 eq "NarSize") { $narSize = int($2); }
|
||||||
|
elsif ($1 eq "References") { @refs = split / /, $2; }
|
||||||
|
elsif ($1 eq "Deriver") { $deriver = $2; }
|
||||||
|
elsif ($1 eq "System") { $system = $2; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef if $storePath ne $storePath2 || !defined $url || !defined $narHash;
|
||||||
|
|
||||||
|
return
|
||||||
|
{ url => $url
|
||||||
|
, compression => $compression
|
||||||
|
, fileHash => $fileHash
|
||||||
|
, fileSize => $fileSize
|
||||||
|
, narHash => $narHash
|
||||||
|
, narSize => $narSize
|
||||||
|
, refs => [ @refs ]
|
||||||
|
, deriver => $deriver
|
||||||
|
, system => $system
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ sub closeSSHConnection {
|
|||||||
if ($sshStarted) {
|
if ($sshStarted) {
|
||||||
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
|
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
|
||||||
or warn "unable to stop SSH master: $?";
|
or warn "unable to stop SSH master: $?";
|
||||||
|
$sshStarted = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-17
@@ -14,6 +14,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
|||||||
|
|
||||||
our @EXPORT = qw(
|
our @EXPORT = qw(
|
||||||
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
|
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
|
||||||
|
queryPathFromHashPart
|
||||||
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
|
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
|
||||||
hashPath hashFile hashString
|
hashPath hashFile hashString
|
||||||
addToStore makeFixedOutputPath
|
addToStore makeFixedOutputPath
|
||||||
@@ -41,50 +42,50 @@ if ($Nix::Config::useBindings) {
|
|||||||
use File::Temp;
|
use File::Temp;
|
||||||
use Fcntl qw/F_SETFD/;
|
use Fcntl qw/F_SETFD/;
|
||||||
|
|
||||||
sub hashFile {
|
*hashFile = sub {
|
||||||
my ($algo, $base32, $path) = @_;
|
my ($algo, $base32, $path) = @_;
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
|
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
};
|
||||||
|
|
||||||
sub hashPath {
|
*hashPath = sub {
|
||||||
my ($algo, $base32, $path) = @_;
|
my ($algo, $base32, $path) = @_;
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
|
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
};
|
||||||
|
|
||||||
sub hashString {
|
*hashString = sub {
|
||||||
my ($algo, $base32, $s) = @_;
|
my ($algo, $base32, $s) = @_;
|
||||||
my $fh = File::Temp->new();
|
my $fh = File::Temp->new();
|
||||||
print $fh $s;
|
print $fh $s;
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
|
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
};
|
||||||
|
|
||||||
sub addToStore {
|
*addToStore = sub {
|
||||||
my ($srcPath, $recursive, $algo) = @_;
|
my ($srcPath, $recursive, $algo) = @_;
|
||||||
die "not implemented" if $recursive || $algo ne "sha256";
|
die "not implemented" if $recursive || $algo ne "sha256";
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
|
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
};
|
||||||
|
|
||||||
sub isValidPath {
|
*isValidPath = sub {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
|
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res ne $path;
|
return $res ne $path;
|
||||||
}
|
};
|
||||||
|
|
||||||
sub queryPathHash {
|
*queryPathHash = sub {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
|
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
|
||||||
chomp $res;
|
chomp $res;
|
||||||
return $res;
|
return $res;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
+27
-12
@@ -15,11 +15,12 @@
|
|||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
|
|
||||||
void doInit()
|
void doInit()
|
||||||
{
|
{
|
||||||
if (!store) {
|
if (!store) {
|
||||||
try {
|
try {
|
||||||
setDefaultsFromEnvironment();
|
settings.processEnvironment();
|
||||||
|
settings.lockCPU = false;
|
||||||
store = openStore();
|
store = openStore();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak(e.what());
|
croak(e.what());
|
||||||
@@ -86,7 +87,7 @@ SV * queryDeriver(char * path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SV * queryPathInfo(char * path)
|
SV * queryPathInfo(char * path, int base32)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
doInit();
|
||||||
@@ -95,7 +96,7 @@ SV * queryPathInfo(char * path)
|
|||||||
XPUSHs(&PL_sv_undef);
|
XPUSHs(&PL_sv_undef);
|
||||||
else
|
else
|
||||||
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0)));
|
||||||
string s = "sha256:" + printHash(info.hash);
|
string s = "sha256:" + (base32 ? printHash32(info.hash) : printHash(info.hash));
|
||||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||||
mXPUSHi(info.registrationTime);
|
mXPUSHi(info.registrationTime);
|
||||||
mXPUSHi(info.narSize);
|
mXPUSHi(info.narSize);
|
||||||
@@ -108,6 +109,17 @@ SV * queryPathInfo(char * path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SV * queryPathFromHashPart(char * hashPart)
|
||||||
|
PPCODE:
|
||||||
|
try {
|
||||||
|
doInit();
|
||||||
|
Path path = store->queryPathFromHashPart(hashPart);
|
||||||
|
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
|
||||||
|
} catch (Error & e) {
|
||||||
|
croak(e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
|
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
@@ -226,32 +238,35 @@ SV * derivationFromPath(char * drvPath)
|
|||||||
doInit();
|
doInit();
|
||||||
Derivation drv = derivationFromPath(*store, drvPath);
|
Derivation drv = derivationFromPath(*store, drvPath);
|
||||||
hash = newHV();
|
hash = newHV();
|
||||||
|
|
||||||
/* TODO: handle drv.outputs */
|
HV * outputs = newHV();
|
||||||
|
for (DerivationOutputs::iterator i = drv.outputs.begin(); i != drv.outputs.end(); ++i)
|
||||||
|
hv_store(outputs, i->first.c_str(), i->first.size(), newSVpv(i->second.path.c_str(), 0), 0);
|
||||||
|
hv_stores(hash, "outputs", newRV((SV *) outputs));
|
||||||
|
|
||||||
AV * inputDrvs = newAV();
|
AV * inputDrvs = newAV();
|
||||||
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
||||||
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second
|
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second
|
||||||
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
|
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
|
||||||
|
|
||||||
AV * inputSrcs = newAV();
|
AV * inputSrcs = newAV();
|
||||||
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
|
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
|
||||||
av_push(inputSrcs, newSVpv(i->c_str(), 0));
|
av_push(inputSrcs, newSVpv(i->c_str(), 0));
|
||||||
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
|
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
|
||||||
|
|
||||||
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
|
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
|
||||||
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
|
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
|
||||||
|
|
||||||
AV * args = newAV();
|
AV * args = newAV();
|
||||||
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)
|
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)
|
||||||
av_push(args, newSVpv(i->c_str(), 0));
|
av_push(args, newSVpv(i->c_str(), 0));
|
||||||
hv_stores(hash, "args", newRV((SV *) args));
|
hv_stores(hash, "args", newRV((SV *) args));
|
||||||
|
|
||||||
HV * env = newHV();
|
HV * env = newHV();
|
||||||
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i)
|
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i)
|
||||||
hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0);
|
hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0);
|
||||||
hv_stores(hash, "env", newRV((SV *) env));
|
hv_stores(hash, "env", newRV((SV *) env));
|
||||||
|
|
||||||
RETVAL = newRV_noinc((SV *)hash);
|
RETVAL = newRV_noinc((SV *)hash);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak(e.what());
|
croak(e.what());
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package Nix::Utils;
|
||||||
|
|
||||||
|
our @ISA = qw(Exporter);
|
||||||
|
our @EXPORT = qw(checkURL uniq writeFile readFile);
|
||||||
|
|
||||||
|
$urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*]+ )";
|
||||||
|
|
||||||
|
sub checkURL {
|
||||||
|
my ($url) = @_;
|
||||||
|
die "invalid URL ‘$url’\n" unless $url =~ /^ $urlRE $ /x;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uniq {
|
||||||
|
my %seen;
|
||||||
|
my @res;
|
||||||
|
foreach my $name (@_) {
|
||||||
|
next if $seen{$name};
|
||||||
|
$seen{$name} = 1;
|
||||||
|
push @res, $name;
|
||||||
|
}
|
||||||
|
return @res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writeFile {
|
||||||
|
my ($fn, $s) = @_;
|
||||||
|
open TMP, ">$fn" or die "cannot create file `$fn': $!";
|
||||||
|
print TMP "$s" or die;
|
||||||
|
close TMP or die;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub readFile {
|
||||||
|
local $/ = undef;
|
||||||
|
my ($fn) = @_;
|
||||||
|
open TMP, "<$fn" or die "cannot open file `$fn': $!";
|
||||||
|
my $s = <TMP>;
|
||||||
|
close TMP or die;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
+86
-31
@@ -1,15 +1,19 @@
|
|||||||
{ nixpkgs ? <nixpkgs>
|
{ nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
||||||
, nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
|
||||||
, officialRelease ? false
|
, officialRelease ? false
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
pkgs = import <nixpkgs> {};
|
||||||
|
|
||||||
|
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "x86_64-freebsd" "i686-freebsd" "i686-cygwin" "i686-solaris" ];
|
||||||
|
|
||||||
|
|
||||||
jobs = rec {
|
jobs = rec {
|
||||||
|
|
||||||
|
|
||||||
tarball =
|
tarball =
|
||||||
with import nixpkgs {};
|
with pkgs;
|
||||||
|
|
||||||
releaseTools.sourceTarball {
|
releaseTools.sourceTarball {
|
||||||
name = "nix-tarball";
|
name = "nix-tarball";
|
||||||
@@ -19,7 +23,7 @@ let
|
|||||||
inherit officialRelease;
|
inherit officialRelease;
|
||||||
|
|
||||||
buildInputs =
|
buildInputs =
|
||||||
[ curl bison25 flex2535 perl libxml2 libxslt w3m bzip2
|
[ curl bison flex2535 perl libxml2 libxslt w3m bzip2
|
||||||
tetex dblatex nukeReferences pkgconfig sqlite git
|
tetex dblatex nukeReferences pkgconfig sqlite git
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -29,6 +33,7 @@ let
|
|||||||
--with-xml-flags=--nonet
|
--with-xml-flags=--nonet
|
||||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||||
|
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
postUnpack = ''
|
postUnpack = ''
|
||||||
@@ -41,9 +46,18 @@ let
|
|||||||
export VARTEXFONTS=$TMPDIR/texfonts
|
export VARTEXFONTS=$TMPDIR/texfonts
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
distPhase =
|
||||||
|
''
|
||||||
|
runHook preDist
|
||||||
|
make dist-gzip
|
||||||
|
make dist-xz
|
||||||
|
mkdir -p $out/tarballs
|
||||||
|
cp *.tar.* $out/tarballs
|
||||||
|
'';
|
||||||
|
|
||||||
preDist = ''
|
preDist = ''
|
||||||
make -C doc/manual install prefix=$out
|
make -C doc/manual install prefix=$out
|
||||||
|
|
||||||
make -C doc/manual manual.pdf prefix=$out
|
make -C doc/manual manual.pdf prefix=$out
|
||||||
cp doc/manual/manual.pdf $out/manual.pdf
|
cp doc/manual/manual.pdf $out/manual.pdf
|
||||||
|
|
||||||
@@ -54,7 +68,7 @@ let
|
|||||||
# to Windows and Macs, so there should be no Linux binaries
|
# to Windows and Macs, so there should be no Linux binaries
|
||||||
# in the closure).
|
# in the closure).
|
||||||
nuke-refs $out/manual.pdf
|
nuke-refs $out/manual.pdf
|
||||||
|
|
||||||
echo "doc manual $out/share/doc/nix/manual" >> $out/nix-support/hydra-build-products
|
echo "doc manual $out/share/doc/nix/manual" >> $out/nix-support/hydra-build-products
|
||||||
echo "doc-pdf manual $out/manual.pdf" >> $out/nix-support/hydra-build-products
|
echo "doc-pdf manual $out/manual.pdf" >> $out/nix-support/hydra-build-products
|
||||||
echo "doc release-notes $out/share/doc/nix/release-notes" >> $out/nix-support/hydra-build-products
|
echo "doc release-notes $out/share/doc/nix/release-notes" >> $out/nix-support/hydra-build-products
|
||||||
@@ -62,10 +76,9 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
build =
|
build = pkgs.lib.genAttrs systems (system:
|
||||||
{ system ? "i686-linux" }:
|
|
||||||
|
|
||||||
with import nixpkgs { inherit system; };
|
with import <nixpkgs> { inherit system; };
|
||||||
|
|
||||||
releaseTools.nixBuild {
|
releaseTools.nixBuild {
|
||||||
name = "nix";
|
name = "nix";
|
||||||
@@ -77,15 +90,54 @@ let
|
|||||||
--disable-init-state
|
--disable-init-state
|
||||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||||
|
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||||
--enable-gc
|
--enable-gc
|
||||||
|
--sysconfdir=/etc
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
makeFlags = "profiledir=$(out)/etc/profile.d";
|
||||||
|
|
||||||
|
installFlags = "sysconfdir=$(out)/etc";
|
||||||
|
|
||||||
doInstallCheck = true;
|
doInstallCheck = true;
|
||||||
};
|
});
|
||||||
|
|
||||||
|
|
||||||
|
binaryTarball = pkgs.lib.genAttrs systems (system:
|
||||||
|
|
||||||
|
with import <nixpkgs> { inherit system; };
|
||||||
|
|
||||||
|
let
|
||||||
|
toplevel = builtins.getAttr system jobs.build;
|
||||||
|
version = toplevel.src.version;
|
||||||
|
in
|
||||||
|
|
||||||
|
runCommand "nix-binary-tarball-${version}"
|
||||||
|
{ exportReferencesGraph = [ "closure" toplevel ];
|
||||||
|
buildInputs = [ perl ];
|
||||||
|
meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
|
||||||
|
}
|
||||||
|
''
|
||||||
|
storePaths=$(perl ${pathsFromGraph} ./closure)
|
||||||
|
printRegistration=1 perl ${pathsFromGraph} ./closure > $TMPDIR/reginfo
|
||||||
|
substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
|
||||||
|
--subst-var-by nix ${toplevel} --subst-var-by regInfo /nix/store/reginfo
|
||||||
|
chmod +x $TMPDIR/install
|
||||||
|
fn=$out/nix-${version}-${system}.tar.bz2
|
||||||
|
mkdir -p $out/nix-support
|
||||||
|
echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
|
||||||
|
tar cvfj $fn \
|
||||||
|
--owner=0 --group=0 --absolute-names \
|
||||||
|
--transform "s,$TMPDIR/install,/usr/bin/nix-finish-install," \
|
||||||
|
--transform "s,$TMPDIR/reginfo,/nix/store/reginfo," \
|
||||||
|
$TMPDIR/install $TMPDIR/reginfo $storePaths
|
||||||
|
'');
|
||||||
|
|
||||||
|
|
||||||
coverage =
|
coverage =
|
||||||
with import nixpkgs { system = "x86_64-linux"; };
|
with import <nixpkgs> { system = "x86_64-linux"; };
|
||||||
|
|
||||||
releaseTools.coverageAnalysis {
|
releaseTools.coverageAnalysis {
|
||||||
name = "nix-build";
|
name = "nix-build";
|
||||||
@@ -101,12 +153,13 @@ let
|
|||||||
--disable-init-state
|
--disable-init-state
|
||||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||||
|
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
dontInstall = false;
|
dontInstall = false;
|
||||||
|
|
||||||
doInstallCheck = true;
|
doInstallCheck = true;
|
||||||
|
|
||||||
lcovFilter = [ "*/boost/*" "*-tab.*" ];
|
lcovFilter = [ "*/boost/*" "*-tab.*" ];
|
||||||
|
|
||||||
# We call `dot', and even though we just use it to
|
# We call `dot', and even though we just use it to
|
||||||
@@ -115,20 +168,18 @@ let
|
|||||||
FONTCONFIG_FILE = texFunctions.fontsConf;
|
FONTCONFIG_FILE = texFunctions.fontsConf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
rpm_fedora13i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora13i386) 50;
|
|
||||||
rpm_fedora13x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora13x86_64) 50;
|
|
||||||
rpm_fedora16i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora16i386) 50;
|
rpm_fedora16i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora16i386) 50;
|
||||||
rpm_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_64) 50;
|
rpm_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_64) 50;
|
||||||
|
rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) 60;
|
||||||
rpm_opensuse103i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse103i386) 40;
|
rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) 60;
|
||||||
rpm_opensuse110i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse110i386) 50;
|
|
||||||
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.opensuse110x86_64) 50;
|
|
||||||
|
|
||||||
|
|
||||||
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
|
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
|
||||||
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
|
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
|
||||||
|
deb_debian70i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian70i386) 60;
|
||||||
|
deb_debian70x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian70x86_64) 60;
|
||||||
|
|
||||||
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
|
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
|
||||||
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
|
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
|
||||||
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
|
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
|
||||||
@@ -137,15 +188,19 @@ let
|
|||||||
deb_ubuntu1110x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1110x86_64) 60;
|
deb_ubuntu1110x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1110x86_64) 60;
|
||||||
deb_ubuntu1204i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1204i386) 60;
|
deb_ubuntu1204i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1204i386) 60;
|
||||||
deb_ubuntu1204x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1204x86_64) 60;
|
deb_ubuntu1204x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1204x86_64) 60;
|
||||||
|
deb_ubuntu1210i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1210i386) 70;
|
||||||
|
deb_ubuntu1210x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1210x86_64) 70;
|
||||||
|
deb_ubuntu1304i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1304i386) 80;
|
||||||
|
deb_ubuntu1304x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1304x86_64) 80;
|
||||||
|
|
||||||
|
|
||||||
# System tests.
|
# System tests.
|
||||||
tests.remote_builds = (import ./tests/remote-builds.nix rec {
|
tests.remote_builds = (import ./tests/remote-builds.nix rec {
|
||||||
nix = build { inherit system; }; system = "x86_64-linux";
|
nix = build.x86_64-linux; system = "x86_64-linux";
|
||||||
}).test;
|
}).test;
|
||||||
|
|
||||||
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
|
tests.nix_copy_closure = (import ./tests/nix-copy-closure.nix rec {
|
||||||
nix = build { inherit system; }; system = "x86_64-linux";
|
nix = build.x86_64-linux; system = "x86_64-linux";
|
||||||
}).test;
|
}).test;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -154,16 +209,16 @@ let
|
|||||||
makeRPM_i686 = makeRPM "i686-linux";
|
makeRPM_i686 = makeRPM "i686-linux";
|
||||||
makeRPM_x86_64 = makeRPM "x86_64-linux";
|
makeRPM_x86_64 = makeRPM "x86_64-linux";
|
||||||
|
|
||||||
makeRPM =
|
makeRPM =
|
||||||
system: diskImageFun: prio:
|
system: diskImageFun: prio:
|
||||||
|
|
||||||
with import nixpkgs { inherit system; };
|
with import <nixpkgs> { inherit system; };
|
||||||
|
|
||||||
releaseTools.rpmBuild rec {
|
releaseTools.rpmBuild rec {
|
||||||
name = "nix-rpm-${diskImage.name}";
|
name = "nix-rpm";
|
||||||
src = jobs.tarball;
|
src = jobs.tarball;
|
||||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||||
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" ]; };
|
{ extraPackages = [ "perl-DBD-SQLite" "perl-devel" "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "perl-WWW-Curl" ]; };
|
||||||
memSize = 1024;
|
memSize = 1024;
|
||||||
meta.schedulingPriority = prio;
|
meta.schedulingPriority = prio;
|
||||||
postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";
|
postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";
|
||||||
@@ -172,21 +227,21 @@ let
|
|||||||
|
|
||||||
makeDeb_i686 = makeDeb "i686-linux";
|
makeDeb_i686 = makeDeb "i686-linux";
|
||||||
makeDeb_x86_64 = makeDeb "x86_64-linux";
|
makeDeb_x86_64 = makeDeb "x86_64-linux";
|
||||||
|
|
||||||
makeDeb =
|
makeDeb =
|
||||||
system: diskImageFun: prio:
|
system: diskImageFun: prio:
|
||||||
|
|
||||||
with import nixpkgs { inherit system; };
|
with import <nixpkgs> { inherit system; };
|
||||||
|
|
||||||
releaseTools.debBuild {
|
releaseTools.debBuild {
|
||||||
name = "nix-deb";
|
name = "nix-deb";
|
||||||
src = jobs.tarball;
|
src = jobs.tarball;
|
||||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||||
{ extraPackages = [ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" ]; };
|
{ extraPackages = [ "libdbd-sqlite3-perl" "libsqlite3-dev" "libbz2-dev" "libwww-curl-perl" ]; };
|
||||||
memSize = 1024;
|
memSize = 1024;
|
||||||
meta.schedulingPriority = prio;
|
meta.schedulingPriority = prio;
|
||||||
configureFlags = "--sysconfdir=/etc";
|
configureFlags = "--sysconfdir=/etc";
|
||||||
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" ];
|
debRequires = [ "curl" "libdbd-sqlite3-perl" "libsqlite3-0" "libbz2-1.0" "bzip2" "xz-utils" "libwww-curl-perl" ];
|
||||||
doInstallCheck = true;
|
doInstallCheck = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -7,18 +7,18 @@ noinst_SCRIPTS = nix-profile.sh \
|
|||||||
find-runtime-roots.pl build-remote.pl nix-reduce-build \
|
find-runtime-roots.pl build-remote.pl nix-reduce-build \
|
||||||
copy-from-other-stores.pl nix-http-export.cgi
|
copy-from-other-stores.pl nix-http-export.cgi
|
||||||
|
|
||||||
nix-pull nix-push: download-using-manifests.pl
|
profiledir = $(sysconfdir)/profile.d
|
||||||
|
|
||||||
install-exec-local: download-using-manifests.pl copy-from-other-stores.pl find-runtime-roots.pl
|
install-exec-local: download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl find-runtime-roots.pl
|
||||||
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/profile.d
|
$(INSTALL) -d $(DESTDIR)$(profiledir)
|
||||||
$(INSTALL_PROGRAM) nix-profile.sh $(DESTDIR)$(sysconfdir)/profile.d/nix.sh
|
$(INSTALL_DATA) nix-profile.sh $(DESTDIR)$(profiledir)/nix.sh
|
||||||
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix
|
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix
|
||||||
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
|
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
|
||||||
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
|
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
|
||||||
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
|
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
|
||||||
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix/substituters
|
$(INSTALL_PROGRAM) download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl $(DESTDIR)$(libexecdir)/nix/substituters
|
||||||
$(INSTALL_PROGRAM) copy-from-other-stores.pl $(DESTDIR)$(libexecdir)/nix/substituters
|
|
||||||
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
|
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
|
||||||
|
ln -sf nix-build $(DESTDIR)$(bindir)/nix-shell
|
||||||
|
|
||||||
include ../substitute.mk
|
include ../substitute.mk
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ EXTRA_DIST = nix-collect-garbage.in \
|
|||||||
nix-build.in \
|
nix-build.in \
|
||||||
download-using-manifests.pl.in \
|
download-using-manifests.pl.in \
|
||||||
copy-from-other-stores.pl.in \
|
copy-from-other-stores.pl.in \
|
||||||
|
download-from-binary-cache.pl.in \
|
||||||
nix-copy-closure.in \
|
nix-copy-closure.in \
|
||||||
find-runtime-roots.pl.in \
|
find-runtime-roots.pl.in \
|
||||||
build-remote.pl.in \
|
build-remote.pl.in \
|
||||||
|
|||||||
+28
-23
@@ -6,6 +6,7 @@ use IO::Handle;
|
|||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
use Nix::SSH qw/sshOpts openSSHConnection/;
|
use Nix::SSH qw/sshOpts openSSHConnection/;
|
||||||
use Nix::CopyClosure;
|
use Nix::CopyClosure;
|
||||||
|
use Nix::Store;
|
||||||
no warnings('once');
|
no warnings('once');
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ no warnings('once');
|
|||||||
# less than the maximum load for that machine, we try to get an
|
# less than the maximum load for that machine, we try to get an
|
||||||
# exclusive lock on $currentLoad/$machine-$slot (without blocking).
|
# exclusive lock on $currentLoad/$machine-$slot (without blocking).
|
||||||
# If we get such a lock, we send "accept" to the caller. Otherwise,
|
# If we get such a lock, we send "accept" to the caller. Otherwise,
|
||||||
# we send "postpone" and exit.
|
# we send "postpone" and exit.
|
||||||
# - We release the exclusive lock on $currentLoad/main-lock.
|
# - We release the exclusive lock on $currentLoad/main-lock.
|
||||||
# - We perform the build on $neededSystem.
|
# - We perform the build on $neededSystem.
|
||||||
# - We release the exclusive lock on $currentLoad/$machine-$slot.
|
# - We release the exclusive lock on $currentLoad/$machine-$slot.
|
||||||
@@ -45,8 +46,7 @@ sub all { $_ || return 0 for @_; 1 }
|
|||||||
# Initialisation.
|
# Initialisation.
|
||||||
my $loadIncreased = 0;
|
my $loadIncreased = 0;
|
||||||
|
|
||||||
my ($localSystem, $maxSilentTime, $printBuildTrace) = @ARGV;
|
my ($localSystem, $maxSilentTime, $printBuildTrace, $buildTimeout) = @ARGV;
|
||||||
$maxSilentTime = 0 unless defined $maxSilentTime;
|
|
||||||
|
|
||||||
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
|
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
|
||||||
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
|
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
|
||||||
@@ -102,14 +102,14 @@ REQ: while (1) {
|
|||||||
sendReply "decline";
|
sendReply "decline";
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Acquire the exclusive lock on $currentLoad/main-lock.
|
# Acquire the exclusive lock on $currentLoad/main-lock.
|
||||||
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
|
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
|
||||||
my $mainLock = "$currentLoad/main-lock";
|
my $mainLock = "$currentLoad/main-lock";
|
||||||
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
|
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
|
||||||
flock(MAINLOCK, LOCK_EX) or die;
|
flock(MAINLOCK, LOCK_EX) or die;
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
# Find all machine that can execute this build, i.e., that
|
# Find all machine that can execute this build, i.e., that
|
||||||
# support builds for the given platform and features, and are
|
# support builds for the given platform and features, and are
|
||||||
@@ -141,7 +141,7 @@ REQ: while (1) {
|
|||||||
close $slotLock;
|
close $slotLock;
|
||||||
$slot++;
|
$slot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
push @available, { machine => $cur, load => $load, free => $free }
|
push @available, { machine => $cur, load => $load, free => $free }
|
||||||
if $load < $cur->{maxJobs};
|
if $load < $cur->{maxJobs};
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ REQ: while (1) {
|
|||||||
if ($rightType && !$canBuildLocally) {
|
if ($rightType && !$canBuildLocally) {
|
||||||
sendReply "postpone";
|
sendReply "postpone";
|
||||||
} else {
|
} else {
|
||||||
sendReply "decline";
|
sendReply "decline";
|
||||||
}
|
}
|
||||||
close MAINLOCK;
|
close MAINLOCK;
|
||||||
next REQ;
|
next REQ;
|
||||||
@@ -182,9 +182,9 @@ REQ: while (1) {
|
|||||||
|
|
||||||
|
|
||||||
# Select the best available machine and lock a free slot.
|
# Select the best available machine and lock a free slot.
|
||||||
my $selected = $available[0];
|
my $selected = $available[0];
|
||||||
my $machine = $selected->{machine};
|
my $machine = $selected->{machine};
|
||||||
|
|
||||||
$slotLock = openSlotLock($machine, $selected->{free});
|
$slotLock = openSlotLock($machine, $selected->{free});
|
||||||
flock($slotLock, LOCK_EX | LOCK_NB) or die;
|
flock($slotLock, LOCK_EX | LOCK_NB) or die;
|
||||||
utime undef, undef, $slotLock;
|
utime undef, undef, $slotLock;
|
||||||
@@ -195,9 +195,13 @@ REQ: while (1) {
|
|||||||
# Connect to the selected machine.
|
# Connect to the selected machine.
|
||||||
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
|
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
|
||||||
$hostName = $machine->{hostName};
|
$hostName = $machine->{hostName};
|
||||||
last REQ if openSSHConnection $hostName;
|
if (openSSHConnection($hostName)) {
|
||||||
|
last REQ if system("ssh $hostName @sshOpts nix-builds-inhibited < /dev/null > /dev/null 2>&1") != 0;
|
||||||
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
|
warn "machine `$hostName' is refusing builds, trying other available machines...\n";
|
||||||
|
closeSSHConnection;
|
||||||
|
} else {
|
||||||
|
warn "unable to open SSH connection to `$hostName', trying other available machines...\n";
|
||||||
|
}
|
||||||
$machine->{enabled} = 0;
|
$machine->{enabled} = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +213,6 @@ my @inputs = split /\s/, readline(STDIN);
|
|||||||
my @outputs = split /\s/, readline(STDIN);
|
my @outputs = split /\s/, readline(STDIN);
|
||||||
|
|
||||||
|
|
||||||
print STDERR "building `$drvPath' on `$hostName'\n";
|
|
||||||
print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
|
print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace;
|
||||||
|
|
||||||
|
|
||||||
@@ -257,7 +260,10 @@ close UPLOADLOCK;
|
|||||||
|
|
||||||
|
|
||||||
# Perform the build.
|
# Perform the build.
|
||||||
my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsDir/\$PPID.out --option verbosity 0";
|
my $buildFlags =
|
||||||
|
"--max-silent-time $maxSilentTime --option build-timeout $buildTimeout"
|
||||||
|
. " --fallback --add-root $rootsDir/\$PPID.out --quiet"
|
||||||
|
. " --option build-keep-log false";
|
||||||
|
|
||||||
# We let the remote side kill its process group when the connection is
|
# We let the remote side kill its process group when the connection is
|
||||||
# closed unexpectedly. This is necessary to ensure that no processes
|
# closed unexpectedly. This is necessary to ensure that no processes
|
||||||
@@ -266,8 +272,9 @@ my $buildFlags = "--max-silent-time $maxSilentTime --fallback --add-root $rootsD
|
|||||||
# is interrupted unless the `-tt' flag is used to force a pseudo-tty,
|
# is interrupted unless the `-tt' flag is used to force a pseudo-tty,
|
||||||
# in which case every child receives SIGHUP; however, `-tt' doesn't
|
# in which case every child receives SIGHUP; however, `-tt' doesn't
|
||||||
# work on some platforms when connection sharing is used.)
|
# work on some platforms when connection sharing is used.)
|
||||||
|
print STDERR "building `$drvPath' on `$hostName'\n";
|
||||||
pipe STDIN, DUMMY; # make sure we have a readable STDIN
|
pipe STDIN, DUMMY; # make sure we have a readable STDIN
|
||||||
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
|
if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & exec nix-store -r $drvPath $buildFlags > /dev/null' 2>&4") != 0) {
|
||||||
# Note that if we get exit code 100 from `nix-store -r', it
|
# Note that if we get exit code 100 from `nix-store -r', it
|
||||||
# denotes a permanent build failure (as opposed to an SSH problem
|
# denotes a permanent build failure (as opposed to an SSH problem
|
||||||
# or a temporary Nix problem). We propagate this to the caller to
|
# or a temporary Nix problem). We propagate this to the caller to
|
||||||
@@ -283,13 +290,11 @@ if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store
|
|||||||
|
|
||||||
|
|
||||||
# Copy the output from the build machine.
|
# Copy the output from the build machine.
|
||||||
foreach my $output (@outputs) {
|
my @outputs2 = grep { !isValidPath($_) } @outputs;
|
||||||
my $maybeSignRemote = "";
|
if (scalar @outputs2 > 0) {
|
||||||
$maybeSignRemote = "--sign" if $UID != 0;
|
system("exec ssh $hostName @sshOpts 'nix-store --export @outputs2'" .
|
||||||
|
"| NIX_HELD_LOCKS='@outputs2' @bindir@/nix-store --import > /dev/null") == 0
|
||||||
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
|
or die("cannot copy paths " . join(", ", @outputs) . " from `$hostName': $?");
|
||||||
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
|
|
||||||
or die "cannot copy $output from $hostName: $?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ foreach my $dir (@remoteStoresAll) {
|
|||||||
push @remoteStores, glob($dir);
|
push @remoteStores, glob($dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit if scalar @remoteStores == 0;
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
|
||||||
$ENV{"NIX_REMOTE"} = "";
|
$ENV{"NIX_REMOTE"} = "";
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ sub findStorePath {
|
|||||||
next unless -e $sourcePath || -l $sourcePath;
|
next unless -e $sourcePath || -l $sourcePath;
|
||||||
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
||||||
return ($store, $sourcePath) if
|
return ($store, $sourcePath) if
|
||||||
system("@bindir@/nix-store --check-validity $storePath") == 0;
|
system("$binDir/nix-store --check-validity $storePath") == 0;
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@@ -36,42 +39,45 @@ sub findStorePath {
|
|||||||
if ($ARGV[0] eq "--query") {
|
if ($ARGV[0] eq "--query") {
|
||||||
|
|
||||||
while (<STDIN>) {
|
while (<STDIN>) {
|
||||||
my $cmd = $_; chomp $cmd;
|
chomp;
|
||||||
|
my ($cmd, @args) = split " ", $_;
|
||||||
|
|
||||||
if ($cmd eq "have") {
|
if ($cmd eq "have") {
|
||||||
my $storePath = <STDIN>; chomp $storePath;
|
foreach my $storePath (@args) {
|
||||||
print STDOUT (defined findStorePath($storePath) ? "1\n" : "0\n");
|
print "$storePath\n" if defined findStorePath($storePath);
|
||||||
|
}
|
||||||
|
print "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($cmd eq "info") {
|
elsif ($cmd eq "info") {
|
||||||
my $storePath = <STDIN>; chomp $storePath;
|
foreach my $storePath (@args) {
|
||||||
my ($store, $sourcePath) = findStorePath($storePath);
|
my ($store, $sourcePath) = findStorePath($storePath);
|
||||||
if (!defined $store) {
|
next unless defined $store;
|
||||||
|
|
||||||
|
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
||||||
|
|
||||||
|
my $deriver = `$binDir/nix-store --query --deriver $storePath`;
|
||||||
|
die "cannot query deriver of `$storePath'" if $? != 0;
|
||||||
|
chomp $deriver;
|
||||||
|
$deriver = "" if $deriver eq "unknown-deriver";
|
||||||
|
|
||||||
|
my @references = split "\n",
|
||||||
|
`$binDir/nix-store --query --references $storePath`;
|
||||||
|
die "cannot query references of `$storePath'" if $? != 0;
|
||||||
|
|
||||||
|
my $narSize = `$binDir/nix-store --query --size $storePath`;
|
||||||
|
die "cannot query size of `$storePath'" if $? != 0;
|
||||||
|
chomp $narSize;
|
||||||
|
|
||||||
|
print "$storePath\n";
|
||||||
|
print "$deriver\n";
|
||||||
|
print scalar @references, "\n";
|
||||||
|
print "$_\n" foreach @references;
|
||||||
print "0\n";
|
print "0\n";
|
||||||
next; # not an error
|
print "$narSize\n";
|
||||||
}
|
}
|
||||||
print "1\n";
|
|
||||||
|
|
||||||
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
print "\n";
|
||||||
|
|
||||||
my $deriver = `@bindir@/nix-store --query --deriver $storePath`;
|
|
||||||
die "cannot query deriver of `$storePath'" if $? != 0;
|
|
||||||
chomp $deriver;
|
|
||||||
$deriver = "" if $deriver eq "unknown-deriver";
|
|
||||||
|
|
||||||
my @references = split "\n",
|
|
||||||
`@bindir@/nix-store --query --references $storePath`;
|
|
||||||
die "cannot query references of `$storePath'" if $? != 0;
|
|
||||||
|
|
||||||
my $narSize = `@bindir@/nix-store --query --size $storePath`;
|
|
||||||
die "cannot query size of `$storePath'" if $? != 0;
|
|
||||||
chomp $narSize;
|
|
||||||
|
|
||||||
print "$deriver\n";
|
|
||||||
print scalar @references, "\n";
|
|
||||||
print "$_\n" foreach @references;
|
|
||||||
print "$narSize\n";
|
|
||||||
print "$narSize\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else { die "unknown command `$cmd'"; }
|
else { die "unknown command `$cmd'"; }
|
||||||
@@ -80,13 +86,15 @@ if ($ARGV[0] eq "--query") {
|
|||||||
|
|
||||||
|
|
||||||
elsif ($ARGV[0] eq "--substitute") {
|
elsif ($ARGV[0] eq "--substitute") {
|
||||||
die unless scalar @ARGV == 2;
|
die unless scalar @ARGV == 3;
|
||||||
my $storePath = $ARGV[1];
|
my $storePath = $ARGV[1];
|
||||||
|
my $destPath = $ARGV[2];
|
||||||
my ($store, $sourcePath) = findStorePath $storePath;
|
my ($store, $sourcePath) = findStorePath $storePath;
|
||||||
die unless $store;
|
die unless $store;
|
||||||
print "\n*** Copying `$storePath' from `$sourcePath'\n\n";
|
print STDERR "\n*** Copying `$storePath' from `$sourcePath'\n\n";
|
||||||
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $storePath") == 0
|
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $destPath") == 0
|
||||||
or die "cannot copy `$sourcePath' to `$storePath'";
|
or die "cannot copy `$sourcePath' to `$storePath'";
|
||||||
|
print "\n"; # no hash to verify
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,588 @@
|
|||||||
|
#! @perl@ -w @perlFlags@
|
||||||
|
|
||||||
|
use DBI;
|
||||||
|
use File::Basename;
|
||||||
|
use IO::Select;
|
||||||
|
use Nix::Config;
|
||||||
|
use Nix::Store;
|
||||||
|
use Nix::Utils;
|
||||||
|
use Nix::Manifest;
|
||||||
|
use WWW::Curl::Easy;
|
||||||
|
use WWW::Curl::Multi;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
|
||||||
|
Nix::Config::readConfig;
|
||||||
|
|
||||||
|
my @caches;
|
||||||
|
my $gotCaches = 0;
|
||||||
|
|
||||||
|
my $maxParallelRequests = int($Nix::Config::config{"binary-caches-parallel-connections"} // 150);
|
||||||
|
$maxParallelRequests = 1 if $maxParallelRequests < 1;
|
||||||
|
|
||||||
|
my $ttlNegative = 24 * 3600; # when to purge negative lookups from the database
|
||||||
|
my $ttlNegativeUse = 3600; # how long negative lookups are valid for non-"have" lookups
|
||||||
|
my $didExpiration = 0;
|
||||||
|
|
||||||
|
my $showAfter = 5; # show that we're waiting for a request after this many seconds
|
||||||
|
|
||||||
|
my $debug = ($Nix::Config::config{"debug-subst"} // "") eq 1 || ($Nix::Config::config{"untrusted-debug-subst"} // "") eq 1;
|
||||||
|
|
||||||
|
my $cacheFileURLs = ($ENV{"_NIX_CACHE_FILE_URLS"} // "") eq 1; # for testing
|
||||||
|
|
||||||
|
my ($dbh, $queryCache, $insertNAR, $queryNAR, $insertNARExistence, $queryNARExistence, $expireNARExistence);
|
||||||
|
|
||||||
|
my $curlm = WWW::Curl::Multi->new;
|
||||||
|
my $activeRequests = 0;
|
||||||
|
my $curlIdCount = 1;
|
||||||
|
my %requests;
|
||||||
|
my %scheduled;
|
||||||
|
my $caBundle = $ENV{"CURL_CA_BUNDLE"} // $ENV{"OPENSSL_X509_CERT_FILE"};
|
||||||
|
|
||||||
|
my $userName = getpwuid($<) or die "cannot figure out user name";
|
||||||
|
|
||||||
|
|
||||||
|
sub addRequest {
|
||||||
|
my ($storePath, $url, $head) = @_;
|
||||||
|
|
||||||
|
my $curl = WWW::Curl::Easy->new;
|
||||||
|
my $curlId = $curlIdCount++;
|
||||||
|
$requests{$curlId} = { storePath => $storePath, url => $url, handle => $curl, content => "", type => $head ? "HEAD" : "GET"
|
||||||
|
, shown => 0, started => time() };
|
||||||
|
|
||||||
|
$curl->setopt(CURLOPT_PRIVATE, $curlId);
|
||||||
|
$curl->setopt(CURLOPT_URL, $url);
|
||||||
|
open (my $fh, ">", \$requests{$curlId}->{content});
|
||||||
|
$curl->setopt(CURLOPT_WRITEDATA, $fh);
|
||||||
|
$curl->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
$curl->setopt(CURLOPT_CAINFO, $caBundle) if defined $caBundle;
|
||||||
|
$curl->setopt(CURLOPT_USERAGENT, "Nix/$Nix::Config::version");
|
||||||
|
$curl->setopt(CURLOPT_NOBODY, 1) if $head;
|
||||||
|
$curl->setopt(CURLOPT_FAILONERROR, 1);
|
||||||
|
$curl->setopt(CURLOPT_TIMEOUT, int($ENV{"NIX_CONNECT_TIMEOUT"} // 0));
|
||||||
|
|
||||||
|
if ($activeRequests >= $maxParallelRequests) {
|
||||||
|
$scheduled{$curlId} = 1;
|
||||||
|
} else {
|
||||||
|
$curlm->add_handle($curl);
|
||||||
|
$activeRequests++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requests{$curlId};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub processRequests {
|
||||||
|
while ($activeRequests) {
|
||||||
|
my ($rfds, $wfds, $efds) = $curlm->fdset();
|
||||||
|
#print STDERR "R = @{$rfds}, W = @{$wfds}, E = @{$efds}\n";
|
||||||
|
|
||||||
|
# Sleep until we can read or write some data.
|
||||||
|
if (scalar @{$rfds} + scalar @{$wfds} + scalar @{$efds} > 0) {
|
||||||
|
IO::Select->select(IO::Select->new(@{$rfds}), IO::Select->new(@{$wfds}), IO::Select->new(@{$efds}), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($curlm->perform() != $activeRequests) {
|
||||||
|
while (my ($id, $result) = $curlm->info_read) {
|
||||||
|
if ($id) {
|
||||||
|
my $request = $requests{$id} or die;
|
||||||
|
my $handle = $request->{handle};
|
||||||
|
$request->{result} = $result;
|
||||||
|
$request->{httpStatus} = $handle->getinfo(CURLINFO_RESPONSE_CODE);
|
||||||
|
|
||||||
|
print STDERR "$request->{type} on $request->{url} [$request->{result}, $request->{httpStatus}]\n" if $debug;
|
||||||
|
|
||||||
|
$activeRequests--;
|
||||||
|
delete $request->{handle};
|
||||||
|
|
||||||
|
if (scalar(keys %scheduled) > 0) {
|
||||||
|
my $id2 = (keys %scheduled)[0];
|
||||||
|
$curlm->add_handle($requests{$id2}->{handle});
|
||||||
|
$activeRequests++;
|
||||||
|
delete $scheduled{$id2};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $time = time();
|
||||||
|
while (my ($key, $request) = each %requests) {
|
||||||
|
next unless defined $request->{handle};
|
||||||
|
next if $request->{shown};
|
||||||
|
if ($time > $request->{started} + $showAfter) {
|
||||||
|
print STDERR "still waiting for ‘$request->{url}’ after $showAfter seconds...\n";
|
||||||
|
$request->{shown} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub initCache {
|
||||||
|
my $dbPath = "$Nix::Config::stateDir/binary-cache-v2.sqlite";
|
||||||
|
|
||||||
|
unlink "$Nix::Config::stateDir/binary-cache-v1.sqlite";
|
||||||
|
|
||||||
|
# Open/create the database.
|
||||||
|
$dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
|
||||||
|
or die "cannot open database `$dbPath'";
|
||||||
|
$dbh->{RaiseError} = 1;
|
||||||
|
$dbh->{PrintError} = 0;
|
||||||
|
|
||||||
|
$dbh->sqlite_busy_timeout(60 * 60 * 1000);
|
||||||
|
|
||||||
|
$dbh->do("pragma synchronous = off"); # we can always reproduce the cache
|
||||||
|
$dbh->do("pragma journal_mode = truncate");
|
||||||
|
|
||||||
|
# Initialise the database schema, if necessary.
|
||||||
|
$dbh->do(<<EOF);
|
||||||
|
create table if not exists BinaryCaches (
|
||||||
|
id integer primary key autoincrement not null,
|
||||||
|
url text unique not null,
|
||||||
|
timestamp integer not null,
|
||||||
|
storeDir text not null,
|
||||||
|
wantMassQuery integer not null,
|
||||||
|
priority integer not null
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$dbh->do(<<EOF);
|
||||||
|
create table if not exists NARs (
|
||||||
|
cache integer not null,
|
||||||
|
storePath text not null,
|
||||||
|
url text not null,
|
||||||
|
compression text not null,
|
||||||
|
fileHash text,
|
||||||
|
fileSize integer,
|
||||||
|
narHash text,
|
||||||
|
narSize integer,
|
||||||
|
refs text,
|
||||||
|
deriver text,
|
||||||
|
system text,
|
||||||
|
timestamp integer not null,
|
||||||
|
primary key (cache, storePath),
|
||||||
|
foreign key (cache) references BinaryCaches(id) on delete cascade
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$dbh->do(<<EOF);
|
||||||
|
create table if not exists NARExistence (
|
||||||
|
cache integer not null,
|
||||||
|
storePath text not null,
|
||||||
|
exist integer not null,
|
||||||
|
timestamp integer not null,
|
||||||
|
primary key (cache, storePath),
|
||||||
|
foreign key (cache) references BinaryCaches(id) on delete cascade
|
||||||
|
);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$dbh->do("create index if not exists NARExistenceByExistTimestamp on NARExistence (exist, timestamp)");
|
||||||
|
|
||||||
|
$queryCache = $dbh->prepare("select id, storeDir, wantMassQuery, priority from BinaryCaches where url = ?") or die;
|
||||||
|
|
||||||
|
$insertNAR = $dbh->prepare(
|
||||||
|
"insert or replace into NARs(cache, storePath, url, compression, fileHash, fileSize, narHash, " .
|
||||||
|
"narSize, refs, deriver, system, timestamp) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
|
||||||
|
|
||||||
|
$queryNAR = $dbh->prepare("select * from NARs where cache = ? and storePath = ?") or die;
|
||||||
|
|
||||||
|
$insertNARExistence = $dbh->prepare(
|
||||||
|
"insert or replace into NARExistence(cache, storePath, exist, timestamp) values (?, ?, ?, ?)") or die;
|
||||||
|
|
||||||
|
$queryNARExistence = $dbh->prepare("select exist, timestamp from NARExistence where cache = ? and storePath = ?") or die;
|
||||||
|
|
||||||
|
$expireNARExistence = $dbh->prepare("delete from NARExistence where exist = ? and timestamp < ?") or die;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub getAvailableCaches {
|
||||||
|
return if $gotCaches;
|
||||||
|
$gotCaches = 1;
|
||||||
|
|
||||||
|
sub strToList {
|
||||||
|
my ($s) = @_;
|
||||||
|
return map { s/\/+$//; $_ } split(/ /, $s);
|
||||||
|
}
|
||||||
|
|
||||||
|
my @urls = strToList($Nix::Config::config{"binary-caches"} //
|
||||||
|
($Nix::Config::storeDir eq "/nix/store" ? "http://cache.nixos.org" : ""));
|
||||||
|
|
||||||
|
my $urlsFiles = $Nix::Config::config{"binary-cache-files"}
|
||||||
|
// "$Nix::Config::stateDir/profiles/per-user/$userName/channels/binary-caches/*";
|
||||||
|
foreach my $urlFile (glob $urlsFiles) {
|
||||||
|
next unless -f $urlFile;
|
||||||
|
open FILE, "<$urlFile" or die "cannot open ‘$urlFile’\n";
|
||||||
|
my $url = <FILE>; chomp $url;
|
||||||
|
close FILE;
|
||||||
|
push @urls, strToList($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
push @urls, strToList($Nix::Config::config{"extra-binary-caches"} // "");
|
||||||
|
|
||||||
|
# Allow Nix daemon users to override the binary caches to a subset
|
||||||
|
# of those listed in the config file. Note that ‘untrusted-*’
|
||||||
|
# denotes options passed by the client.
|
||||||
|
my @trustedUrls = uniq(@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
|
||||||
|
|
||||||
|
if (defined $Nix::Config::config{"untrusted-binary-caches"}) {
|
||||||
|
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-binary-caches"};
|
||||||
|
@urls = ();
|
||||||
|
foreach my $url (@untrustedUrls) {
|
||||||
|
die "binary cache ‘$url’ is not trusted (please add it to ‘trusted-binary-caches’ [@trustedUrls] in $Nix::Config::confDir/nix.conf)\n"
|
||||||
|
unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
|
||||||
|
push @urls, $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"} // "";
|
||||||
|
foreach my $url (@untrustedUrls) {
|
||||||
|
next unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
|
||||||
|
push @urls, $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $url (uniq @urls) {
|
||||||
|
|
||||||
|
# FIXME: not atomic.
|
||||||
|
$queryCache->execute($url);
|
||||||
|
my $res = $queryCache->fetchrow_hashref();
|
||||||
|
if (defined $res) {
|
||||||
|
next if $res->{storeDir} ne $Nix::Config::storeDir;
|
||||||
|
push @caches, { id => $res->{id}, url => $url, wantMassQuery => $res->{wantMassQuery}, priority => $res->{priority} };
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the cache info file.
|
||||||
|
my $request = addRequest(undef, $url . "/nix-cache-info");
|
||||||
|
processRequests;
|
||||||
|
|
||||||
|
if ($request->{result} != 0) {
|
||||||
|
print STDERR "could not download ‘$request->{url}’ (" .
|
||||||
|
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $storeDir = "/nix/store";
|
||||||
|
my $wantMassQuery = 0;
|
||||||
|
my $priority = 50;
|
||||||
|
foreach my $line (split "\n", $request->{content}) {
|
||||||
|
unless ($line =~ /^(.*): (.*)$/) {
|
||||||
|
print STDERR "bad cache info file ‘$request->{url}’\n";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
if ($1 eq "StoreDir") { $storeDir = $2; }
|
||||||
|
elsif ($1 eq "WantMassQuery") { $wantMassQuery = int($2); }
|
||||||
|
elsif ($1 eq "Priority") { $priority = int($2); }
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbh->do("insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)",
|
||||||
|
{}, $url, time(), $storeDir, $wantMassQuery, $priority);
|
||||||
|
$queryCache->execute($url);
|
||||||
|
$res = $queryCache->fetchrow_hashref() or die;
|
||||||
|
next if $storeDir ne $Nix::Config::storeDir;
|
||||||
|
push @caches, { id => $res->{id}, url => $url, wantMassQuery => $wantMassQuery, priority => $priority };
|
||||||
|
}
|
||||||
|
|
||||||
|
@caches = sort { $a->{priority} <=> $b->{priority} } @caches;
|
||||||
|
|
||||||
|
expireNegative();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub shouldCache {
|
||||||
|
my ($url) = @_;
|
||||||
|
return $cacheFileURLs || $url !~ /^file:/;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub processNARInfo {
|
||||||
|
my ($storePath, $cache, $request) = @_;
|
||||||
|
|
||||||
|
if ($request->{result} != 0) {
|
||||||
|
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
|
||||||
|
print STDERR "could not download ‘$request->{url}’ (" .
|
||||||
|
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
|
||||||
|
} else {
|
||||||
|
$insertNARExistence->execute($cache->{id}, basename($storePath), 0, time())
|
||||||
|
if shouldCache $request->{url};
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $narInfo = parseNARInfo($storePath, $request->{content});
|
||||||
|
return undef unless defined $narInfo;
|
||||||
|
|
||||||
|
# Cache the result.
|
||||||
|
$insertNAR->execute(
|
||||||
|
$cache->{id}, basename($storePath), $narInfo->{url}, $narInfo->{compression},
|
||||||
|
$narInfo->{fileHash}, $narInfo->{fileSize}, $narInfo->{narHash}, $narInfo->{narSize},
|
||||||
|
join(" ", @{$narInfo->{refs}}), $narInfo->{deriver}, $narInfo->{system}, time())
|
||||||
|
if shouldCache $request->{url};
|
||||||
|
|
||||||
|
return $narInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub getCachedInfoFrom {
|
||||||
|
my ($storePath, $cache) = @_;
|
||||||
|
|
||||||
|
$queryNAR->execute($cache->{id}, basename($storePath));
|
||||||
|
my $res = $queryNAR->fetchrow_hashref();
|
||||||
|
return undef unless defined $res;
|
||||||
|
|
||||||
|
return
|
||||||
|
{ url => $res->{url}
|
||||||
|
, compression => $res->{compression}
|
||||||
|
, fileHash => $res->{fileHash}
|
||||||
|
, fileSize => $res->{fileSize}
|
||||||
|
, narHash => $res->{narHash}
|
||||||
|
, narSize => $res->{narSize}
|
||||||
|
, refs => [ split " ", $res->{refs} ]
|
||||||
|
, deriver => $res->{deriver}
|
||||||
|
} if defined $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub negativeHit {
|
||||||
|
my ($storePath, $cache) = @_;
|
||||||
|
$queryNARExistence->execute($cache->{id}, basename($storePath));
|
||||||
|
my $res = $queryNARExistence->fetchrow_hashref();
|
||||||
|
return defined $res && $res->{exist} == 0 && time() - $res->{timestamp} < $ttlNegativeUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub positiveHit {
|
||||||
|
my ($storePath, $cache) = @_;
|
||||||
|
return 1 if defined getCachedInfoFrom($storePath, $cache);
|
||||||
|
$queryNARExistence->execute($cache->{id}, basename($storePath));
|
||||||
|
my $res = $queryNARExistence->fetchrow_hashref();
|
||||||
|
return defined $res && $res->{exist} == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub expireNegative {
|
||||||
|
return if $didExpiration;
|
||||||
|
$didExpiration = 1;
|
||||||
|
my $time = time();
|
||||||
|
# Round up to the next multiple of the TTL to ensure that we do
|
||||||
|
# expiration only once per time interval. E.g. if $ttlNegative ==
|
||||||
|
# 3600, we expire entries at most once per hour. This is
|
||||||
|
# presumably faster than expiring a few entries per request (and
|
||||||
|
# thus doing a transaction).
|
||||||
|
my $limit = (int($time / $ttlNegative) - 1) * $ttlNegative;
|
||||||
|
$expireNARExistence->execute($limit, 0);
|
||||||
|
print STDERR "expired ", $expireNARExistence->rows, " negative entries\n" if $debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub printInfo {
|
||||||
|
my ($storePath, $info) = @_;
|
||||||
|
print "$storePath\n";
|
||||||
|
print $info->{deriver} ? "$Nix::Config::storeDir/$info->{deriver}" : "", "\n";
|
||||||
|
print scalar @{$info->{refs}}, "\n";
|
||||||
|
print "$Nix::Config::storeDir/$_\n" foreach @{$info->{refs}};
|
||||||
|
print $info->{fileSize} || 0, "\n";
|
||||||
|
print $info->{narSize} || 0, "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub infoUrl {
|
||||||
|
my ($binaryCacheUrl, $storePath) = @_;
|
||||||
|
my $pathHash = substr(basename($storePath), 0, 32);
|
||||||
|
my $infoUrl = "$binaryCacheUrl/$pathHash.narinfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub printInfoParallel {
|
||||||
|
my @paths = @_;
|
||||||
|
|
||||||
|
# First print all paths for which we have cached info.
|
||||||
|
my @left;
|
||||||
|
foreach my $storePath (@paths) {
|
||||||
|
my $found = 0;
|
||||||
|
foreach my $cache (@caches) {
|
||||||
|
my $info = getCachedInfoFrom($storePath, $cache);
|
||||||
|
if (defined $info) {
|
||||||
|
printInfo($storePath, $info);
|
||||||
|
$found = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push @left, $storePath if !$found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return if scalar @left == 0;
|
||||||
|
|
||||||
|
foreach my $cache (@caches) {
|
||||||
|
|
||||||
|
my @left2;
|
||||||
|
%requests = ();
|
||||||
|
foreach my $storePath (@left) {
|
||||||
|
if (negativeHit($storePath, $cache)) {
|
||||||
|
push @left2, $storePath;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
addRequest($storePath, infoUrl($cache->{url}, $storePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
processRequests;
|
||||||
|
|
||||||
|
foreach my $request (values %requests) {
|
||||||
|
my $info = processNARInfo($request->{storePath}, $cache, $request);
|
||||||
|
if (defined $info) {
|
||||||
|
printInfo($request->{storePath}, $info);
|
||||||
|
} else {
|
||||||
|
push @left2, $request->{storePath};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@left = @left2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub printSubstitutablePaths {
|
||||||
|
my @paths = @_;
|
||||||
|
|
||||||
|
# First look for paths that have cached info.
|
||||||
|
my @left;
|
||||||
|
foreach my $storePath (@paths) {
|
||||||
|
my $found = 0;
|
||||||
|
foreach my $cache (@caches) {
|
||||||
|
next unless $cache->{wantMassQuery};
|
||||||
|
if (positiveHit($storePath, $cache)) {
|
||||||
|
print "$storePath\n";
|
||||||
|
$found = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push @left, $storePath if !$found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return if scalar @left == 0;
|
||||||
|
|
||||||
|
# For remaining paths, do HEAD requests.
|
||||||
|
foreach my $cache (@caches) {
|
||||||
|
next unless $cache->{wantMassQuery};
|
||||||
|
my @left2;
|
||||||
|
%requests = ();
|
||||||
|
foreach my $storePath (@left) {
|
||||||
|
if (negativeHit($storePath, $cache)) {
|
||||||
|
push @left2, $storePath;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
addRequest($storePath, infoUrl($cache->{url}, $storePath), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
processRequests;
|
||||||
|
|
||||||
|
foreach my $request (values %requests) {
|
||||||
|
if ($request->{result} != 0) {
|
||||||
|
if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
|
||||||
|
print STDERR "could not check ‘$request->{url}’ (" .
|
||||||
|
($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
|
||||||
|
} else {
|
||||||
|
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 0, time())
|
||||||
|
if shouldCache $request->{url};
|
||||||
|
}
|
||||||
|
push @left2, $request->{storePath};
|
||||||
|
} else {
|
||||||
|
$insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 1, time())
|
||||||
|
if shouldCache $request->{url};
|
||||||
|
print "$request->{storePath}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@left = @left2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub downloadBinary {
|
||||||
|
my ($storePath, $destPath) = @_;
|
||||||
|
|
||||||
|
foreach my $cache (@caches) {
|
||||||
|
my $info = getCachedInfoFrom($storePath, $cache);
|
||||||
|
|
||||||
|
unless (defined $info) {
|
||||||
|
next if negativeHit($storePath, $cache);
|
||||||
|
my $request = addRequest($storePath, infoUrl($cache->{url}, $storePath));
|
||||||
|
processRequests;
|
||||||
|
$info = processNARInfo($storePath, $cache, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
next unless defined $info;
|
||||||
|
|
||||||
|
my $decompressor;
|
||||||
|
if ($info->{compression} eq "bzip2") { $decompressor = "| $Nix::Config::bzip2 -d"; }
|
||||||
|
elsif ($info->{compression} eq "xz") { $decompressor = "| $Nix::Config::xz -d"; }
|
||||||
|
elsif ($info->{compression} eq "none") { $decompressor = ""; }
|
||||||
|
else {
|
||||||
|
print STDERR "unknown compression method ‘$info->{compression}’\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my $url = "$cache->{url}/$info->{url}"; # FIXME: handle non-relative URLs
|
||||||
|
print STDERR "\n*** Downloading ‘$url’ to ‘$storePath’...\n";
|
||||||
|
checkURL $url;
|
||||||
|
if (system("$Nix::Config::curl --fail --location --insecure '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
|
||||||
|
warn "download of `$url' failed" . ($! ? ": $!" : "") . "\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tell Nix about the expected hash so it can verify it.
|
||||||
|
print "$info->{narHash}\n";
|
||||||
|
|
||||||
|
print STDERR "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print STDERR "could not download ‘$storePath’ from any binary cache\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Bail out right away if binary caches are disabled.
|
||||||
|
exit 0 if
|
||||||
|
($Nix::Config::config{"use-binary-caches"} // "true") eq "false" ||
|
||||||
|
($Nix::Config::config{"untrusted-use-binary-caches"} // "true") eq "false";
|
||||||
|
print "\n";
|
||||||
|
flush STDOUT;
|
||||||
|
|
||||||
|
initCache();
|
||||||
|
|
||||||
|
|
||||||
|
if ($ARGV[0] eq "--query") {
|
||||||
|
|
||||||
|
while (<STDIN>) {
|
||||||
|
getAvailableCaches;
|
||||||
|
chomp;
|
||||||
|
my ($cmd, @args) = split " ", $_;
|
||||||
|
|
||||||
|
if ($cmd eq "have") {
|
||||||
|
print STDERR "checking binary caches for existence of @args\n" if $debug;
|
||||||
|
printSubstitutablePaths(@args);
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
elsif ($cmd eq "info") {
|
||||||
|
print STDERR "checking binary caches for info on @args\n" if $debug;
|
||||||
|
printInfoParallel(@args);
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
else { die "unknown command `$cmd'"; }
|
||||||
|
|
||||||
|
flush STDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
elsif ($ARGV[0] eq "--substitute") {
|
||||||
|
my $storePath = $ARGV[1] or die;
|
||||||
|
my $destPath = $ARGV[2] or die;
|
||||||
|
getAvailableCaches;
|
||||||
|
downloadBinary($storePath, $destPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
die;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ use strict;
|
|||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
use Nix::Manifest;
|
use Nix::Manifest;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
|
use Nix::Utils;
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
|
|
||||||
@@ -15,9 +16,14 @@ my $logFile = "$Nix::Config::logDir/downloads";
|
|||||||
# estimating the expected download size.
|
# estimating the expected download size.
|
||||||
my $fast = 1;
|
my $fast = 1;
|
||||||
|
|
||||||
|
# ‘--insecure’ is fine because Nix verifies the hash of the result.
|
||||||
|
my $curl = "$Nix::Config::curl --fail --location --insecure";
|
||||||
|
|
||||||
|
|
||||||
# Open the manifest cache and update it if necessary.
|
# Open the manifest cache and update it if necessary.
|
||||||
my $dbh = updateManifestDB();
|
my $dbh = updateManifestDB();
|
||||||
|
exit 0 unless defined $dbh; # exit if there are no manifests
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
|
||||||
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
|
# $hashCache->{$algo}->{$path} yields the $algo-hash of $path.
|
||||||
@@ -38,7 +44,7 @@ sub parseHash {
|
|||||||
# given path.
|
# given path.
|
||||||
sub computeSmallestDownload {
|
sub computeSmallestDownload {
|
||||||
my $targetPath = shift;
|
my $targetPath = shift;
|
||||||
|
|
||||||
# Build a graph of all store paths that might contribute to the
|
# Build a graph of all store paths that might contribute to the
|
||||||
# construction of $targetPath, and the special node "start". The
|
# construction of $targetPath, and the special node "start". The
|
||||||
# edges are either patch operations, or downloads of full NAR
|
# edges are either patch operations, or downloads of full NAR
|
||||||
@@ -93,7 +99,7 @@ sub computeSmallestDownload {
|
|||||||
my $patchList = $dbh->selectall_arrayref(
|
my $patchList = $dbh->selectall_arrayref(
|
||||||
"select * from Patches where storePath = ?",
|
"select * from Patches where storePath = ?",
|
||||||
{ Slice => {} }, $u);
|
{ Slice => {} }, $u);
|
||||||
|
|
||||||
foreach my $patch (@{$patchList}) {
|
foreach my $patch (@{$patchList}) {
|
||||||
if (isValidPath($patch->{basePath})) {
|
if (isValidPath($patch->{basePath})) {
|
||||||
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
|
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
|
||||||
@@ -106,7 +112,7 @@ sub computeSmallestDownload {
|
|||||||
$hash =~ s/.*://;
|
$hash =~ s/.*://;
|
||||||
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
|
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
next if $hash ne $baseHash;
|
next if $hash ne $baseHash;
|
||||||
}
|
}
|
||||||
push @queue, $patch->{basePath};
|
push @queue, $patch->{basePath};
|
||||||
@@ -117,7 +123,7 @@ sub computeSmallestDownload {
|
|||||||
my $narFileList = $dbh->selectall_arrayref(
|
my $narFileList = $dbh->selectall_arrayref(
|
||||||
"select * from NARs where storePath = ?",
|
"select * from NARs where storePath = ?",
|
||||||
{ Slice => {} }, $u);
|
{ Slice => {} }, $u);
|
||||||
|
|
||||||
foreach my $narFile (@{$narFileList}) {
|
foreach my $narFile (@{$narFileList}) {
|
||||||
# !!! how to handle files whose size is not known in advance?
|
# !!! how to handle files whose size is not known in advance?
|
||||||
# For now, assume some arbitrary size (1 GB).
|
# For now, assume some arbitrary size (1 GB).
|
||||||
@@ -173,58 +179,56 @@ sub computeSmallestDownload {
|
|||||||
if ($ARGV[0] eq "--query") {
|
if ($ARGV[0] eq "--query") {
|
||||||
|
|
||||||
while (<STDIN>) {
|
while (<STDIN>) {
|
||||||
my $cmd = $_; chomp $cmd;
|
chomp;
|
||||||
|
my ($cmd, @args) = split " ", $_;
|
||||||
|
|
||||||
if ($cmd eq "have") {
|
if ($cmd eq "have") {
|
||||||
my $storePath = <STDIN>; chomp $storePath;
|
foreach my $storePath (@args) {
|
||||||
print STDOUT (
|
print "$storePath\n" if scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0;
|
||||||
scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0
|
}
|
||||||
? "1\n" : "0\n");
|
print "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($cmd eq "info") {
|
elsif ($cmd eq "info") {
|
||||||
my $storePath = <STDIN>; chomp $storePath;
|
foreach my $storePath (@args) {
|
||||||
|
|
||||||
my $infos = $dbh->selectall_arrayref(
|
my $infos = $dbh->selectall_arrayref(
|
||||||
"select * from NARs where storePath = ?",
|
"select * from NARs where storePath = ?",
|
||||||
{ Slice => {} }, $storePath);
|
{ Slice => {} }, $storePath);
|
||||||
|
|
||||||
my $info;
|
|
||||||
if (scalar @{$infos} > 0) {
|
|
||||||
$info = @{$infos}[0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print "0\n";
|
|
||||||
next; # not an error
|
|
||||||
}
|
|
||||||
|
|
||||||
print "1\n";
|
next unless scalar @{$infos} > 0;
|
||||||
print "$info->{deriver}\n";
|
my $info = @{$infos}[0];
|
||||||
my @references = split " ", $info->{refs};
|
|
||||||
print scalar @references, "\n";
|
|
||||||
print "$_\n" foreach @references;
|
|
||||||
|
|
||||||
my @path = computeSmallestDownload $storePath;
|
print "$storePath\n";
|
||||||
|
print "$info->{deriver}\n";
|
||||||
|
my @references = split " ", $info->{refs};
|
||||||
|
print scalar @references, "\n";
|
||||||
|
print "$_\n" foreach @references;
|
||||||
|
|
||||||
my $downloadSize = 0;
|
my @path = computeSmallestDownload $storePath;
|
||||||
while (scalar @path > 0) {
|
|
||||||
my $edge = pop @path;
|
my $downloadSize = 0;
|
||||||
my $u = $edge->{start};
|
while (scalar @path > 0) {
|
||||||
my $v = $edge->{end};
|
my $edge = pop @path;
|
||||||
if ($edge->{type} eq "patch") {
|
my $u = $edge->{start};
|
||||||
$downloadSize += $edge->{info}->{size} || 0;
|
my $v = $edge->{end};
|
||||||
}
|
if ($edge->{type} eq "patch") {
|
||||||
elsif ($edge->{type} eq "narfile") {
|
$downloadSize += $edge->{info}->{size} || 0;
|
||||||
$downloadSize += $edge->{info}->{size} || 0;
|
}
|
||||||
|
elsif ($edge->{type} eq "narfile") {
|
||||||
|
$downloadSize += $edge->{info}->{size} || 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print "$downloadSize\n";
|
||||||
|
|
||||||
|
my $narSize = $info->{narSize} || 0;
|
||||||
|
print "$narSize\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
print "$downloadSize\n";
|
print "\n";
|
||||||
|
|
||||||
my $narSize = $info->{narSize} || 0;
|
|
||||||
print "$narSize\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else { die "unknown command `$cmd'"; }
|
else { die "unknown command `$cmd'"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +240,9 @@ elsif ($ARGV[0] ne "--substitute") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
die unless scalar @ARGV == 2;
|
die unless scalar @ARGV == 3;
|
||||||
my $targetPath = $ARGV[1];
|
my $targetPath = $ARGV[1];
|
||||||
|
my $destPath = $ARGV[2];
|
||||||
$fast = 0;
|
$fast = 0;
|
||||||
|
|
||||||
|
|
||||||
@@ -273,16 +278,6 @@ $dbh->disconnect;
|
|||||||
my $curStep = 1;
|
my $curStep = 1;
|
||||||
my $maxStep = scalar @path;
|
my $maxStep = scalar @path;
|
||||||
|
|
||||||
sub downloadFile {
|
|
||||||
my $url = shift;
|
|
||||||
$ENV{"PRINT_PATH"} = 1;
|
|
||||||
$ENV{"QUIET"} = 1;
|
|
||||||
my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`;
|
|
||||||
die "download of `$url' failed" . ($! ? ": $!" : "") . "\n" unless $? == 0;
|
|
||||||
chomp $path;
|
|
||||||
return $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $finalNarHash;
|
my $finalNarHash;
|
||||||
|
|
||||||
while (scalar @path > 0) {
|
while (scalar @path > 0) {
|
||||||
@@ -314,13 +309,16 @@ while (scalar @path > 0) {
|
|||||||
|
|
||||||
# Download the patch.
|
# Download the patch.
|
||||||
print STDERR " downloading patch...\n";
|
print STDERR " downloading patch...\n";
|
||||||
my $patchPath = downloadFile "$patch->{url}";
|
my $patchPath = "$tmpDir/patch";
|
||||||
|
checkURL $patch->{url};
|
||||||
|
system("$curl '$patch->{url}' -o $patchPath") == 0
|
||||||
|
or die "cannot download patch `$patch->{url}'\n";
|
||||||
|
|
||||||
# Apply the patch to the NAR archive produced in step 1 (for
|
# Apply the patch to the NAR archive produced in step 1 (for
|
||||||
# the already present path) or a later step (for patch sequences).
|
# the already present path) or a later step (for patch sequences).
|
||||||
print STDERR " applying patch...\n";
|
print STDERR " applying patch...\n";
|
||||||
system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0
|
system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0
|
||||||
or die "cannot apply patch `$patchPath' to $tmpNar";
|
or die "cannot apply patch `$patchPath' to $tmpNar\n";
|
||||||
|
|
||||||
if ($curStep < $maxStep) {
|
if ($curStep < $maxStep) {
|
||||||
# The archive will be used as the base of the next patch.
|
# The archive will be used as the base of the next patch.
|
||||||
@@ -329,8 +327,8 @@ while (scalar @path > 0) {
|
|||||||
# This was the last patch. Unpack the final NAR archive
|
# This was the last patch. Unpack the final NAR archive
|
||||||
# into the target path.
|
# into the target path.
|
||||||
print STDERR " unpacking patched archive...\n";
|
print STDERR " unpacking patched archive...\n";
|
||||||
system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0
|
system("$Nix::Config::binDir/nix-store --restore $destPath < $tmpNar2") == 0
|
||||||
or die "cannot unpack $tmpNar2 into `$v'";
|
or die "cannot unpack $tmpNar2 to `$v'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$finalNarHash = $patch->{narHash};
|
$finalNarHash = $patch->{narHash};
|
||||||
@@ -338,24 +336,27 @@ while (scalar @path > 0) {
|
|||||||
|
|
||||||
elsif ($edge->{type} eq "narfile") {
|
elsif ($edge->{type} eq "narfile") {
|
||||||
my $narFile = $edge->{info};
|
my $narFile = $edge->{info};
|
||||||
print STDERR "downloading `$narFile->{url}' into `$v'\n";
|
print STDERR "downloading `$narFile->{url}' to `$v'\n";
|
||||||
|
|
||||||
my $size = $narFile->{size} || -1;
|
my $size = $narFile->{size} || -1;
|
||||||
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
|
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
|
||||||
|
|
||||||
# Download the archive.
|
checkURL $narFile->{url};
|
||||||
print STDERR " downloading archive...\n";
|
|
||||||
my $narFilePath = downloadFile "$narFile->{url}";
|
my $decompressor =
|
||||||
|
$narFile->{compressionType} eq "bzip2" ? "| $Nix::Config::bzip2 -d" :
|
||||||
|
$narFile->{compressionType} eq "xz" ? "| $Nix::Config::xz -d" :
|
||||||
|
$narFile->{compressionType} eq "none" ? "" :
|
||||||
|
die "unknown compression type `$narFile->{compressionType}'";
|
||||||
|
|
||||||
if ($curStep < $maxStep) {
|
if ($curStep < $maxStep) {
|
||||||
# The archive will be used a base to a patch.
|
# The archive will be used a base to a patch.
|
||||||
system("$Nix::Config::bzip2 -d < '$narFilePath' > $tmpNar") == 0
|
system("$curl '$narFile->{url}' $decompressor > $tmpNar") == 0
|
||||||
or die "cannot unpack `$narFilePath' into `$v'";
|
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
|
||||||
} else {
|
} else {
|
||||||
# Unpack the archive into the target path.
|
# Unpack the archive to the target path.
|
||||||
print STDERR " unpacking archive...\n";
|
system("$curl '$narFile->{url}' $decompressor | $Nix::Config::binDir/nix-store --restore '$destPath'") == 0
|
||||||
system("$Nix::Config::bzip2 -d < '$narFilePath' | $Nix::Config::binDir/nix-store --restore '$v'") == 0
|
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
|
||||||
or die "cannot unpack `$narFilePath' into `$v'";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$finalNarHash = $narFile->{narHash};
|
$finalNarHash = $narFile->{narHash};
|
||||||
@@ -365,21 +366,10 @@ while (scalar @path > 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Make sure that the hash declared in the manifest matches what we
|
# Tell Nix about the expected hash so it can verify it.
|
||||||
# downloaded and unpacked.
|
die "cannot check integrity of the downloaded path since its hash is not known\n"
|
||||||
|
unless defined $finalNarHash;
|
||||||
if (defined $finalNarHash) {
|
print "$finalNarHash\n";
|
||||||
my ($hashAlgo, $hash) = parseHash $finalNarHash;
|
|
||||||
|
|
||||||
# The hash in the manifest can be either in base-16 or base-32.
|
|
||||||
# Handle both.
|
|
||||||
my $hash2 = hashPath($hashAlgo, $hashAlgo eq "sha256" && length($hash) != 64, $targetPath);
|
|
||||||
|
|
||||||
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2\n"
|
|
||||||
if $hash ne $hash2;
|
|
||||||
} else {
|
|
||||||
die "cannot check integrity of the downloaded path since its hash is not known\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
print STDERR "\n";
|
print STDERR "\n";
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#! @perl@ -w
|
#! @perl@ -w @perlFlags@
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use Nix::Utils;
|
||||||
my $procDir = "/proc";
|
use Nix::Config;
|
||||||
|
|
||||||
|
|
||||||
sub readProc {
|
sub readProc {
|
||||||
return unless -d $procDir;
|
return unless -d "/proc";
|
||||||
|
|
||||||
|
opendir DIR, "/proc" or return;
|
||||||
|
|
||||||
opendir DIR, $procDir or return;
|
|
||||||
|
|
||||||
foreach my $name (readdir DIR) {
|
foreach my $name (readdir DIR) {
|
||||||
next unless $name =~ /^\d+$/;
|
next unless $name =~ /^\d+$/;
|
||||||
|
|
||||||
my $process = "$procDir/$name";
|
my $process = "/proc/$name";
|
||||||
|
|
||||||
#print STDERR "=== $process\n";
|
#print STDERR "=== $process\n";
|
||||||
|
|
||||||
my $target;
|
my $target;
|
||||||
print "$target\n" if $target = readlink "$process/exe";
|
print "$target\n" if $target = readlink "$process/exe";
|
||||||
print "$target\n" if $target = readlink "$process/cwd";
|
print "$target\n" if $target = readlink "$process/cwd";
|
||||||
@@ -36,6 +36,13 @@ sub readProc {
|
|||||||
}
|
}
|
||||||
close MAP;
|
close MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Get all store paths that appear in the environment of this process.
|
||||||
|
eval {
|
||||||
|
my $env = Nix::Utils::readFile "$process/environ";
|
||||||
|
my @matches = $env =~ /\Q$Nix::Config::storeDir\E\/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*/g;
|
||||||
|
print "$_\n" foreach @matches;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir DIR;
|
closedir DIR;
|
||||||
@@ -58,18 +65,15 @@ readProc;
|
|||||||
lsof;
|
lsof;
|
||||||
|
|
||||||
|
|
||||||
sub readFile {
|
sub printFile {
|
||||||
my $path = shift;
|
my ($fn) = @_;
|
||||||
if (-e $path) {
|
if (-e $fn) {
|
||||||
if (open FILE, "$path") {
|
print Nix::Utils::readFile($fn), "\n";
|
||||||
while (<FILE>) {
|
|
||||||
print;
|
|
||||||
}
|
|
||||||
close FILE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# This is rather NixOS-specific, so it probably shouldn't be here.
|
# This is rather NixOS-specific, so it probably shouldn't be here.
|
||||||
readFile "/proc/sys/kernel/modprobe";
|
printFile "/proc/sys/kernel/modprobe";
|
||||||
readFile "/proc/sys/kernel/fbsplash";
|
printFile "/proc/sys/kernel/fbsplash";
|
||||||
|
printFile "/proc/sys/kernel/poweroff_cmd";
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#! /bin/sh -e
|
||||||
|
|
||||||
|
nix=@nix@
|
||||||
|
regInfo=@regInfo@
|
||||||
|
|
||||||
|
if ! $nix/bin/nix-store --load-db < $regInfo; then
|
||||||
|
echo "$0: unable to register valid paths"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
. @nix@/etc/profile.d/nix.sh
|
||||||
|
|
||||||
|
if ! $nix/bin/nix-env -i @nix@; then
|
||||||
|
echo "$0: unable to install Nix into your default profile"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add nix.sh to the shell's profile.d directory.
|
||||||
|
p=$NIX_LINK/etc/profile.d/nix.sh
|
||||||
|
|
||||||
|
if [ -w /etc/profile.d ]; then
|
||||||
|
ln -s $p /etc/profile.d/
|
||||||
|
elif [ -w /usr/local/etc/profile.d ]; then
|
||||||
|
ln -s $p /usr/local/etc/profile.d/
|
||||||
|
else
|
||||||
|
cat <<EOF
|
||||||
|
Installation finished. To ensure that the necessary environment
|
||||||
|
variables are set, please add the line
|
||||||
|
|
||||||
|
source $p
|
||||||
|
|
||||||
|
to your shell profile (e.g. ~/.profile).
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
+89
-50
@@ -3,23 +3,27 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
|
use Nix::Utils;
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
|
|
||||||
|
|
||||||
my $dryRun = 0;
|
my $dryRun = 0;
|
||||||
my $verbose = 0;
|
my $verbose = 0;
|
||||||
my $runEnv = 0;
|
my $runEnv = $0 =~ /nix-shell$/;
|
||||||
|
my $pure = 0;
|
||||||
|
|
||||||
my @instArgs = ();
|
my @instArgs = ();
|
||||||
my @buildArgs = ();
|
my @buildArgs = ();
|
||||||
my @exprs = ();
|
my @exprs = ();
|
||||||
|
|
||||||
my $shell = $ENV{SHELL} || "/bin/sh";
|
my $shell = $ENV{SHELL} || "/bin/sh";
|
||||||
my $envCommand = "p=\$PATH; source \$stdenv/setup; PATH=\$PATH:\$p; exec $shell";
|
my $envCommand = ""; # interactive shell
|
||||||
my @envExclude = ();
|
my @envExclude = ();
|
||||||
|
|
||||||
|
my $myName = $runEnv ? "nix-shell" : "nix-build";
|
||||||
|
|
||||||
my $tmpDir = tempdir("nix-build.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
|
||||||
|
my $tmpDir = tempdir("$myName.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||||
or die "cannot create a temporary directory";
|
or die "cannot create a temporary directory";
|
||||||
|
|
||||||
my $outLink = "./result";
|
my $outLink = "./result";
|
||||||
@@ -33,29 +37,12 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
|
|||||||
my $arg = $ARGV[$n];
|
my $arg = $ARGV[$n];
|
||||||
|
|
||||||
if ($arg eq "--help") {
|
if ($arg eq "--help") {
|
||||||
print STDERR <<EOF;
|
exec "man $myName" or die;
|
||||||
Usage: nix-build [OPTION]... [FILE]...
|
}
|
||||||
|
|
||||||
`nix-build' builds the given Nix expressions (which
|
elsif ($arg eq "--version") {
|
||||||
default to ./default.nix if none are given). A symlink called
|
print "$myName (Nix) $Nix::Config::version\n";
|
||||||
`result' is placed in the current directory.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--add-drv-link: create a symlink `derivation' to the store derivation
|
|
||||||
--drv-link NAME: create symlink NAME instead of `derivation'
|
|
||||||
--no-out-link: do not create the `result' symlink
|
|
||||||
--out-link / -o NAME: create symlink NAME instead of `result'
|
|
||||||
--attr / -A ATTR: select a specific attribute from the Nix expression
|
|
||||||
|
|
||||||
--run-env: build dependencies of the specified derivation, then start a
|
|
||||||
shell with the environment of the derivation
|
|
||||||
--command: command to run with `--run-env'
|
|
||||||
--exclude: regexp specifying dependencies to be excluded by `--run-env'
|
|
||||||
|
|
||||||
Any additional flags are passed to `nix-store'.
|
|
||||||
EOF
|
|
||||||
exit 0;
|
exit 0;
|
||||||
# '` hack
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--add-drv-link") {
|
elsif ($arg eq "--add-drv-link") {
|
||||||
@@ -104,7 +91,7 @@ EOF
|
|||||||
$n += 2;
|
$n += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores") {
|
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type" or $arg eq "--cores" or $arg eq "--timeout") {
|
||||||
$n++;
|
$n++;
|
||||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||||
push @buildArgs, ($arg, $ARGV[$n]);
|
push @buildArgs, ($arg, $ARGV[$n]);
|
||||||
@@ -114,30 +101,34 @@ EOF
|
|||||||
push @buildArgs, "--dry-run";
|
push @buildArgs, "--dry-run";
|
||||||
$dryRun = 1;
|
$dryRun = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--show-trace") {
|
elsif ($arg eq "--show-trace") {
|
||||||
push @instArgs, $arg;
|
push @instArgs, $arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elsif ($arg eq "-") {
|
||||||
|
@exprs = ("-");
|
||||||
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
|
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
|
||||||
push @buildArgs, $arg;
|
push @buildArgs, $arg;
|
||||||
push @instArgs, $arg;
|
push @instArgs, $arg;
|
||||||
$verbose = 1;
|
$verbose = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--quiet") {
|
elsif ($arg eq "--quiet" || $arg eq "--repair") {
|
||||||
push @buildArgs, $arg;
|
push @buildArgs, $arg;
|
||||||
push @instArgs, $arg;
|
push @instArgs, $arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--run-env") {
|
elsif ($arg eq "--run-env") { # obsolete
|
||||||
$runEnv = 1;
|
$runEnv = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--command") {
|
elsif ($arg eq "--command") {
|
||||||
$n++;
|
$n++;
|
||||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||||
$envCommand = $ARGV[$n];
|
$envCommand = "$ARGV[$n]\nexit $!";
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--exclude") {
|
elsif ($arg eq "--exclude") {
|
||||||
@@ -146,6 +137,10 @@ EOF
|
|||||||
push @envExclude, $ARGV[$n];
|
push @envExclude, $ARGV[$n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elsif ($arg eq "--pure") {
|
||||||
|
$pure = 1;
|
||||||
|
}
|
||||||
|
|
||||||
elsif (substr($arg, 0, 1) eq "-") {
|
elsif (substr($arg, 0, 1) eq "-") {
|
||||||
push @buildArgs, $arg;
|
push @buildArgs, $arg;
|
||||||
}
|
}
|
||||||
@@ -162,17 +157,22 @@ foreach my $expr (@exprs) {
|
|||||||
|
|
||||||
# Instantiate.
|
# Instantiate.
|
||||||
my @drvPaths;
|
my @drvPaths;
|
||||||
# !!! would prefer the perl 5.8.0 pipe open feature here.
|
if ($expr !~ /^\/.*\.drv$/) {
|
||||||
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
# !!! would prefer the perl 5.8.0 pipe open feature here.
|
||||||
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
|
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
||||||
if (!close DRVPATHS) {
|
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
|
||||||
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
if (!close DRVPATHS) {
|
||||||
exit 1;
|
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push @drvPaths, $expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($runEnv) {
|
if ($runEnv) {
|
||||||
die "$0: ‘--run-env’ requires a single derivation\n" if scalar @drvPaths != 1;
|
die "$0: a single derivation is required\n" if scalar @drvPaths != 1;
|
||||||
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
|
my $drvPath = $drvPaths[0];
|
||||||
|
$drvPath = readlink $drvPath or die "cannot read symlink `$drvPath'" if -l $drvPath;
|
||||||
my $drv = derivationFromPath($drvPath);
|
my $drv = derivationFromPath($drvPath);
|
||||||
|
|
||||||
# Build or fetch all dependencies of the derivation.
|
# Build or fetch all dependencies of the derivation.
|
||||||
@@ -181,28 +181,67 @@ foreach my $expr (@exprs) {
|
|||||||
or die "$0: failed to build all dependencies\n";
|
or die "$0: failed to build all dependencies\n";
|
||||||
|
|
||||||
# Set the environment.
|
# Set the environment.
|
||||||
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
|
if ($pure) {
|
||||||
foreach (keys %{$drv->{env}}) {
|
foreach my $name (keys %ENV) {
|
||||||
$ENV{$_} = $drv->{env}->{$_};
|
next if $name eq "HOME" || $name eq "USER" || $name eq "LOGNAME" || $name eq "DISPLAY" || $name eq "PATH";
|
||||||
|
delete $ENV{$name};
|
||||||
|
}
|
||||||
|
# NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
|
||||||
|
$ENV{'__ETC_PROFILE_SOURCED'} = 1;
|
||||||
}
|
}
|
||||||
|
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} = $ENV{'TEMPDIR'} = $ENV{'TMP'} = $ENV{'TEMP'} = $ENV{'TMPDIR'} // "/tmp";
|
||||||
|
$ENV{'NIX_STORE'} = $Nix::Config::storeDir;
|
||||||
|
$ENV{$_} = $drv->{env}->{$_} foreach keys %{$drv->{env}};
|
||||||
|
|
||||||
|
$ENV{'IN_NIX_SHELL'} = 1;
|
||||||
|
|
||||||
# Run a shell using the derivation's environment. For
|
# Run a shell using the derivation's environment. For
|
||||||
# convenience, source $stdenv/setup to setup additional
|
# convenience, source $stdenv/setup to setup additional
|
||||||
# environment variables. Also don't lose the current $PATH
|
# environment variables and shell functions. Also don't lose
|
||||||
# directories.
|
# the current $PATH directories.
|
||||||
exec($ENV{SHELL}, "-c", $envCommand);
|
my $rcfile = "$tmpDir/rc";
|
||||||
|
writeFile(
|
||||||
|
$rcfile,
|
||||||
|
'[ -e ~/.bashrc ] && source ~/.bashrc; ' .
|
||||||
|
($pure ? '' : 'p=$PATH; ' ) .
|
||||||
|
'dontAddDisableDepTrack=1; ' .
|
||||||
|
'[ -e $stdenv/setup ] && source $stdenv/setup; ' .
|
||||||
|
($pure ? '' : 'PATH=$PATH:$p; ') .
|
||||||
|
'set +e; ' .
|
||||||
|
'PS1="\n\[\033[1;32m\][nix-shell:\w]$\[\033[0m\] "; ' .
|
||||||
|
'unset NIX_ENFORCE_PURITY; ' .
|
||||||
|
$envCommand);
|
||||||
|
exec($ENV{NIX_BUILD_SHELL} // "bash", "--rcfile", $rcfile);
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ugly hackery to make "nix-build -A foo.all" produce symlinks
|
||||||
|
# ./result, ./result-dev, and so on, rather than ./result,
|
||||||
|
# ./result-2-dev, and so on. This combines multiple derivation
|
||||||
|
# paths into one "/nix/store/drv-path!out1,out2,..." argument.
|
||||||
|
my $prevDrvPath = "";
|
||||||
|
my @drvPaths2;
|
||||||
foreach my $drvPath (@drvPaths) {
|
foreach my $drvPath (@drvPaths) {
|
||||||
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
|
my $p = $drvPath; my $output = "out";
|
||||||
|
if ($drvPath =~ /(.*)!(.*)/) {
|
||||||
|
$p = $1; $output = $2;
|
||||||
|
} else {
|
||||||
|
$p = $drvPath;
|
||||||
|
}
|
||||||
|
my $target = readlink $p or die "cannot read symlink `$p'";
|
||||||
print STDERR "derivation is $target\n" if $verbose;
|
print STDERR "derivation is $target\n" if $verbose;
|
||||||
|
if ($target eq $prevDrvPath) {
|
||||||
|
push @drvPaths2, (pop @drvPaths2) . "," . $output;
|
||||||
|
} else {
|
||||||
|
push @drvPaths2, $target . "!" . $output;
|
||||||
|
$prevDrvPath = $target;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build.
|
# Build.
|
||||||
my @outPaths;
|
my @outPaths;
|
||||||
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
|
my $pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
|
||||||
@buildArgs, @drvPaths;
|
@buildArgs, @drvPaths2;
|
||||||
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
|
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
|
||||||
if (!close OUTPATHS) {
|
if (!close OUTPATHS) {
|
||||||
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||||
|
|||||||
+46
-37
@@ -4,6 +4,9 @@ use strict;
|
|||||||
use File::Basename;
|
use File::Basename;
|
||||||
use File::Path qw(mkpath);
|
use File::Path qw(mkpath);
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
|
use Nix::Manifest;
|
||||||
|
|
||||||
|
Nix::Config::readConfig;
|
||||||
|
|
||||||
my $manifestDir = $Nix::Config::manifestDir;
|
my $manifestDir = $Nix::Config::manifestDir;
|
||||||
|
|
||||||
@@ -22,7 +25,7 @@ my $nixDefExpr = "$home/.nix-defexpr";
|
|||||||
my $userName = getpwuid($<) or die "cannot figure out user name";
|
my $userName = getpwuid($<) or die "cannot figure out user name";
|
||||||
my $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
|
my $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
|
||||||
mkpath(dirname $profile, 0, 0755);
|
mkpath(dirname $profile, 0, 0755);
|
||||||
|
|
||||||
my %channels;
|
my %channels;
|
||||||
|
|
||||||
|
|
||||||
@@ -65,11 +68,13 @@ sub addChannel {
|
|||||||
sub removeChannel {
|
sub removeChannel {
|
||||||
my ($name) = @_;
|
my ($name) = @_;
|
||||||
readChannels;
|
readChannels;
|
||||||
|
my $url = $channels{$name};
|
||||||
|
deleteOldManifests($url . "/MANIFEST", undef) if defined $url;
|
||||||
delete $channels{$name};
|
delete $channels{$name};
|
||||||
writeChannels;
|
writeChannels;
|
||||||
|
|
||||||
system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
|
system("$Nix::Config::binDir/nix-env --profile '$profile' -e '$name'") == 0
|
||||||
or die "cannot remove channel `$name'";
|
or die "cannot remove channel `$name'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,20 +82,14 @@ sub removeChannel {
|
|||||||
# channels.
|
# channels.
|
||||||
sub update {
|
sub update {
|
||||||
my @channelNames = @_;
|
my @channelNames = @_;
|
||||||
|
|
||||||
readChannels;
|
readChannels;
|
||||||
|
|
||||||
# Create the manifests directory if it doesn't exist.
|
|
||||||
mkdir $manifestDir, 0755 unless -e $manifestDir;
|
|
||||||
|
|
||||||
# Do we have write permission to the manifests directory?
|
|
||||||
die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
|
|
||||||
|
|
||||||
# Download each channel.
|
# Download each channel.
|
||||||
my $exprs = "";
|
my $exprs = "";
|
||||||
foreach my $name (keys %channels) {
|
foreach my $name (keys %channels) {
|
||||||
next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
|
next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
|
||||||
|
|
||||||
my $url = $channels{$name};
|
my $url = $channels{$name};
|
||||||
my $origUrl = "$url/MANIFEST";
|
my $origUrl = "$url/MANIFEST";
|
||||||
|
|
||||||
@@ -101,17 +100,34 @@ sub update {
|
|||||||
die "$0: unable to check `$url'\n" if $? != 0;
|
die "$0: unable to check `$url'\n" if $? != 0;
|
||||||
$headers =~ s/\r//g;
|
$headers =~ s/\r//g;
|
||||||
$url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
|
$url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
|
||||||
|
|
||||||
# Pull the channel manifest.
|
# Check if the channel advertises a binary cache.
|
||||||
$ENV{'NIX_ORIG_URL'} = $origUrl;
|
my $binaryCacheURL = `$Nix::Config::curl --silent '$url'/binary-cache-url`;
|
||||||
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
|
my $extraAttrs = "";
|
||||||
or die "cannot pull manifest from `$url'\n";
|
my $getManifest = ($Nix::Config::config{"force-manifest"} // "false") eq "true";
|
||||||
|
if ($? == 0 && $binaryCacheURL ne "") {
|
||||||
|
$extraAttrs .= "binaryCacheURL = \"$binaryCacheURL\"; ";
|
||||||
|
deleteOldManifests($origUrl, undef);
|
||||||
|
} else {
|
||||||
|
$getManifest = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($getManifest) {
|
||||||
|
# No binary cache, so pull the channel manifest.
|
||||||
|
mkdir $manifestDir, 0755 unless -e $manifestDir;
|
||||||
|
die "$0: you do not have write permission to `$manifestDir'!\n" unless -W $manifestDir;
|
||||||
|
$ENV{'NIX_ORIG_URL'} = $origUrl;
|
||||||
|
system("$Nix::Config::binDir/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
|
||||||
|
or die "cannot pull manifest from `$url'\n";
|
||||||
|
}
|
||||||
|
|
||||||
# Download the channel tarball.
|
# Download the channel tarball.
|
||||||
my $fullURL = "$url/nixexprs.tar.bz2";
|
my $fullURL = "$url/nixexprs.tar.xz";
|
||||||
|
system("$Nix::Config::curl --fail --silent --head '$fullURL' > /dev/null") == 0 or
|
||||||
|
$fullURL = "$url/nixexprs.tar.bz2";
|
||||||
print STDERR "downloading Nix expressions from `$fullURL'...\n";
|
print STDERR "downloading Nix expressions from `$fullURL'...\n";
|
||||||
my ($hash, $path) = `PRINT_PATH=1 QUIET=1 $Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
|
my ($hash, $path) = `PRINT_PATH=1 QUIET=1 $Nix::Config::binDir/nix-prefetch-url '$fullURL'`;
|
||||||
die "cannot fetch `$fullURL'" if $? != 0;
|
die "cannot fetch `$fullURL'\n" if $? != 0;
|
||||||
chomp $path;
|
chomp $path;
|
||||||
|
|
||||||
# If the URL contains a version number, append it to the name
|
# If the URL contains a version number, append it to the name
|
||||||
@@ -120,7 +136,7 @@ sub update {
|
|||||||
my $cname = $name;
|
my $cname = $name;
|
||||||
$cname .= $1 if basename($url) =~ /(-\d.*)$/;
|
$cname .= $1 if basename($url) =~ /(-\d.*)$/;
|
||||||
|
|
||||||
$exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; }' ";
|
$exprs .= "'f: f { name = \"$cname\"; channelName = \"$name\"; src = builtins.storePath \"$path\"; $extraAttrs }' ";
|
||||||
}
|
}
|
||||||
|
|
||||||
# Unpack the channel tarballs into the Nix store and install them
|
# Unpack the channel tarballs into the Nix store and install them
|
||||||
@@ -139,26 +155,14 @@ sub update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub usageError {
|
die "$0: argument expected\n" if scalar @ARGV == 0;
|
||||||
print STDERR <<EOF;
|
|
||||||
Usage:
|
|
||||||
nix-channel --add URL [CHANNEL-NAME]
|
|
||||||
nix-channel --remove CHANNEL-NAME
|
|
||||||
nix-channel --list
|
|
||||||
nix-channel --update [CHANNEL-NAME...]
|
|
||||||
EOF
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
usageError if scalar @ARGV == 0;
|
|
||||||
|
|
||||||
|
|
||||||
while (scalar @ARGV) {
|
while (scalar @ARGV) {
|
||||||
my $arg = shift @ARGV;
|
my $arg = shift @ARGV;
|
||||||
|
|
||||||
if ($arg eq "--add") {
|
if ($arg eq "--add") {
|
||||||
usageError if scalar @ARGV < 1 || scalar @ARGV > 2;
|
die "$0: `--add' requires one or two arguments\n" if scalar @ARGV < 1 || scalar @ARGV > 2;
|
||||||
my $url = shift @ARGV;
|
my $url = shift @ARGV;
|
||||||
my $name = shift @ARGV;
|
my $name = shift @ARGV;
|
||||||
unless (defined $name) {
|
unless (defined $name) {
|
||||||
@@ -171,13 +175,13 @@ while (scalar @ARGV) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($arg eq "--remove") {
|
if ($arg eq "--remove") {
|
||||||
usageError if scalar @ARGV != 1;
|
die "$0: `--remove' requires one argument\n" if scalar @ARGV != 1;
|
||||||
removeChannel(shift @ARGV);
|
removeChannel(shift @ARGV);
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($arg eq "--list") {
|
if ($arg eq "--list") {
|
||||||
usageError if scalar @ARGV != 0;
|
die "$0: `--list' requires one argument\n" if scalar @ARGV != 0;
|
||||||
readChannels;
|
readChannels;
|
||||||
foreach my $name (keys %channels) {
|
foreach my $name (keys %channels) {
|
||||||
print "$name $channels{$name}\n";
|
print "$name $channels{$name}\n";
|
||||||
@@ -189,12 +193,17 @@ while (scalar @ARGV) {
|
|||||||
update(@ARGV);
|
update(@ARGV);
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif ($arg eq "--help") {
|
elsif ($arg eq "--help") {
|
||||||
usageError;
|
exec "man nix-channel" or die;
|
||||||
|
}
|
||||||
|
|
||||||
|
elsif ($arg eq "--version") {
|
||||||
|
print "nix-channel (Nix) $Nix::Config::version\n";
|
||||||
|
exit 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
die "unknown argument `$arg'; try `--help'";
|
die "unknown argument `$arg'; try `--help'\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,15 @@ my $profilesDir = "@localstatedir@/nix/profiles";
|
|||||||
# Process the command line arguments.
|
# Process the command line arguments.
|
||||||
my @args = ();
|
my @args = ();
|
||||||
my $removeOld = 0;
|
my $removeOld = 0;
|
||||||
|
my $dryRun = 0;
|
||||||
|
|
||||||
for my $arg (@ARGV) {
|
for my $arg (@ARGV) {
|
||||||
if ($arg eq "--delete-old" || $arg eq "-d") {
|
if ($arg eq "--delete-old" || $arg eq "-d") {
|
||||||
$removeOld = 1;
|
$removeOld = 1;
|
||||||
|
} elsif ($arg eq "--dry-run") {
|
||||||
|
$dryRun = 1;
|
||||||
|
} elsif ($arg eq "--help") {
|
||||||
|
exec "man nix-collect-garbage" or die;
|
||||||
} else {
|
} else {
|
||||||
push @args, $arg;
|
push @args, $arg;
|
||||||
}
|
}
|
||||||
@@ -35,13 +40,13 @@ sub removeOldGenerations {
|
|||||||
$name = $dir . "/" . $name;
|
$name = $dir . "/" . $name;
|
||||||
if (-l $name && (readlink($name) =~ /link/)) {
|
if (-l $name && (readlink($name) =~ /link/)) {
|
||||||
print STDERR "removing old generations of profile $name\n";
|
print STDERR "removing old generations of profile $name\n";
|
||||||
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old");
|
system("$Nix::Config::binDir/nix-env", "-p", $name, "--delete-generations", "old", $dryRun ? "--dry-run" : ());
|
||||||
}
|
}
|
||||||
elsif (! -l $name && -d $name) {
|
elsif (! -l $name && -d $name) {
|
||||||
removeOldGenerations $name;
|
removeOldGenerations $name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir $dh or die;
|
closedir $dh or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,4 +54,4 @@ removeOldGenerations $profilesDir if $removeOld;
|
|||||||
|
|
||||||
|
|
||||||
# Run the actual garbage collector.
|
# Run the actual garbage collector.
|
||||||
exec "$Nix::Config::binDir/nix-store", "--gc", @args;
|
exec "$Nix::Config::binDir/nix-store", "--gc", @args unless $dryRun;
|
||||||
|
|||||||
+28
-14
@@ -4,6 +4,7 @@ use Nix::SSH;
|
|||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
use Nix::CopyClosure;
|
use Nix::CopyClosure;
|
||||||
|
use List::Util qw(sum);
|
||||||
|
|
||||||
|
|
||||||
if (scalar @ARGV < 1) {
|
if (scalar @ARGV < 1) {
|
||||||
@@ -17,19 +18,14 @@ EOF
|
|||||||
|
|
||||||
# Get the target host.
|
# Get the target host.
|
||||||
my $sshHost;
|
my $sshHost;
|
||||||
|
|
||||||
my $sign = 0;
|
my $sign = 0;
|
||||||
|
|
||||||
my $compressor = "";
|
my $compressor = "";
|
||||||
my $decompressor = "";
|
my $decompressor = "";
|
||||||
|
|
||||||
my $progressViewer = "";
|
my $progressViewer = "";
|
||||||
|
|
||||||
my $toMode = 1;
|
my $toMode = 1;
|
||||||
|
|
||||||
my $includeOutputs = 0;
|
my $includeOutputs = 0;
|
||||||
|
|
||||||
my $dryRun = 0;
|
my $dryRun = 0;
|
||||||
|
my $useSubstitutes = 0;
|
||||||
|
|
||||||
|
|
||||||
# !!! Copied from nix-pack-closure, should put this in a module.
|
# !!! Copied from nix-pack-closure, should put this in a module.
|
||||||
@@ -37,8 +33,11 @@ my @storePaths = ();
|
|||||||
|
|
||||||
while (@ARGV) {
|
while (@ARGV) {
|
||||||
my $arg = shift @ARGV;
|
my $arg = shift @ARGV;
|
||||||
|
|
||||||
if ($arg eq "--sign") {
|
if ($arg eq "--help") {
|
||||||
|
exec "man nix-copy-closure" or die;
|
||||||
|
}
|
||||||
|
elsif ($arg eq "--sign") {
|
||||||
$sign = 1;
|
$sign = 1;
|
||||||
}
|
}
|
||||||
elsif ($arg eq "--gzip") {
|
elsif ($arg eq "--gzip") {
|
||||||
@@ -68,6 +67,9 @@ while (@ARGV) {
|
|||||||
elsif ($arg eq "--dry-run") {
|
elsif ($arg eq "--dry-run") {
|
||||||
$dryRun = 1;
|
$dryRun = 1;
|
||||||
}
|
}
|
||||||
|
elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
|
||||||
|
$useSubstitutes = 1;
|
||||||
|
}
|
||||||
elsif (!defined $sshHost) {
|
elsif (!defined $sshHost) {
|
||||||
$sshHost = $arg;
|
$sshHost = $arg;
|
||||||
}
|
}
|
||||||
@@ -76,12 +78,16 @@ while (@ARGV) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
die "$0: you did not specify a host name\n" unless defined $sshHost;
|
||||||
|
|
||||||
|
|
||||||
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
|
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
|
||||||
|
|
||||||
|
|
||||||
if ($toMode) { # Copy TO the remote machine.
|
if ($toMode) { # Copy TO the remote machine.
|
||||||
Nix::CopyClosure::copyTo($sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer);
|
Nix::CopyClosure::copyTo(
|
||||||
|
$sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor,
|
||||||
|
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
else { # Copy FROM the remote machine.
|
else { # Copy FROM the remote machine.
|
||||||
@@ -92,7 +98,7 @@ else { # Copy FROM the remote machine.
|
|||||||
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
|
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
|
||||||
my $pid = open(READ,
|
my $pid = open(READ,
|
||||||
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
|
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
|
||||||
|
|
||||||
while (<READ>) {
|
while (<READ>) {
|
||||||
chomp;
|
chomp;
|
||||||
die "bad: $_" unless /^\//;
|
die "bad: $_" unless /^\//;
|
||||||
@@ -101,15 +107,23 @@ else { # Copy FROM the remote machine.
|
|||||||
|
|
||||||
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
|
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
|
||||||
|
|
||||||
|
my $missingSize = 0;
|
||||||
|
if ($progressViewer ne "") {
|
||||||
|
$missingSize = sum (split ' ', `set -f; ssh @sshOpts $sshHost nix-store -q --size @missing`) or die;
|
||||||
|
}
|
||||||
|
|
||||||
# Export the store paths on the remote machine and import them locally.
|
# Export the store paths on the remote machine and import them locally.
|
||||||
if (scalar @missing > 0) {
|
if (scalar @missing > 0) {
|
||||||
print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n";
|
print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n";
|
||||||
$compressor = "| $compressor" if $compressor ne "";
|
|
||||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
|
||||||
$progressViewer = "$progressViewer |" if $progressViewer ne "";
|
|
||||||
unless ($dryRun) {
|
unless ($dryRun) {
|
||||||
|
if ($useSubstitutes) {
|
||||||
|
system "$Nix::Config::binDir/nix-store -r --ignore-unknown @missing";
|
||||||
|
}
|
||||||
|
$compressor = "| $compressor" if $compressor ne "";
|
||||||
|
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||||
|
$progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
|
||||||
my $extraOpts = $sign ? "--sign" : "";
|
my $extraOpts = $sign ? "--sign" : "";
|
||||||
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $progressViewer $decompressor $Nix::Config::binDir/nix-store --import > /dev/null") == 0
|
system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $progressViewer $Nix::Config::binDir/nix-store --import > /dev/null") == 0
|
||||||
or die "copying store paths from remote machine `$sshHost' failed: $?";
|
or die "copying store paths from remote machine `$sshHost' failed: $?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,11 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
|
use Nix::Utils;
|
||||||
|
|
||||||
sub usageError {
|
|
||||||
print STDERR <<EOF;
|
|
||||||
Usage: nix-install-package (FILE | --url URL)
|
|
||||||
|
|
||||||
Install a Nix Package (.nixpkg) either directly from FILE or by
|
|
||||||
downloading it from URL.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--profile / -p LINK: install into the specified profile
|
|
||||||
--non-interactive: don't run inside a new terminal
|
|
||||||
EOF
|
|
||||||
; # '
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Parse the command line arguments.
|
# Parse the command line arguments.
|
||||||
my @args = @ARGV;
|
my @args = @ARGV;
|
||||||
usageError if scalar @args == 0;
|
|
||||||
|
|
||||||
my $source;
|
my $source;
|
||||||
my $fromURL = 0;
|
my $fromURL = 0;
|
||||||
@@ -33,14 +17,14 @@ my $interactive = 1;
|
|||||||
while (scalar @args) {
|
while (scalar @args) {
|
||||||
my $arg = shift @args;
|
my $arg = shift @args;
|
||||||
if ($arg eq "--help") {
|
if ($arg eq "--help") {
|
||||||
usageError;
|
exec "man nix-install-package" or die;
|
||||||
}
|
}
|
||||||
elsif ($arg eq "--url") {
|
elsif ($arg eq "--url") {
|
||||||
$fromURL = 1;
|
$fromURL = 1;
|
||||||
}
|
}
|
||||||
elsif ($arg eq "--profile" || $arg eq "-p") {
|
elsif ($arg eq "--profile" || $arg eq "-p") {
|
||||||
my $profile = shift @args;
|
my $profile = shift @args;
|
||||||
usageError if !defined $profile;
|
die "$0: `--profile' requires an argument\n" if !defined $profile;
|
||||||
push @extraNixEnvArgs, "-p", $profile;
|
push @extraNixEnvArgs, "-p", $profile;
|
||||||
}
|
}
|
||||||
elsif ($arg eq "--non-interactive") {
|
elsif ($arg eq "--non-interactive") {
|
||||||
@@ -51,7 +35,7 @@ while (scalar @args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
usageError unless defined $source;
|
die "$0: please specify a .nixpkg file or URL\n" unless defined $source;
|
||||||
|
|
||||||
|
|
||||||
# Re-execute in a terminal, if necessary, so that if we're executed
|
# Re-execute in a terminal, if necessary, so that if we're executed
|
||||||
@@ -72,7 +56,7 @@ my $tmpDir = tempdir("nix-install-package.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
|||||||
|
|
||||||
sub barf {
|
sub barf {
|
||||||
my $msg = shift;
|
my $msg = shift;
|
||||||
print "$msg\n";
|
print "\nInstallation failed: $msg\n";
|
||||||
<STDIN> if $interactive;
|
<STDIN> if $interactive;
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
@@ -92,7 +76,6 @@ open PKGFILE, "<$pkgFile" or barf "cannot open `$pkgFile': $!";
|
|||||||
my $contents = <PKGFILE>;
|
my $contents = <PKGFILE>;
|
||||||
close PKGFILE;
|
close PKGFILE;
|
||||||
|
|
||||||
my $urlRE = "(?: [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+ )";
|
|
||||||
my $nameRE = "(?: [A-Za-z0-9\+\-\.\_\?\=]+ )"; # see checkStoreName()
|
my $nameRE = "(?: [A-Za-z0-9\+\-\.\_\?\=]+ )"; # see checkStoreName()
|
||||||
my $systemRE = "(?: [A-Za-z0-9\+\-\_]+ )";
|
my $systemRE = "(?: [A-Za-z0-9\+\-\_]+ )";
|
||||||
my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
|
my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
|
||||||
@@ -101,7 +84,7 @@ my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
|
|||||||
# store path. We'll let nix-env do that.
|
# store path. We'll let nix-env do that.
|
||||||
|
|
||||||
$contents =~
|
$contents =~
|
||||||
/ ^ \s* (\S+) \s+ ($urlRE) \s+ ($nameRE) \s+ ($systemRE) \s+ ($pathRE) \s+ ($pathRE) /x
|
/ ^ \s* (\S+) \s+ ($Nix::Utils::urlRE) \s+ ($nameRE) \s+ ($systemRE) \s+ ($pathRE) \s+ ($pathRE) ( \s+ ($Nix::Utils::urlRE) )? /x
|
||||||
or barf "invalid package contents";
|
or barf "invalid package contents";
|
||||||
my $version = $1;
|
my $version = $1;
|
||||||
my $manifestURL = $2;
|
my $manifestURL = $2;
|
||||||
@@ -109,6 +92,7 @@ my $drvName = $3;
|
|||||||
my $system = $4;
|
my $system = $4;
|
||||||
my $drvPath = $5;
|
my $drvPath = $5;
|
||||||
my $outPath = $6;
|
my $outPath = $6;
|
||||||
|
my $binaryCacheURL = $8;
|
||||||
|
|
||||||
barf "invalid package version `$version'" unless $version eq "NIXPKG1";
|
barf "invalid package version `$version'" unless $version eq "NIXPKG1";
|
||||||
|
|
||||||
@@ -122,17 +106,25 @@ if ($interactive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Store the manifest in the temporary directory so that we don't
|
if (defined $binaryCacheURL) {
|
||||||
# pollute /nix/var/nix/manifests. This also requires that we don't
|
|
||||||
# use the Nix daemon (because otherwise download-using-manifests won't
|
|
||||||
# see our NIX_MANIFESTS_DIRS environment variable).
|
|
||||||
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
|
|
||||||
$ENV{NIX_REMOTE} = "";
|
|
||||||
|
|
||||||
|
push @extraNixEnvArgs, "--option", "binary-caches", $binaryCacheURL;
|
||||||
|
|
||||||
print "\nPulling manifests...\n";
|
} else {
|
||||||
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
|
|
||||||
or barf "nix-pull failed: $?";
|
# Store the manifest in the temporary directory so that we don't
|
||||||
|
# pollute /nix/var/nix/manifests. This also requires that we
|
||||||
|
# don't use the Nix daemon (because otherwise
|
||||||
|
# download-using-manifests won't see our NIX_MANIFESTS_DIRS
|
||||||
|
# environment variable).
|
||||||
|
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
|
||||||
|
$ENV{NIX_REMOTE} = "";
|
||||||
|
|
||||||
|
print "\nPulling manifests...\n";
|
||||||
|
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
|
||||||
|
or barf "nix-pull failed: $?";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
print "\nInstalling package...\n";
|
print "\nInstalling package...\n";
|
||||||
|
|||||||
+21
-19
@@ -6,12 +6,30 @@ use File::Temp qw(tempdir);
|
|||||||
use File::stat;
|
use File::stat;
|
||||||
use Nix::Store;
|
use Nix::Store;
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
|
use Nix::Utils;
|
||||||
|
|
||||||
my $url = shift;
|
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256"; # obsolete
|
||||||
my $expHash = shift;
|
|
||||||
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256";
|
|
||||||
my $cacheDir = $ENV{'NIX_DOWNLOAD_CACHE'};
|
my $cacheDir = $ENV{'NIX_DOWNLOAD_CACHE'};
|
||||||
|
|
||||||
|
my @args;
|
||||||
|
my $arg;
|
||||||
|
while ($arg = shift) {
|
||||||
|
if ($arg eq "--help") {
|
||||||
|
exec "man nix-prefetch-url" or die;
|
||||||
|
} elsif ($arg eq "--type") {
|
||||||
|
$hashType = shift;
|
||||||
|
die "$0: `$arg' requires an argument\n" unless defined $hashType;
|
||||||
|
} elsif (substr($arg, 0, 1) eq "-") {
|
||||||
|
die "$0: unknown flag `$arg'\n";
|
||||||
|
} else {
|
||||||
|
push @args, $arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $url = $args[0];
|
||||||
|
my $expHash = $args[1];
|
||||||
|
|
||||||
|
|
||||||
if (!defined $url || $url eq "") {
|
if (!defined $url || $url eq "") {
|
||||||
print STDERR <<EOF
|
print STDERR <<EOF
|
||||||
Usage: nix-prefetch-url URL [EXPECTED-HASH]
|
Usage: nix-prefetch-url URL [EXPECTED-HASH]
|
||||||
@@ -20,22 +38,6 @@ EOF
|
|||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub writeFile {
|
|
||||||
my ($fn, $s) = @_;
|
|
||||||
open TMP, ">$fn" or die;
|
|
||||||
print TMP "$s" or die;
|
|
||||||
close TMP or die;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub readFile {
|
|
||||||
local $/ = undef;
|
|
||||||
my ($fn) = @_;
|
|
||||||
open TMP, "<$fn" or die;
|
|
||||||
my $s = <TMP>;
|
|
||||||
close TMP or die;
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $tmpDir = tempdir("nix-prefetch-url.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
my $tmpDir = tempdir("nix-prefetch-url.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||||
or die "cannot create a temporary directory";
|
or die "cannot create a temporary directory";
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
if test -n "$HOME"; then
|
if test -n "$HOME"; then
|
||||||
NIX_LINK="$HOME/.nix-profile"
|
NIX_LINK="$HOME/.nix-profile"
|
||||||
|
|
||||||
if ! test -L "$NIX_LINK"; then
|
# Set the default profile.
|
||||||
|
if ! [ -L "$NIX_LINK" ]; then
|
||||||
echo "creating $NIX_LINK" >&2
|
echo "creating $NIX_LINK" >&2
|
||||||
_NIX_DEF_LINK=@localstatedir@/nix/profiles/default
|
_NIX_DEF_LINK=@localstatedir@/nix/profiles/default
|
||||||
@coreutils@/ln -s "$_NIX_DEF_LINK" "$NIX_LINK"
|
@coreutils@/ln -s "$_NIX_DEF_LINK" "$NIX_LINK"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Subscribe the root user to the Nixpkgs channel by default.
|
||||||
|
if [ ! -e $HOME/.nix-channels ]; then
|
||||||
|
echo "http://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
|
||||||
|
fi
|
||||||
|
|
||||||
export PATH=$NIX_LINK/bin:$PATH
|
export PATH=$NIX_LINK/bin:$PATH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# This is a quick hack to make fontconfig-based packages in Nixpkgs
|
|
||||||
# work out of the box on non-NixOS systems. Of course, we should
|
|
||||||
# really fix fontconfig...
|
|
||||||
if test -z "$FONTCONFIG_FILE" -a -e /etc/fonts/fonts.conf; then
|
|
||||||
export FONTCONFIG_FILE=/etc/fonts/fonts.conf
|
|
||||||
fi
|
|
||||||
|
|||||||
+6
-15
@@ -76,31 +76,22 @@ sub processURL {
|
|||||||
open URL, ">$urlFile" or die "cannot create `$urlFile'";
|
open URL, ">$urlFile" or die "cannot create `$urlFile'";
|
||||||
print URL $origUrl;
|
print URL $origUrl;
|
||||||
close URL;
|
close URL;
|
||||||
|
|
||||||
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
|
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
|
||||||
|
|
||||||
unlink $finalPath if -e $finalPath;
|
unlink $finalPath if -e $finalPath;
|
||||||
|
|
||||||
symlink("$manifest", "$finalPath")
|
symlink("$manifest", "$finalPath")
|
||||||
or die "cannot link `$finalPath to `$manifest'";
|
or die "cannot link `$finalPath to `$manifest'";
|
||||||
|
|
||||||
# Delete all old manifests downloaded from this URL.
|
deleteOldManifests($origUrl, $urlFile);
|
||||||
for my $urlFile2 (glob "$manifestDir/*.url") {
|
|
||||||
next if $urlFile eq $urlFile2;
|
|
||||||
open URL, "<$urlFile2" or die;
|
|
||||||
my $url2 = <URL>;
|
|
||||||
chomp $url2;
|
|
||||||
close URL;
|
|
||||||
next unless $origUrl eq $url2;
|
|
||||||
my $base = $urlFile2; $base =~ s/.url$//;
|
|
||||||
unlink "${base}.url";
|
|
||||||
unlink "${base}.nixmanifest";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (@ARGV) {
|
while (@ARGV) {
|
||||||
my $url = shift @ARGV;
|
my $url = shift @ARGV;
|
||||||
if ($url eq "--skip-wrong-store") {
|
if ($url eq "--help") {
|
||||||
|
exec "man nix-pull" or die;
|
||||||
|
} elsif ($url eq "--skip-wrong-store") {
|
||||||
# No-op, no longer supported.
|
# No-op, no longer supported.
|
||||||
} else {
|
} else {
|
||||||
processURL $url;
|
processURL $url;
|
||||||
|
|||||||
+189
-195
@@ -1,85 +1,85 @@
|
|||||||
#! @perl@ -w @perlFlags@
|
#! @perl@ -w @perlFlags@
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use File::Basename;
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
|
use File::Path qw(mkpath);
|
||||||
use File::stat;
|
use File::stat;
|
||||||
|
use File::Copy;
|
||||||
use Nix::Config;
|
use Nix::Config;
|
||||||
|
use Nix::Store;
|
||||||
use Nix::Manifest;
|
use Nix::Manifest;
|
||||||
|
use Nix::Utils;
|
||||||
my $hashAlgo = "sha256";
|
|
||||||
|
|
||||||
my $tmpDir = tempdir("nix-push.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
my $tmpDir = tempdir("nix-push.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||||
or die "cannot create a temporary directory";
|
or die "cannot create a temporary directory";
|
||||||
|
|
||||||
my $nixExpr = "$tmpDir/create-nars.nix";
|
my $nixExpr = "$tmpDir/create-nars.nix";
|
||||||
my $manifest = "$tmpDir/MANIFEST";
|
|
||||||
|
|
||||||
my $curl = "$Nix::Config::curl --fail --silent";
|
|
||||||
my $extraCurlFlags = ${ENV{'CURL_FLAGS'}};
|
|
||||||
$curl = "$curl $extraCurlFlags" if defined $extraCurlFlags;
|
|
||||||
|
|
||||||
|
|
||||||
# Parse the command line.
|
# Parse the command line.
|
||||||
my $localCopy;
|
my $compressionType = "xz";
|
||||||
my $localArchivesDir;
|
my $force = 0;
|
||||||
my $localManifestFile;
|
my $destDir;
|
||||||
|
my $writeManifest = 0;
|
||||||
|
my $manifestPath;
|
||||||
|
my $archivesURL;
|
||||||
|
my $link = 0;
|
||||||
|
my @roots;
|
||||||
|
|
||||||
my $targetArchivesUrl;
|
for (my $n = 0; $n < scalar @ARGV; $n++) {
|
||||||
|
my $arg = $ARGV[$n];
|
||||||
|
|
||||||
my $archivesPutURL;
|
if ($arg eq "--help") {
|
||||||
my $archivesGetURL;
|
exec "man nix-push" or die;
|
||||||
my $manifestPutURL;
|
} elsif ($arg eq "--bzip2") {
|
||||||
|
$compressionType = "bzip2";
|
||||||
sub showSyntax {
|
} elsif ($arg eq "--none") {
|
||||||
print STDERR <<EOF
|
$compressionType = "none";
|
||||||
Usage: nix-push --copy ARCHIVES_DIR MANIFEST_FILE PATHS...
|
} elsif ($arg eq "--force") {
|
||||||
or: nix-push ARCHIVES_PUT_URL ARCHIVES_GET_URL MANIFEST_PUT_URL PATHS...
|
$force = 1;
|
||||||
|
} elsif ($arg eq "--dest") {
|
||||||
`nix-push' copies or uploads the closure of PATHS to the given
|
$n++;
|
||||||
destination.
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||||
EOF
|
$destDir = $ARGV[$n];
|
||||||
; # `
|
mkpath($destDir, 0, 0755);
|
||||||
exit 1;
|
} elsif ($arg eq "--manifest") {
|
||||||
}
|
$writeManifest = 1;
|
||||||
|
} elsif ($arg eq "--manifest-path") {
|
||||||
showSyntax if scalar @ARGV < 1;
|
$n++;
|
||||||
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||||
if ($ARGV[0] eq "--copy") {
|
$manifestPath = $ARGV[$n];
|
||||||
showSyntax if scalar @ARGV < 3;
|
$writeManifest = 1;
|
||||||
$localCopy = 1;
|
mkpath(dirname($manifestPath), 0, 0755);
|
||||||
shift @ARGV;
|
} elsif ($arg eq "--url-prefix") {
|
||||||
$localArchivesDir = shift @ARGV;
|
$n++;
|
||||||
$localManifestFile = shift @ARGV;
|
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||||
if ($ARGV[0] eq "--target") {
|
$archivesURL = $ARGV[$n];
|
||||||
shift @ARGV;
|
} elsif ($arg eq "--link") {
|
||||||
$targetArchivesUrl = shift @ARGV;
|
$link = 1;
|
||||||
}
|
} elsif (substr($arg, 0, 1) eq "-") {
|
||||||
else {
|
die "$0: unknown flag `$arg'\n";
|
||||||
$targetArchivesUrl = "file://$localArchivesDir";
|
} else {
|
||||||
|
push @roots, $arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
showSyntax if scalar @ARGV < 3;
|
die "$0: please specify a destination directory\n" if !defined $destDir;
|
||||||
$localCopy = 0;
|
|
||||||
$archivesPutURL = shift @ARGV;
|
$archivesURL = "file://$destDir" unless defined $archivesURL;
|
||||||
$archivesGetURL = shift @ARGV;
|
|
||||||
$manifestPutURL = shift @ARGV;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# From the given store paths, determine the set of requisite store
|
# From the given store paths, determine the set of requisite store
|
||||||
# paths, i.e, the paths required to realise them.
|
# paths, i.e, the paths required to realise them.
|
||||||
my %storePaths;
|
my %storePaths;
|
||||||
|
|
||||||
foreach my $path (@ARGV) {
|
foreach my $path (@roots) {
|
||||||
die unless $path =~ /^\//;
|
# Get all paths referenced by the normalisation of the given
|
||||||
|
|
||||||
# Get all paths referenced by the normalisation of the given
|
|
||||||
# Nix expression.
|
# Nix expression.
|
||||||
my $pid = open(READ,
|
my $pid = open(READ,
|
||||||
"$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
|
"$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
|
||||||
"--include-outputs '$path'|") or die;
|
"--include-outputs '$path'|") or die;
|
||||||
|
|
||||||
while (<READ>) {
|
while (<READ>) {
|
||||||
chomp;
|
chomp;
|
||||||
die "bad: $_" unless /^\//;
|
die "bad: $_" unless /^\//;
|
||||||
@@ -92,19 +92,50 @@ foreach my $path (@ARGV) {
|
|||||||
my @storePaths = keys %storePaths;
|
my @storePaths = keys %storePaths;
|
||||||
|
|
||||||
|
|
||||||
# For each path, create a Nix expression that turns the path into
|
# Don't create archives for files that are already in the binary cache.
|
||||||
# a Nix archive.
|
my @storePaths2;
|
||||||
|
my %narFiles;
|
||||||
|
foreach my $storePath (@storePaths) {
|
||||||
|
my $pathHash = substr(basename($storePath), 0, 32);
|
||||||
|
my $narInfoFile = "$destDir/$pathHash.narinfo";
|
||||||
|
if (-e $narInfoFile) {
|
||||||
|
my $narInfo = parseNARInfo($storePath, readFile($narInfoFile));
|
||||||
|
my $narFile = "$destDir/$narInfo->{url}";
|
||||||
|
if (-e $narFile) {
|
||||||
|
print STDERR "skipping existing $storePath\n";
|
||||||
|
# Add the NAR info to $narFiles if we're writing a
|
||||||
|
# manifest.
|
||||||
|
$narFiles{$storePath} = [
|
||||||
|
{ url => ("$archivesURL/" . basename $narInfo->{url})
|
||||||
|
, hash => $narInfo->{fileHash}
|
||||||
|
, size => $narInfo->{fileSize}
|
||||||
|
, compressionType => $narInfo->{compression}
|
||||||
|
, narHash => $narInfo->{narHash}
|
||||||
|
, narSize => $narInfo->{narSize}
|
||||||
|
, references => join(" ", map { "$Nix::Config::storeDir/$_" } @{$narInfo->{refs}})
|
||||||
|
, deriver => $narInfo->{deriver} ? "$Nix::Config::storeDir/$narInfo->{deriver}" : undef
|
||||||
|
}
|
||||||
|
] if $writeManifest;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push @storePaths2, $storePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Create a list of Nix derivations that turn each path into a Nix
|
||||||
|
# archive.
|
||||||
open NIX, ">$nixExpr";
|
open NIX, ">$nixExpr";
|
||||||
print NIX "[";
|
print NIX "[";
|
||||||
|
|
||||||
foreach my $storePath (@storePaths) {
|
foreach my $storePath (@storePaths2) {
|
||||||
die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
|
die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
|
||||||
|
|
||||||
# Construct a Nix expression that creates a Nix archive.
|
# Construct a Nix expression that creates a Nix archive.
|
||||||
my $nixexpr =
|
my $nixexpr =
|
||||||
"(import <nix/nar.nix> " .
|
"(import <nix/nar.nix> " .
|
||||||
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"$hashAlgo\"; }) ";
|
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"sha256\"; compressionType = \"$compressionType\"; }) ";
|
||||||
|
|
||||||
print NIX $nixexpr;
|
print NIX $nixexpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,172 +143,135 @@ print NIX "]";
|
|||||||
close NIX;
|
close NIX;
|
||||||
|
|
||||||
|
|
||||||
# Instantiate store derivations from the Nix expression.
|
# Build the Nix expression.
|
||||||
my @storeExprs;
|
print STDERR "building compressed archives...\n";
|
||||||
print STDERR "instantiating store derivations...\n";
|
my @narPaths;
|
||||||
my $pid = open(READ, "$Nix::Config::binDir/nix-instantiate $nixExpr|")
|
my $pid = open(READ, "$Nix::Config::binDir/nix-build $nixExpr -o $tmpDir/result |")
|
||||||
or die "cannot run nix-instantiate";
|
or die "cannot run nix-build";
|
||||||
while (<READ>) {
|
while (<READ>) {
|
||||||
chomp;
|
chomp;
|
||||||
die unless /^\//;
|
die unless /^\//;
|
||||||
push @storeExprs, $_;
|
push @narPaths, $_;
|
||||||
}
|
}
|
||||||
close READ or die "nix-instantiate failed: $?";
|
close READ or die "nix-build failed: $?";
|
||||||
|
|
||||||
|
|
||||||
# Build the derivations.
|
# Write the cache info file.
|
||||||
print STDERR "creating archives...\n";
|
my $cacheInfoFile = "$destDir/nix-cache-info";
|
||||||
|
if (! -e $cacheInfoFile) {
|
||||||
my @narPaths;
|
open FILE, ">$cacheInfoFile" or die "cannot create $cacheInfoFile: $!";
|
||||||
|
print FILE "StoreDir: $Nix::Config::storeDir\n";
|
||||||
my @tmp = @storeExprs;
|
print FILE "WantMassQuery: 0\n"; # by default, don't hit this cache for "nix-env -qas"
|
||||||
while (scalar @tmp > 0) {
|
close FILE;
|
||||||
my $n = scalar @tmp;
|
|
||||||
if ($n > 256) { $n = 256 };
|
|
||||||
my @tmp2 = @tmp[0..$n - 1];
|
|
||||||
@tmp = @tmp[$n..scalar @tmp - 1];
|
|
||||||
|
|
||||||
my $pid = open(READ, "$Nix::Config::binDir/nix-store --realise @tmp2|")
|
|
||||||
or die "cannot run nix-store";
|
|
||||||
while (<READ>) {
|
|
||||||
chomp;
|
|
||||||
die unless (/^\//);
|
|
||||||
push @narPaths, "$_";
|
|
||||||
}
|
|
||||||
close READ or die "nix-store failed: $?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Create the manifest.
|
# Copy the archives and the corresponding NAR info files.
|
||||||
print STDERR "creating manifest...\n";
|
print STDERR "copying archives...\n";
|
||||||
|
|
||||||
my %narFiles;
|
my $totalNarSize = 0;
|
||||||
my %patches;
|
my $totalCompressedSize = 0;
|
||||||
|
|
||||||
my @narArchives;
|
for (my $n = 0; $n < scalar @storePaths2; $n++) {
|
||||||
for (my $n = 0; $n < scalar @storePaths; $n++) {
|
my $storePath = $storePaths2[$n];
|
||||||
my $storePath = $storePaths[$n];
|
|
||||||
my $narDir = $narPaths[$n];
|
my $narDir = $narPaths[$n];
|
||||||
|
my $baseName = basename $storePath;
|
||||||
$storePath =~ /\/([^\/]*)$/;
|
|
||||||
my $basename = $1;
|
|
||||||
defined $basename or die;
|
|
||||||
|
|
||||||
open HASH, "$narDir/narbz2-hash" or die "cannot open narbz2-hash";
|
# Get info about the store path.
|
||||||
my $narbz2Hash = <HASH>;
|
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1);
|
||||||
chomp $narbz2Hash;
|
|
||||||
$narbz2Hash =~ /^[0-9a-z]+$/ or die "invalid hash";
|
|
||||||
close HASH;
|
|
||||||
|
|
||||||
my $narName = "$narbz2Hash.nar.bz2";
|
|
||||||
|
|
||||||
my $narFile = "$narDir/$narName";
|
|
||||||
(-f $narFile) or die "narfile for $storePath not found";
|
|
||||||
push @narArchives, $narFile;
|
|
||||||
|
|
||||||
my $narbz2Size = stat($narFile)->size;
|
|
||||||
|
|
||||||
my $references = `$Nix::Config::binDir/nix-store --query --references '$storePath'`;
|
|
||||||
die "cannot query references for `$storePath'" if $? != 0;
|
|
||||||
$references = join(" ", split(" ", $references));
|
|
||||||
|
|
||||||
my $deriver = `$Nix::Config::binDir/nix-store --query --deriver '$storePath'`;
|
|
||||||
die "cannot query deriver for `$storePath'" if $? != 0;
|
|
||||||
chomp $deriver;
|
|
||||||
$deriver = "" if $deriver eq "unknown-deriver";
|
|
||||||
|
|
||||||
my $narHash = `$Nix::Config::binDir/nix-store --query --hash '$storePath'`;
|
|
||||||
die "cannot query hash for `$storePath'" if $? != 0;
|
|
||||||
chomp $narHash;
|
|
||||||
|
|
||||||
# In some exceptional cases (such as VM tests that use the Nix
|
# In some exceptional cases (such as VM tests that use the Nix
|
||||||
# store of the host), the database doesn't contain the hash. So
|
# store of the host), the database doesn't contain the hash. So
|
||||||
# compute it.
|
# compute it.
|
||||||
if ($narHash =~ /^sha256:0*$/) {
|
if ($narHash =~ /^sha256:0*$/) {
|
||||||
$narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 '$storePath'`;
|
my $nar = "$tmpDir/nar";
|
||||||
die "cannot hash `$storePath'" if $? != 0;
|
system("$Nix::Config::binDir/nix-store --dump $storePath > $nar") == 0
|
||||||
|
or die "cannot dump $storePath\n";
|
||||||
|
$narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 --flat $nar`;
|
||||||
|
die "cannot hash `$nar'" if $? != 0;
|
||||||
chomp $narHash;
|
chomp $narHash;
|
||||||
$narHash = "sha256:$narHash";
|
$narHash = "sha256:$narHash";
|
||||||
|
$narSize = stat("$nar")->size;
|
||||||
|
unlink $nar or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $narSize = `$Nix::Config::binDir/nix-store --query --size '$storePath'`;
|
$totalNarSize += $narSize;
|
||||||
die "cannot query size for `$storePath'" if $? != 0;
|
|
||||||
chomp $narSize;
|
|
||||||
|
|
||||||
my $url;
|
# Get info about the compressed NAR.
|
||||||
if ($localCopy) {
|
open HASH, "$narDir/nar-compressed-hash" or die "cannot open nar-compressed-hash";
|
||||||
$url = "$targetArchivesUrl/$narName";
|
my $compressedHash = <HASH>;
|
||||||
} else {
|
chomp $compressedHash;
|
||||||
$url = "$archivesGetURL/$narName";
|
$compressedHash =~ /^[0-9a-z]+$/ or die "invalid hash";
|
||||||
|
close HASH;
|
||||||
|
|
||||||
|
my $narName = "$compressedHash.nar" . ($compressionType eq "xz" ? ".xz" : $compressionType eq "bzip2" ? ".bz2" : "");
|
||||||
|
|
||||||
|
my $narFile = "$narDir/$narName";
|
||||||
|
(-f $narFile) or die "NAR file for $storePath not found";
|
||||||
|
|
||||||
|
my $compressedSize = stat($narFile)->size;
|
||||||
|
$totalCompressedSize += $compressedSize;
|
||||||
|
|
||||||
|
printf STDERR "%s [%.2f MiB, %.1f%%]\n", $storePath,
|
||||||
|
$compressedSize / (1024 * 1024), $compressedSize / $narSize * 100;
|
||||||
|
|
||||||
|
# Copy the compressed NAR.
|
||||||
|
my $dst = "$destDir/$narName";
|
||||||
|
if (! -f $dst) {
|
||||||
|
my $tmp = "$destDir/.tmp.$$.$narName";
|
||||||
|
if ($link) {
|
||||||
|
link($narFile, $tmp) or die "cannot link $tmp to $narFile: $!\n";
|
||||||
|
} else {
|
||||||
|
copy($narFile, $tmp) or die "cannot copy $narFile to $tmp: $!\n";
|
||||||
|
}
|
||||||
|
rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Write the info file.
|
||||||
|
my $info;
|
||||||
|
$info .= "StorePath: $storePath\n";
|
||||||
|
$info .= "URL: $narName\n";
|
||||||
|
$info .= "Compression: $compressionType\n";
|
||||||
|
$info .= "FileHash: sha256:$compressedHash\n";
|
||||||
|
$info .= "FileSize: $compressedSize\n";
|
||||||
|
$info .= "NarHash: $narHash\n";
|
||||||
|
$info .= "NarSize: $narSize\n";
|
||||||
|
$info .= "References: " . join(" ", map { basename $_ } @{$refs}) . "\n";
|
||||||
|
if (defined $deriver) {
|
||||||
|
$info .= "Deriver: " . basename $deriver . "\n";
|
||||||
|
if (isValidPath($deriver)) {
|
||||||
|
my $drv = derivationFromPath($deriver);
|
||||||
|
$info .= "System: $drv->{platform}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $pathHash = substr(basename($storePath), 0, 32);
|
||||||
|
|
||||||
|
$dst = "$destDir/$pathHash.narinfo";
|
||||||
|
if ($force || ! -f $dst) {
|
||||||
|
my $tmp = "$destDir/.tmp.$$.$pathHash.narinfo";
|
||||||
|
open INFO, ">$tmp" or die;
|
||||||
|
print INFO "$info" or die;
|
||||||
|
close INFO or die;
|
||||||
|
rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
|
||||||
|
}
|
||||||
|
|
||||||
$narFiles{$storePath} = [
|
$narFiles{$storePath} = [
|
||||||
{ url => $url
|
{ url => "$archivesURL/$narName"
|
||||||
, hash => "$hashAlgo:$narbz2Hash"
|
, hash => "sha256:$compressedHash"
|
||||||
, size => $narbz2Size
|
, size => $compressedSize
|
||||||
|
, compressionType => $compressionType
|
||||||
, narHash => "$narHash"
|
, narHash => "$narHash"
|
||||||
, narSize => $narSize
|
, narSize => $narSize
|
||||||
, references => $references
|
, references => join(" ", @{$refs})
|
||||||
, deriver => $deriver
|
, deriver => $deriver
|
||||||
}
|
}
|
||||||
];
|
] if $writeManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeManifest $manifest, \%narFiles, \%patches;
|
printf STDERR "total compressed size %.2f MiB, %.1f%%\n",
|
||||||
|
$totalCompressedSize / (1024 * 1024), $totalCompressedSize / ($totalNarSize || 1) * 100;
|
||||||
|
|
||||||
|
|
||||||
sub copyFile {
|
# Optionally write a manifest.
|
||||||
my $src = shift;
|
writeManifest($manifestPath // "$destDir/MANIFEST", \%narFiles, \()) if $writeManifest;
|
||||||
my $dst = shift;
|
|
||||||
my $tmp = "$dst.tmp.$$";
|
|
||||||
system("@coreutils@/cp", $src, $tmp) == 0 or die "cannot copy file";
|
|
||||||
rename($tmp, $dst) or die "cannot rename file: $!";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Upload/copy the archives.
|
|
||||||
print STDERR "uploading/copying archives...\n";
|
|
||||||
|
|
||||||
sub archiveExists {
|
|
||||||
my $name = shift;
|
|
||||||
print STDERR " HEAD on $archivesGetURL/$name\n";
|
|
||||||
return system("$curl --head $archivesGetURL/$name > /dev/null") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $narArchive (@narArchives) {
|
|
||||||
|
|
||||||
$narArchive =~ /\/([^\/]*)$/;
|
|
||||||
my $basename = $1;
|
|
||||||
|
|
||||||
if ($localCopy) {
|
|
||||||
# Since nix-push creates $dst atomically, if it exists we
|
|
||||||
# don't have to copy again.
|
|
||||||
my $dst = "$localArchivesDir/$basename";
|
|
||||||
if (! -f "$localArchivesDir/$basename") {
|
|
||||||
print STDERR " $narArchive\n";
|
|
||||||
copyFile $narArchive, $dst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!archiveExists("$basename")) {
|
|
||||||
print STDERR " $narArchive\n";
|
|
||||||
system("$curl --show-error --upload-file " .
|
|
||||||
"'$narArchive' '$archivesPutURL/$basename' > /dev/null") == 0 or
|
|
||||||
die "curl failed on $narArchive: $?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Upload the manifest.
|
|
||||||
print STDERR "uploading manifest...\n";
|
|
||||||
if ($localCopy) {
|
|
||||||
copyFile $manifest, $localManifestFile;
|
|
||||||
copyFile "$manifest.bz2", "$localManifestFile.bz2";
|
|
||||||
} else {
|
|
||||||
system("$curl --show-error --upload-file " .
|
|
||||||
"'$manifest' '$manifestPutURL' > /dev/null") == 0 or
|
|
||||||
die "curl failed on $manifest: $?";
|
|
||||||
system("$curl --show-error --upload-file " .
|
|
||||||
"'$manifest'.bz2 '$manifestPutURL'.bz2 > /dev/null") == 0 or
|
|
||||||
die "curl failed on $manifest: $?";
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
|
SUBDIRS = boost libutil libstore libmain nix-store nix-hash \
|
||||||
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
|
libexpr nix-instantiate nix-env nix-daemon nix-setuid-helper \
|
||||||
nix-log2xml bsdiff-4.3
|
nix-log2xml bsdiff-4.3
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
noinst_PROGRAMS = bin2c
|
|
||||||
|
|
||||||
bin2c_SOURCES = bin2c.c
|
|
||||||
|
|
||||||
bin2c$(EXEEXT): bin2c.c
|
|
||||||
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -o bin2c bin2c.c
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
void print(const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
if (vprintf(format, ap) < 0) abort();
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char * * argv)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
if (argc != 2) abort();
|
|
||||||
print("static unsigned char %s[] = { ", argv[1]);
|
|
||||||
while ((c = getchar()) != EOF) {
|
|
||||||
print("0x%02x, ", (unsigned char) c);
|
|
||||||
}
|
|
||||||
print("0 };\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+23
-22
@@ -6,19 +6,18 @@
|
|||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
// !!! Shouldn't we return a pointer to a Value?
|
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
Bindings & autoArgs, Value & vIn)
|
||||||
Bindings & autoArgs, Expr * e, Value & v)
|
|
||||||
{
|
{
|
||||||
Strings tokens = tokenizeString(attrPath, ".");
|
Strings tokens = tokenizeString<Strings>(attrPath, ".");
|
||||||
|
|
||||||
Error attrError =
|
Error attrError =
|
||||||
Error(format("attribute selection path `%1%' does not match expression") % attrPath);
|
Error(format("attribute selection path `%1%' does not match expression") % attrPath);
|
||||||
|
|
||||||
string curPath;
|
string curPath;
|
||||||
|
|
||||||
state.mkThunk_(v, e);
|
Value * v = &vIn;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, tokens) {
|
foreach (Strings::iterator, i, tokens) {
|
||||||
|
|
||||||
if (!curPath.empty()) curPath += ".";
|
if (!curPath.empty()) curPath += ".";
|
||||||
@@ -27,14 +26,14 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
|||||||
/* Is *i an index (integer) or a normal attribute name? */
|
/* Is *i an index (integer) or a normal attribute name? */
|
||||||
enum { apAttr, apIndex } apType = apAttr;
|
enum { apAttr, apIndex } apType = apAttr;
|
||||||
string attr = *i;
|
string attr = *i;
|
||||||
int attrIndex = -1;
|
unsigned int attrIndex;
|
||||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||||
|
|
||||||
/* Evaluate the expression. */
|
/* Evaluate the expression. */
|
||||||
Value vTmp;
|
Value * vNew = state.allocValue();
|
||||||
state.autoCallFunction(autoArgs, v, vTmp);
|
state.autoCallFunction(autoArgs, *v, *vNew);
|
||||||
v = vTmp;
|
v = vNew;
|
||||||
state.forceValue(v);
|
state.forceValue(*v);
|
||||||
|
|
||||||
/* It should evaluate to either an attribute set or an
|
/* It should evaluate to either an attribute set or an
|
||||||
expression, according to what is specified in the
|
expression, according to what is specified in the
|
||||||
@@ -42,32 +41,34 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
|||||||
|
|
||||||
if (apType == apAttr) {
|
if (apType == apAttr) {
|
||||||
|
|
||||||
if (v.type != tAttrs)
|
if (v->type != tAttrs)
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
||||||
% curPath % showType(v));
|
% curPath % showType(*v));
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(state.symbols.create(attr));
|
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
||||||
if (a == v.attrs->end())
|
if (a == v->attrs->end())
|
||||||
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
||||||
v = *a->value;
|
v = &*a->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (apType == apIndex) {
|
else if (apType == apIndex) {
|
||||||
|
|
||||||
if (v.type != tList)
|
if (v->type != tList)
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
format("the expression selected by the selection path `%1%' should be a list but is %2%")
|
format("the expression selected by the selection path `%1%' should be a list but is %2%")
|
||||||
% curPath % showType(v));
|
% curPath % showType(*v));
|
||||||
|
|
||||||
if (attrIndex >= v.list.length)
|
if (attrIndex >= v->list.length)
|
||||||
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
|
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
|
||||||
|
|
||||||
v = *v.list.elems[attrIndex];
|
v = v->list.elems[attrIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
#ifndef __ATTR_PATH_H
|
#pragma once
|
||||||
#define __ATTR_PATH_H
|
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
Bindings & autoArgs, Value & vIn);
|
||||||
Bindings & autoArgs, Expr * e, Value & v);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__ATTR_PATH_H */
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#ifndef __COMMON_OPTS_H
|
#pragma once
|
||||||
#define __COMMON_OPTS_H
|
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* Some common option parsing between nix-env and nix-instantiate. */
|
/* Some common option parsing between nix-env and nix-instantiate. */
|
||||||
@@ -17,6 +15,3 @@ bool parseSearchPathArg(const string & arg, Strings::iterator & i,
|
|||||||
Path lookupFileArg(EvalState & state, string s);
|
Path lookupFileArg(EvalState & state, string s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__COMMON_OPTS_H */
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __EVAL_INLINE_H
|
#pragma once
|
||||||
#define __EVAL_INLINE_H
|
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
@@ -8,7 +7,6 @@
|
|||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwEvalError(const char * s))
|
LocalNoInlineNoReturn(void throwEvalError(const char * s))
|
||||||
{
|
{
|
||||||
throw EvalError(s);
|
throw EvalError(s);
|
||||||
@@ -23,13 +21,16 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
|
|||||||
void EvalState::forceValue(Value & v)
|
void EvalState::forceValue(Value & v)
|
||||||
{
|
{
|
||||||
if (v.type == tThunk) {
|
if (v.type == tThunk) {
|
||||||
ValueType saved = v.type;
|
Env * env = v.thunk.env;
|
||||||
|
Expr * expr = v.thunk.expr;
|
||||||
try {
|
try {
|
||||||
v.type = tBlackhole;
|
v.type = tBlackhole;
|
||||||
//checkInterrupt();
|
//checkInterrupt();
|
||||||
v.thunk.expr->eval(*this, *v.thunk.env, v);
|
expr->eval(*this, *env, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
v.type = saved;
|
v.type = tThunk;
|
||||||
|
v.thunk.env = env;
|
||||||
|
v.thunk.expr = expr;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,4 @@ inline void EvalState::forceList(Value & v)
|
|||||||
throwTypeError("value is %1% while a list was expected", showType(v));
|
throwTypeError("value is %1% while a list was expected", showType(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__EVAL_INLINE_H */
|
|
||||||
|
|||||||
+214
-128
@@ -44,7 +44,7 @@ void Bindings::sort()
|
|||||||
{
|
{
|
||||||
std::sort(begin(), end());
|
std::sort(begin(), end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream & operator << (std::ostream & str, const Value & v)
|
std::ostream & operator << (std::ostream & str, const Value & v)
|
||||||
{
|
{
|
||||||
@@ -138,14 +138,18 @@ EvalState::EvalState()
|
|||||||
, sName(symbols.create("name"))
|
, sName(symbols.create("name"))
|
||||||
, sSystem(symbols.create("system"))
|
, sSystem(symbols.create("system"))
|
||||||
, sOverrides(symbols.create("__overrides"))
|
, sOverrides(symbols.create("__overrides"))
|
||||||
|
, sOutputs(symbols.create("outputs"))
|
||||||
|
, sOutputName(symbols.create("outputName"))
|
||||||
|
, sIgnoreNulls(symbols.create("__ignoreNulls"))
|
||||||
|
, repair(false)
|
||||||
, baseEnv(allocEnv(128))
|
, baseEnv(allocEnv(128))
|
||||||
, baseEnvDispl(0)
|
|
||||||
, staticBaseEnv(false, 0)
|
, staticBaseEnv(false, 0)
|
||||||
|
, baseEnvDispl(0)
|
||||||
{
|
{
|
||||||
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
|
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
|
||||||
nrEvaluated = recursionDepth = maxRecursionDepth = 0;
|
|
||||||
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
|
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
|
||||||
deepestStack = (char *) -1;
|
nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0;
|
||||||
|
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
static bool gcInitialised = true;
|
static bool gcInitialised = true;
|
||||||
@@ -154,7 +158,7 @@ EvalState::EvalState()
|
|||||||
physical RAM, up to a maximum of 384 MiB) so that in most
|
physical RAM, up to a maximum of 384 MiB) so that in most
|
||||||
cases we don't need to garbage collect at all. (Collection
|
cases we don't need to garbage collect at all. (Collection
|
||||||
has a fairly significant overhead.) The heap size can be
|
has a fairly significant overhead.) The heap size can be
|
||||||
overriden through libgc's GC_INITIAL_HEAP_SIZE environment
|
overridden through libgc's GC_INITIAL_HEAP_SIZE environment
|
||||||
variable. We should probably also provide a nix.conf
|
variable. We should probably also provide a nix.conf
|
||||||
setting for this. Note that GC_expand_hp() causes a lot of
|
setting for this. Note that GC_expand_hp() causes a lot of
|
||||||
virtual, but not physical (resident) memory to be
|
virtual, but not physical (resident) memory to be
|
||||||
@@ -179,9 +183,9 @@ EvalState::EvalState()
|
|||||||
|
|
||||||
/* Initialise the Nix expression search path. */
|
/* Initialise the Nix expression search path. */
|
||||||
searchPathInsertionPoint = searchPath.end();
|
searchPathInsertionPoint = searchPath.end();
|
||||||
Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":");
|
Strings paths = tokenizeString<Strings>(getEnv("NIX_PATH", ""), ":");
|
||||||
foreach (Strings::iterator, i, paths) addToSearchPath(*i);
|
foreach (Strings::iterator, i, paths) addToSearchPath(*i);
|
||||||
addToSearchPath("nix=" + nixDataDir + "/nix/corepkgs");
|
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
|
||||||
searchPathInsertionPoint = searchPath.begin();
|
searchPathInsertionPoint = searchPath.begin();
|
||||||
|
|
||||||
createBaseEnv();
|
createBaseEnv();
|
||||||
@@ -190,7 +194,6 @@ EvalState::EvalState()
|
|||||||
|
|
||||||
EvalState::~EvalState()
|
EvalState::~EvalState()
|
||||||
{
|
{
|
||||||
assert(recursionDepth == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -219,6 +222,12 @@ void EvalState::addPrimOp(const string & name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::getBuiltin(const string & name, Value & v)
|
||||||
|
{
|
||||||
|
v = *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Every "format" object (even temporary) takes up a few hundred bytes
|
/* Every "format" object (even temporary) takes up a few hundred bytes
|
||||||
of stack space, which is a real killer in the recursive
|
of stack space, which is a real killer in the recursive
|
||||||
evaluator. So here are some helper functions for throwing
|
evaluator. So here are some helper functions for throwing
|
||||||
@@ -244,6 +253,11 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const
|
|||||||
throw TypeError(format(s) % pos % s2);
|
throw TypeError(format(s) % pos % s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
|
||||||
|
{
|
||||||
|
throw TypeError(format(s) % s1 % s2);
|
||||||
|
}
|
||||||
|
|
||||||
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
|
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
|
||||||
{
|
{
|
||||||
throw TypeError(format(s) % pos);
|
throw TypeError(format(s) % pos);
|
||||||
@@ -283,7 +297,7 @@ void mkString(Value & v, const string & s, const PathSet & context)
|
|||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
v.string.context = (const char * *)
|
v.string.context = (const char * *)
|
||||||
GC_MALLOC((context.size() + 1) * sizeof(char *));
|
GC_MALLOC((context.size() + 1) * sizeof(char *));
|
||||||
foreach (PathSet::const_iterator, i, context)
|
foreach (PathSet::const_iterator, i, context)
|
||||||
v.string.context[n++] = GC_STRDUP(i->c_str());
|
v.string.context[n++] = GC_STRDUP(i->c_str());
|
||||||
v.string.context[n] = 0;
|
v.string.context[n] = 0;
|
||||||
}
|
}
|
||||||
@@ -296,21 +310,29 @@ void mkPath(Value & v, const char * s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Value * EvalState::lookupVar(Env * env, const VarRef & var)
|
inline Value * EvalState::lookupVar(Env * env, const VarRef & var, bool noEval)
|
||||||
{
|
{
|
||||||
for (unsigned int l = var.level; l; --l, env = env->up) ;
|
for (unsigned int l = var.level; l; --l, env = env->up) ;
|
||||||
|
|
||||||
if (var.fromWith) {
|
if (!var.fromWith) return env->values[var.displ];
|
||||||
while (1) {
|
|
||||||
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
while (1) {
|
||||||
if (j != env->values[0]->attrs->end())
|
if (!env->haveWithAttrs) {
|
||||||
return j->value;
|
if (noEval) return 0;
|
||||||
if (env->prevWith == 0)
|
Expr * attrs = (Expr *) env->values[0];
|
||||||
throwEvalError("undefined variable `%1%'", var.name);
|
env->values[0] = allocValue();
|
||||||
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
|
evalAttrs(*env->up, attrs, *env->values[0]);
|
||||||
|
env->haveWithAttrs = true;
|
||||||
}
|
}
|
||||||
} else
|
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
||||||
return env->values[var.displ];
|
if (j != env->values[0]->attrs->end()) {
|
||||||
|
if (countCalls && j->pos) attrSelects[*j->pos]++;
|
||||||
|
return j->value;
|
||||||
|
}
|
||||||
|
if (!env->prevWith)
|
||||||
|
throwEvalError("undefined variable `%1%'", var.name);
|
||||||
|
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -327,10 +349,10 @@ Env & EvalState::allocEnv(unsigned int size)
|
|||||||
nrValuesInEnvs += size;
|
nrValuesInEnvs += size;
|
||||||
Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *));
|
Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *));
|
||||||
|
|
||||||
/* Clear the values because maybeThunk() expects this. */
|
/* Clear the values because maybeThunk() and lookupVar fromWith expects this. */
|
||||||
for (unsigned i = 0; i < size; ++i)
|
for (unsigned i = 0; i < size; ++i)
|
||||||
env->values[i] = 0;
|
env->values[i] = 0;
|
||||||
|
|
||||||
return *env;
|
return *env;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,12 +364,12 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::mkList(Value & v, unsigned int length)
|
void EvalState::mkList(Value & v, unsigned int length)
|
||||||
{
|
{
|
||||||
v.type = tList;
|
v.type = tList;
|
||||||
v.list.length = length;
|
v.list.length = length;
|
||||||
v.list.elems = (Value * *) GC_MALLOC(length * sizeof(Value *));
|
v.list.elems = length ? (Value * *) GC_MALLOC(length * sizeof(Value *)) : 0;
|
||||||
nrListElems += length;
|
nrListElems += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +417,7 @@ unsigned long nrAvoided = 0;
|
|||||||
|
|
||||||
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||||
{
|
{
|
||||||
Value * v = state.lookupVar(&env, info);
|
Value * v = state.lookupVar(&env, info, true);
|
||||||
/* The value might not be initialised in the environment yet.
|
/* The value might not be initialised in the environment yet.
|
||||||
In that case, ignore it. */
|
In that case, ignore it. */
|
||||||
if (v) { nrAvoided++; return v; }
|
if (v) { nrAvoided++; return v; }
|
||||||
@@ -424,19 +446,30 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
|||||||
|
|
||||||
void EvalState::evalFile(const Path & path, Value & v)
|
void EvalState::evalFile(const Path & path, Value & v)
|
||||||
{
|
{
|
||||||
FileEvalCache::iterator i = fileEvalCache.find(path);
|
Path path2 = resolveExprPath(path);
|
||||||
if (i == fileEvalCache.end()) {
|
|
||||||
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
FileEvalCache::iterator i = fileEvalCache.find(path2);
|
||||||
Expr * e = parseExprFromFile(path);
|
if (i != fileEvalCache.end()) {
|
||||||
try {
|
|
||||||
eval(e, v);
|
|
||||||
} catch (Error & e) {
|
|
||||||
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
fileEvalCache[path] = v;
|
|
||||||
} else
|
|
||||||
v = i->second;
|
v = i->second;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path2);
|
||||||
|
Expr * e = parseExprFromFile(path2);
|
||||||
|
try {
|
||||||
|
eval(e, v);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorPrefix(e, "while evaluating the file `%1%':\n", path2);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
fileEvalCache[path2] = v;
|
||||||
|
//if (path != path2) fileEvalCache[path2] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::resetFileCache()
|
||||||
|
{
|
||||||
|
fileEvalCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -505,23 +538,17 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
|||||||
environment, while the inherited attributes are evaluated
|
environment, while the inherited attributes are evaluated
|
||||||
in the original environment. */
|
in the original environment. */
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs) {
|
||||||
if (i->second.inherited) {
|
Value * vAttr;
|
||||||
/* !!! handle overrides? */
|
if (hasOverrides && !i->second.inherited) {
|
||||||
Value * vAttr = state.lookupVar(&env, i->second.var);
|
vAttr = state.allocValue();
|
||||||
env2.values[displ++] = vAttr;
|
mkThunk(*vAttr, env2, i->second.e);
|
||||||
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
|
} else
|
||||||
} else {
|
vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
|
||||||
Value * vAttr;
|
env2.values[displ++] = vAttr;
|
||||||
if (hasOverrides) {
|
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
|
||||||
vAttr = state.allocValue();
|
}
|
||||||
mkThunk(*vAttr, env2, i->second.e);
|
|
||||||
} else
|
|
||||||
vAttr = i->second.e->maybeThunk(state, env2);
|
|
||||||
env2.values[displ++] = vAttr;
|
|
||||||
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the rec contains an attribute called `__overrides', then
|
/* If the rec contains an attribute called `__overrides', then
|
||||||
evaluate it, and add the attributes in that set to the rec.
|
evaluate it, and add the attributes in that set to the rec.
|
||||||
This allows overriding of recursive attributes, which is
|
This allows overriding of recursive attributes, which is
|
||||||
@@ -547,10 +574,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
if (i->second.inherited)
|
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
||||||
v.attrs->push_back(Attr(i->first, state.lookupVar(&env, i->second.var), &i->second.pos));
|
|
||||||
else
|
|
||||||
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,10 +591,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
|||||||
environment. */
|
environment. */
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||||
if (i->second.inherited)
|
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
|
||||||
env2.values[displ++] = state.lookupVar(&env, i->second.var);
|
|
||||||
else
|
|
||||||
env2.values[displ++] = i->second.e->maybeThunk(state, env2);
|
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
body->eval(state, env2, v);
|
||||||
}
|
}
|
||||||
@@ -586,7 +607,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
|
|||||||
|
|
||||||
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value * v2 = state.lookupVar(&env, info);
|
Value * v2 = state.lookupVar(&env, info, false);
|
||||||
state.forceValue(*v2);
|
state.forceValue(*v2);
|
||||||
v = *v2;
|
v = *v2;
|
||||||
}
|
}
|
||||||
@@ -603,7 +624,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
|||||||
e->eval(state, env, vTmp);
|
e->eval(state, env, vTmp);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
foreach (AttrPath::const_iterator, i, attrPath) {
|
||||||
nrLookups++;
|
nrLookups++;
|
||||||
Bindings::iterator j;
|
Bindings::iterator j;
|
||||||
@@ -622,17 +643,19 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
|||||||
}
|
}
|
||||||
vAttrs = j->value;
|
vAttrs = j->value;
|
||||||
pos = j->pos;
|
pos = j->pos;
|
||||||
|
if (state.countCalls && pos) state.attrSelects[*pos]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
state.forceValue(*vAttrs);
|
state.forceValue(*vAttrs);
|
||||||
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (pos)
|
if (pos)
|
||||||
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
|
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
|
||||||
showAttrPath(attrPath), *pos);
|
showAttrPath(attrPath), *pos);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
v = *vAttrs;
|
v = *vAttrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +679,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
|||||||
vAttrs = j->value;
|
vAttrs = j->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mkBool(v, true);
|
mkBool(v, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,10 +714,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
assert(primOp->type == tPrimOp);
|
assert(primOp->type == tPrimOp);
|
||||||
unsigned int arity = primOp->primOp->arity;
|
unsigned int arity = primOp->primOp->arity;
|
||||||
unsigned int argsLeft = arity - argsDone;
|
unsigned int argsLeft = arity - argsDone;
|
||||||
|
|
||||||
if (argsLeft == 1) {
|
if (argsLeft == 1) {
|
||||||
/* We have all the arguments, so call the primop. */
|
/* We have all the arguments, so call the primop. */
|
||||||
|
|
||||||
/* Put all the arguments in an array. */
|
/* Put all the arguments in an array. */
|
||||||
Value * vArgs[arity];
|
Value * vArgs[arity];
|
||||||
unsigned int n = arity - 1;
|
unsigned int n = arity - 1;
|
||||||
@@ -703,6 +726,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
vArgs[n--] = arg->primOpApp.right;
|
vArgs[n--] = arg->primOpApp.right;
|
||||||
|
|
||||||
/* And call the primop. */
|
/* And call the primop. */
|
||||||
|
nrPrimOpCalls++;
|
||||||
|
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
||||||
try {
|
try {
|
||||||
primOp->primOp->fun(*this, vArgs, v);
|
primOp->primOp->fun(*this, vArgs, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
@@ -717,9 +742,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fun.type != tLambda)
|
if (fun.type != tLambda)
|
||||||
throwTypeError("attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
|
throwTypeError("attempt to call something which is not a function but %1%",
|
||||||
showType(fun));
|
showType(fun));
|
||||||
|
|
||||||
unsigned int size =
|
unsigned int size =
|
||||||
@@ -735,7 +760,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
forceAttrs(arg);
|
forceAttrs(arg);
|
||||||
|
|
||||||
if (!fun.lambda.fun->arg.empty())
|
if (!fun.lambda.fun->arg.empty())
|
||||||
env2.values[displ++] = &arg;
|
env2.values[displ++] = &arg;
|
||||||
|
|
||||||
@@ -746,8 +771,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||||
Bindings::iterator j = arg.attrs->find(i->name);
|
Bindings::iterator j = arg.attrs->find(i->name);
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
|
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
|
||||||
fun.lambda.fun->pos, i->name);
|
fun.lambda.fun->showNamePos(), i->name);
|
||||||
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
@@ -756,17 +781,24 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that each actual argument is listed as a formal
|
/* Check that each actual argument is listed as a formal
|
||||||
argument (unless the attribute match specifies a `...').
|
argument (unless the attribute match specifies a `...'). */
|
||||||
TODO: show the names of the expected/unexpected
|
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
||||||
arguments. */
|
/* Nope, so show the first unexpected argument to the
|
||||||
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
|
user. */
|
||||||
throwTypeError("function at %1% called with unexpected argument", fun.lambda.fun->pos);
|
foreach (Bindings::iterator, i, *arg.attrs)
|
||||||
|
if (fun.lambda.fun->formals->argNames.find(i->name) == fun.lambda.fun->formals->argNames.end())
|
||||||
|
throwTypeError("%1% called with unexpected argument `%2%'", fun.lambda.fun->showNamePos(), i->name);
|
||||||
|
abort(); // can't happen
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nrFunctionCalls++;
|
||||||
|
if (countCalls) functionCalls[fun.lambda.fun]++;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fun.lambda.fun->body->eval(*this, env2, v);
|
fun.lambda.fun->body->eval(*this, env2, v);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos);
|
addErrorPrefix(e, "while evaluating %1%:\n", fun.lambda.fun->showNamePos());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,20 +813,20 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value actualArgs;
|
Value * actualArgs = allocValue();
|
||||||
mkAttrs(actualArgs, fun.lambda.fun->formals->formals.size());
|
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
||||||
|
|
||||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||||
Bindings::iterator j = args.find(i->name);
|
Bindings::iterator j = args.find(i->name);
|
||||||
if (j != args.end())
|
if (j != args.end())
|
||||||
actualArgs.attrs->push_back(*j);
|
actualArgs->attrs->push_back(*j);
|
||||||
else if (!i->def)
|
else if (!i->def)
|
||||||
throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name);
|
throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
actualArgs.attrs->sort();
|
actualArgs->attrs->sort();
|
||||||
|
|
||||||
callFunction(fun, actualArgs, res);
|
callFunction(fun, *actualArgs, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -803,9 +835,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
|||||||
Env & env2(state.allocEnv(1));
|
Env & env2(state.allocEnv(1));
|
||||||
env2.up = &env;
|
env2.up = &env;
|
||||||
env2.prevWith = prevWith;
|
env2.prevWith = prevWith;
|
||||||
|
env2.haveWithAttrs = false;
|
||||||
env2.values[0] = state.allocValue();
|
env2.values[0] = (Value *) attrs;
|
||||||
state.evalAttrs(env, attrs, *env2.values[0]);
|
|
||||||
|
|
||||||
body->eval(state, env2, v);
|
body->eval(state, env2, v);
|
||||||
}
|
}
|
||||||
@@ -816,7 +847,7 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
|||||||
(state.evalBool(env, cond) ? then : else_)->eval(state, env, v);
|
(state.evalBool(env, cond) ? then : else_)->eval(state, env, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
if (!state.evalBool(env, cond))
|
if (!state.evalBool(env, cond))
|
||||||
@@ -824,7 +855,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
|||||||
body->eval(state, env, v);
|
body->eval(state, env, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
mkBool(v, !state.evalBool(env, e));
|
mkBool(v, !state.evalBool(env, e));
|
||||||
@@ -897,7 +928,7 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
|||||||
|
|
||||||
while (i != v1.attrs->end()) v.attrs->push_back(*i++);
|
while (i != v1.attrs->end()) v.attrs->push_back(*i++);
|
||||||
while (j != v2.attrs->end()) v.attrs->push_back(*j++);
|
while (j != v2.attrs->end()) v.attrs->push_back(*j++);
|
||||||
|
|
||||||
state.nrOpUpdateValuesCopied += v.attrs->size();
|
state.nrOpUpdateValuesCopied += v.attrs->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,14 +936,36 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
|||||||
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v1; e1->eval(state, env, v1);
|
Value v1; e1->eval(state, env, v1);
|
||||||
state.forceList(v1);
|
|
||||||
Value v2; e2->eval(state, env, v2);
|
Value v2; e2->eval(state, env, v2);
|
||||||
state.forceList(v2);
|
Value * lists[2] = { &v1, &v2 };
|
||||||
state.mkList(v, v1.list.length + v2.list.length);
|
state.concatLists(v, 2, lists);
|
||||||
for (unsigned int n = 0; n < v1.list.length; ++n)
|
}
|
||||||
v.list.elems[n] = v1.list.elems[n];
|
|
||||||
for (unsigned int n = 0; n < v2.list.length; ++n)
|
|
||||||
v.list.elems[n + v1.list.length] = v2.list.elems[n];
|
void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists)
|
||||||
|
{
|
||||||
|
nrListConcats++;
|
||||||
|
|
||||||
|
Value * nonEmpty = 0;
|
||||||
|
unsigned int len = 0;
|
||||||
|
for (unsigned int n = 0; n < nrLists; ++n) {
|
||||||
|
forceList(*lists[n]);
|
||||||
|
unsigned int l = lists[n]->list.length;
|
||||||
|
len += l;
|
||||||
|
if (l) nonEmpty = lists[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonEmpty && len == nonEmpty->list.length) {
|
||||||
|
v = *nonEmpty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkList(v, len);
|
||||||
|
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
|
||||||
|
unsigned int l = lists[n]->list.length;
|
||||||
|
memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *));
|
||||||
|
pos += l;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -920,31 +973,39 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
|
NixInt n = 0;
|
||||||
bool first = true, isPath = false;
|
|
||||||
Value vStr;
|
bool first = true;
|
||||||
|
ValueType firstType;
|
||||||
|
|
||||||
foreach (vector<Expr *>::iterator, i, *es) {
|
foreach (vector<Expr *>::iterator, i, *es) {
|
||||||
(*i)->eval(state, env, vStr);
|
Value vTmp;
|
||||||
|
(*i)->eval(state, env, vTmp);
|
||||||
|
|
||||||
/* If the first element is a path, then the result will also
|
/* If the first element is a path, then the result will also
|
||||||
be a path, we don't copy anything (yet - that's done later,
|
be a path, we don't copy anything (yet - that's done later,
|
||||||
since paths are copied when they are used in a derivation),
|
since paths are copied when they are used in a derivation),
|
||||||
and none of the strings are allowed to have contexts. */
|
and none of the strings are allowed to have contexts. */
|
||||||
if (first) {
|
if (first) {
|
||||||
isPath = vStr.type == tPath;
|
firstType = vTmp.type;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s << state.coerceToString(vStr, context, false, !isPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPath && !context.empty())
|
|
||||||
throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
|
|
||||||
|
|
||||||
if (isPath)
|
if (firstType == tInt && !forceString) {
|
||||||
|
if (vTmp.type != tInt)
|
||||||
|
throwEvalError("cannot add %1% to an integer", showType(vTmp));
|
||||||
|
n += vTmp.integer;
|
||||||
|
} else
|
||||||
|
s << state.coerceToString(vTmp, context, false, firstType != tPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstType == tInt)
|
||||||
|
mkInt(v, n);
|
||||||
|
else if (firstType == tPath) {
|
||||||
|
if (!context.empty())
|
||||||
|
throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
|
||||||
mkPath(v, s.str().c_str());
|
mkPath(v, s.str().c_str());
|
||||||
else
|
} else
|
||||||
mkString(v, s.str(), context);
|
mkString(v, s.str(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,12 +1013,12 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||||||
void EvalState::strictForceValue(Value & v)
|
void EvalState::strictForceValue(Value & v)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v);
|
||||||
|
|
||||||
if (v.type == tAttrs) {
|
if (v.type == tAttrs) {
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
foreach (Bindings::iterator, i, *v.attrs)
|
||||||
strictForceValue(*i->value);
|
strictForceValue(*i->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (v.type == tList) {
|
else if (v.type == tList) {
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.list.length; ++n)
|
||||||
strictForceValue(*v.list.elems[n]);
|
strictForceValue(*v.list.elems[n]);
|
||||||
@@ -965,7 +1026,7 @@ void EvalState::strictForceValue(Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int EvalState::forceInt(Value & v)
|
NixInt EvalState::forceInt(Value & v)
|
||||||
{
|
{
|
||||||
forceValue(v);
|
forceValue(v);
|
||||||
if (v.type != tInt)
|
if (v.type != tInt)
|
||||||
@@ -1003,7 +1064,7 @@ string EvalState::forceString(Value & v)
|
|||||||
void copyContext(const Value & v, PathSet & context)
|
void copyContext(const Value & v, PathSet & context)
|
||||||
{
|
{
|
||||||
if (v.string.context)
|
if (v.string.context)
|
||||||
for (const char * * p = v.string.context; *p; ++p)
|
for (const char * * p = v.string.context; *p; ++p)
|
||||||
context.insert(*p);
|
context.insert(*p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,7 +1114,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
|||||||
Path path(canonPath(v.path));
|
Path path(canonPath(v.path));
|
||||||
|
|
||||||
if (!copyToStore) return path;
|
if (!copyToStore) return path;
|
||||||
|
|
||||||
if (nix::isDerivation(path))
|
if (nix::isDerivation(path))
|
||||||
throwEvalError("file names are not allowed to end in `%1%'", drvExtension);
|
throwEvalError("file names are not allowed to end in `%1%'", drvExtension);
|
||||||
|
|
||||||
@@ -1061,9 +1122,9 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
|||||||
if (srcToStore[path] != "")
|
if (srcToStore[path] != "")
|
||||||
dstPath = srcToStore[path];
|
dstPath = srcToStore[path];
|
||||||
else {
|
else {
|
||||||
dstPath = readOnlyMode
|
dstPath = settings.readOnlyMode
|
||||||
? computeStorePathForPath(path).first
|
? computeStorePathForPath(path).first
|
||||||
: store->addToStore(path);
|
: store->addToStore(path, true, htSHA256, defaultPathFilter, repair);
|
||||||
srcToStore[path] = dstPath;
|
srcToStore[path] = dstPath;
|
||||||
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
|
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
|
||||||
% path % dstPath);
|
% path % dstPath);
|
||||||
@@ -1102,7 +1163,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throwTypeError("cannot coerce %1% to a string", showType(v));
|
throwTypeError("cannot coerce %1% to a string", showType(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1178,7 +1239,7 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
|||||||
for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j)
|
for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j)
|
||||||
if (i->name != j->name || !eqValues(*i->value, *j->value))
|
if (i->name != j->name || !eqValues(*i->value, *j->value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,16 +1267,11 @@ void EvalState::printStats()
|
|||||||
|
|
||||||
printMsg(v, format(" time elapsed: %1%") % cpuTime);
|
printMsg(v, format(" time elapsed: %1%") % cpuTime);
|
||||||
printMsg(v, format(" size of a value: %1%") % sizeof(Value));
|
printMsg(v, format(" size of a value: %1%") % sizeof(Value));
|
||||||
printMsg(v, format(" expressions evaluated: %1%") % nrEvaluated);
|
|
||||||
char x;
|
|
||||||
printMsg(v, format(" stack space used: %1% bytes") % (&x - deepestStack));
|
|
||||||
printMsg(v, format(" max eval() nesting depth: %1%") % maxRecursionDepth);
|
|
||||||
printMsg(v, format(" stack space per eval() level: %1% bytes")
|
|
||||||
% ((&x - deepestStack) / (float) maxRecursionDepth));
|
|
||||||
printMsg(v, format(" environments allocated: %1% (%2% bytes)")
|
printMsg(v, format(" environments allocated: %1% (%2% bytes)")
|
||||||
% nrEnvs % (nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *)));
|
% nrEnvs % (nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *)));
|
||||||
printMsg(v, format(" list elements: %1% (%2% bytes)")
|
printMsg(v, format(" list elements: %1% (%2% bytes)")
|
||||||
% nrListElems % (nrListElems * sizeof(Value *)));
|
% nrListElems % (nrListElems * sizeof(Value *)));
|
||||||
|
printMsg(v, format(" list concatenations: %1%") % nrListConcats);
|
||||||
printMsg(v, format(" values allocated: %1% (%2% bytes)")
|
printMsg(v, format(" values allocated: %1% (%2% bytes)")
|
||||||
% nrValues % (nrValues * sizeof(Value)));
|
% nrValues % (nrValues * sizeof(Value)));
|
||||||
printMsg(v, format(" attribute sets allocated: %1%") % nrAttrsets);
|
printMsg(v, format(" attribute sets allocated: %1%") % nrAttrsets);
|
||||||
@@ -1225,6 +1281,36 @@ void EvalState::printStats()
|
|||||||
printMsg(v, format(" number of thunks: %1%") % nrThunks);
|
printMsg(v, format(" number of thunks: %1%") % nrThunks);
|
||||||
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
|
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
|
||||||
printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
|
printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
|
||||||
|
printMsg(v, format(" number of primop calls: %1%") % nrPrimOpCalls);
|
||||||
|
printMsg(v, format(" number of function calls: %1%") % nrFunctionCalls);
|
||||||
|
|
||||||
|
if (countCalls) {
|
||||||
|
|
||||||
|
printMsg(v, format("calls to %1% primops:") % primOpCalls.size());
|
||||||
|
typedef std::multimap<unsigned int, Symbol> PrimOpCalls_;
|
||||||
|
PrimOpCalls_ primOpCalls_;
|
||||||
|
foreach (PrimOpCalls::iterator, i, primOpCalls)
|
||||||
|
primOpCalls_.insert(std::pair<unsigned int, Symbol>(i->second, i->first));
|
||||||
|
foreach_reverse (PrimOpCalls_::reverse_iterator, i, primOpCalls_)
|
||||||
|
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
||||||
|
|
||||||
|
printMsg(v, format("calls to %1% functions:") % functionCalls.size());
|
||||||
|
typedef std::multimap<unsigned int, ExprLambda *> FunctionCalls_;
|
||||||
|
FunctionCalls_ functionCalls_;
|
||||||
|
foreach (FunctionCalls::iterator, i, functionCalls)
|
||||||
|
functionCalls_.insert(std::pair<unsigned int, ExprLambda *>(i->second, i->first));
|
||||||
|
foreach_reverse (FunctionCalls_::reverse_iterator, i, functionCalls_)
|
||||||
|
printMsg(v, format("%1$10d %2%") % i->first % i->second->showNamePos());
|
||||||
|
|
||||||
|
printMsg(v, format("evaluations of %1% attributes:") % attrSelects.size());
|
||||||
|
typedef std::multimap<unsigned int, Pos> AttrSelects_;
|
||||||
|
AttrSelects_ attrSelects_;
|
||||||
|
foreach (AttrSelects::iterator, i, attrSelects)
|
||||||
|
attrSelects_.insert(std::pair<unsigned int, Pos>(i->second, i->first));
|
||||||
|
foreach_reverse (AttrSelects_::reverse_iterator, i, attrSelects_)
|
||||||
|
printMsg(v, format("%1$10d %2%") % i->first % i->second);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+61
-39
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __EVAL_H
|
#pragma once
|
||||||
#define __EVAL_H
|
|
||||||
|
|
||||||
#include "value.hh"
|
#include "value.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
@@ -53,7 +52,8 @@ struct PrimOp
|
|||||||
struct Env
|
struct Env
|
||||||
{
|
{
|
||||||
Env * up;
|
Env * up;
|
||||||
unsigned int prevWith; // nr of levels up to next `with' environment
|
unsigned short prevWith; // nr of levels up to next `with' environment
|
||||||
|
bool haveWithAttrs;
|
||||||
Value * values[0];
|
Value * values[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,19 +88,20 @@ struct EvalState;
|
|||||||
std::ostream & operator << (std::ostream & str, const Value & v);
|
std::ostream & operator << (std::ostream & str, const Value & v);
|
||||||
|
|
||||||
|
|
||||||
class EvalState
|
class EvalState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SymbolTable symbols;
|
SymbolTable symbols;
|
||||||
|
|
||||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
|
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
|
||||||
sSystem, sOverrides;
|
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls;
|
||||||
|
|
||||||
|
/* If set, force copying files to the Nix store even if they
|
||||||
|
already exist there. */
|
||||||
|
bool repair;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrcToStore srcToStore;
|
SrcToStore srcToStore;
|
||||||
|
|
||||||
/* A cache from path names to parse trees. */
|
|
||||||
std::map<Path, Expr *> parseTrees;
|
|
||||||
|
|
||||||
/* A cache from path names to values. */
|
/* A cache from path names to values. */
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
@@ -115,23 +116,25 @@ private:
|
|||||||
SearchPath::iterator searchPathInsertionPoint;
|
SearchPath::iterator searchPathInsertionPoint;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalState();
|
EvalState();
|
||||||
~EvalState();
|
~EvalState();
|
||||||
|
|
||||||
void addToSearchPath(const string & s);
|
void addToSearchPath(const string & s);
|
||||||
|
|
||||||
/* Parse a Nix expression from the specified file. If `path'
|
/* Parse a Nix expression from the specified file. */
|
||||||
refers to a directory, then "/default.nix" is appended. */
|
Expr * parseExprFromFile(const Path & path);
|
||||||
Expr * parseExprFromFile(Path path);
|
|
||||||
|
|
||||||
/* Parse a Nix expression from the specified string. */
|
/* Parse a Nix expression from the specified string. */
|
||||||
|
Expr * parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv);
|
||||||
Expr * parseExprFromString(const string & s, const Path & basePath);
|
Expr * parseExprFromString(const string & s, const Path & basePath);
|
||||||
|
|
||||||
/* Evaluate an expression read from the given file to normal
|
/* Evaluate an expression read from the given file to normal
|
||||||
form. */
|
form. */
|
||||||
void evalFile(const Path & path, Value & v);
|
void evalFile(const Path & path, Value & v);
|
||||||
|
|
||||||
|
void resetFileCache();
|
||||||
|
|
||||||
/* Look up a file in the search path. */
|
/* Look up a file in the search path. */
|
||||||
Path findFile(const string & path);
|
Path findFile(const string & path);
|
||||||
|
|
||||||
@@ -155,7 +158,7 @@ public:
|
|||||||
void strictForceValue(Value & v);
|
void strictForceValue(Value & v);
|
||||||
|
|
||||||
/* Force `v', and then verify that it has the expected type. */
|
/* Force `v', and then verify that it has the expected type. */
|
||||||
int forceInt(Value & v);
|
NixInt forceInt(Value & v);
|
||||||
bool forceBool(Value & v);
|
bool forceBool(Value & v);
|
||||||
inline void forceAttrs(Value & v);
|
inline void forceAttrs(Value & v);
|
||||||
inline void forceList(Value & v);
|
inline void forceList(Value & v);
|
||||||
@@ -171,7 +174,7 @@ public:
|
|||||||
/* String coercion. Converts strings, paths and derivations to a
|
/* String coercion. Converts strings, paths and derivations to a
|
||||||
string. If `coerceMore' is set, also converts nulls, integers,
|
string. If `coerceMore' is set, also converts nulls, integers,
|
||||||
booleans and lists to a string. If `copyToStore' is set,
|
booleans and lists to a string. If `copyToStore' is set,
|
||||||
referenced paths are copied to the Nix store as a side effect.q */
|
referenced paths are copied to the Nix store as a side effect. */
|
||||||
string coerceToString(Value & v, PathSet & context,
|
string coerceToString(Value & v, PathSet & context,
|
||||||
bool coerceMore = false, bool copyToStore = true);
|
bool coerceMore = false, bool copyToStore = true);
|
||||||
|
|
||||||
@@ -180,39 +183,43 @@ public:
|
|||||||
path. Nothing is copied to the store. */
|
path. Nothing is copied to the store. */
|
||||||
Path coerceToPath(Value & v, PathSet & context);
|
Path coerceToPath(Value & v, PathSet & context);
|
||||||
|
|
||||||
private:
|
public:
|
||||||
|
|
||||||
/* The base environment, containing the builtin functions and
|
/* The base environment, containing the builtin functions and
|
||||||
values. */
|
values. */
|
||||||
Env & baseEnv;
|
Env & baseEnv;
|
||||||
|
|
||||||
unsigned int baseEnvDispl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* The same, but used during parsing to resolve variables. */
|
/* The same, but used during parsing to resolve variables. */
|
||||||
StaticEnv staticBaseEnv; // !!! should be private
|
StaticEnv staticBaseEnv; // !!! should be private
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
unsigned int baseEnvDispl;
|
||||||
|
|
||||||
void createBaseEnv();
|
void createBaseEnv();
|
||||||
|
|
||||||
void addConstant(const string & name, Value & v);
|
void addConstant(const string & name, Value & v);
|
||||||
|
|
||||||
void addPrimOp(const string & name,
|
void addPrimOp(const string & name,
|
||||||
unsigned int arity, PrimOpFun primOp);
|
unsigned int arity, PrimOpFun primOp);
|
||||||
|
|
||||||
inline Value * lookupVar(Env * env, const VarRef & var);
|
public:
|
||||||
|
|
||||||
|
void getBuiltin(const string & name, Value & v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
inline Value * lookupVar(Env * env, const VarRef & var, bool noEval);
|
||||||
|
|
||||||
friend class ExprVar;
|
friend class ExprVar;
|
||||||
friend class ExprAttrs;
|
friend class ExprAttrs;
|
||||||
friend class ExprLet;
|
friend class ExprLet;
|
||||||
|
|
||||||
Expr * parse(const char * text,
|
Expr * parse(const char * text, const Path & path,
|
||||||
const Path & path, const Path & basePath);
|
const Path & basePath, StaticEnv & staticEnv);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Do a deep equality test between two values. That is, list
|
/* Do a deep equality test between two values. That is, list
|
||||||
elements and attributes are compared recursively. */
|
elements and attributes are compared recursively. */
|
||||||
bool eqValues(Value & v1, Value & v2);
|
bool eqValues(Value & v1, Value & v2);
|
||||||
@@ -222,7 +229,7 @@ public:
|
|||||||
/* Automatically call a function for which each argument has a
|
/* Automatically call a function for which each argument has a
|
||||||
default value or has a binding in the `args' map. */
|
default value or has a binding in the `args' map. */
|
||||||
void autoCallFunction(Bindings & args, Value & fun, Value & res);
|
void autoCallFunction(Bindings & args, Value & fun, Value & res);
|
||||||
|
|
||||||
/* Allocation primitives. */
|
/* Allocation primitives. */
|
||||||
Value * allocValue();
|
Value * allocValue();
|
||||||
Env & allocEnv(unsigned int size);
|
Env & allocEnv(unsigned int size);
|
||||||
@@ -233,25 +240,39 @@ public:
|
|||||||
void mkAttrs(Value & v, unsigned int expected);
|
void mkAttrs(Value & v, unsigned int expected);
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
|
|
||||||
|
void concatLists(Value & v, unsigned int nrLists, Value * * lists);
|
||||||
|
|
||||||
/* Print statistics. */
|
/* Print statistics. */
|
||||||
void printStats();
|
void printStats();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned long nrEnvs;
|
unsigned long nrEnvs;
|
||||||
unsigned long nrValuesInEnvs;
|
unsigned long nrValuesInEnvs;
|
||||||
unsigned long nrValues;
|
unsigned long nrValues;
|
||||||
unsigned long nrListElems;
|
unsigned long nrListElems;
|
||||||
unsigned long nrEvaluated;
|
|
||||||
unsigned long nrAttrsets;
|
unsigned long nrAttrsets;
|
||||||
unsigned long nrOpUpdates;
|
unsigned long nrOpUpdates;
|
||||||
unsigned long nrOpUpdateValuesCopied;
|
unsigned long nrOpUpdateValuesCopied;
|
||||||
unsigned int recursionDepth;
|
unsigned long nrListConcats;
|
||||||
unsigned int maxRecursionDepth;
|
unsigned long nrPrimOpCalls;
|
||||||
char * deepestStack; /* for measuring stack usage */
|
unsigned long nrFunctionCalls;
|
||||||
|
|
||||||
friend class RecursionCounter;
|
bool countCalls;
|
||||||
|
|
||||||
|
typedef std::map<Symbol, unsigned int> PrimOpCalls;
|
||||||
|
PrimOpCalls primOpCalls;
|
||||||
|
|
||||||
|
typedef std::map<ExprLambda *, unsigned int> FunctionCalls;
|
||||||
|
FunctionCalls functionCalls;
|
||||||
|
|
||||||
|
typedef std::map<Pos, unsigned int> AttrSelects;
|
||||||
|
AttrSelects attrSelects;
|
||||||
|
|
||||||
friend class ExprOpUpdate;
|
friend class ExprOpUpdate;
|
||||||
|
friend class ExprOpConcatLists;
|
||||||
|
friend class ExprSelect;
|
||||||
|
friend void prim_getAttr(EvalState & state, Value * * args, Value & v);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -259,7 +280,8 @@ private:
|
|||||||
string showType(const Value & v);
|
string showType(const Value & v);
|
||||||
|
|
||||||
|
|
||||||
|
/* If `path' refers to a directory, then append "/default.nix". */
|
||||||
|
Path resolveExprPath(Path path);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__EVAL_H */
|
|
||||||
|
|||||||
+64
-19
@@ -28,12 +28,53 @@ string DrvInfo::queryOutPath(EvalState & state) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DrvInfo::Outputs DrvInfo::queryOutputs(EvalState & state)
|
||||||
|
{
|
||||||
|
if (outputs.empty()) {
|
||||||
|
/* Get the ‘outputs’ list. */
|
||||||
|
Bindings::iterator i = attrs->find(state.sOutputs);
|
||||||
|
|
||||||
|
if (i == attrs->end())
|
||||||
|
outputs["out"] = queryOutPath(state);
|
||||||
|
else {
|
||||||
|
state.forceList(*i->value);
|
||||||
|
|
||||||
|
/* For each output... */
|
||||||
|
for (unsigned int j = 0; j < i->value->list.length; ++j) {
|
||||||
|
/* Evaluate the corresponding attribute set. */
|
||||||
|
string name = state.forceStringNoCtx(*i->value->list.elems[j]);
|
||||||
|
Bindings::iterator out = attrs->find(state.symbols.create(name));
|
||||||
|
if (out == attrs->end()) continue; // FIXME: throw error?
|
||||||
|
state.forceAttrs(*out->value);
|
||||||
|
|
||||||
|
/* And evaluate its ‘outPath’ attribute. */
|
||||||
|
Bindings::iterator outPath = out->value->attrs->find(state.sOutPath);
|
||||||
|
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
|
||||||
|
PathSet context;
|
||||||
|
outputs[name] = state.coerceToPath(*outPath->value, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string DrvInfo::queryOutputName(EvalState & state) const
|
||||||
|
{
|
||||||
|
if (outputName == "" && attrs) {
|
||||||
|
Bindings::iterator i = attrs->find(state.sOutputName);
|
||||||
|
(string &) outputName = i != attrs->end() ? state.forceStringNoCtx(*i->value) : "";
|
||||||
|
}
|
||||||
|
return outputName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||||
{
|
{
|
||||||
if (metaInfoRead) return meta;
|
if (metaInfoRead) return meta;
|
||||||
|
|
||||||
(bool &) metaInfoRead = true;
|
(bool &) metaInfoRead = true;
|
||||||
|
|
||||||
Bindings::iterator a = attrs->find(state.sMeta);
|
Bindings::iterator a = attrs->find(state.sMeta);
|
||||||
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
||||||
|
|
||||||
@@ -84,7 +125,8 @@ typedef set<Bindings *> Done;
|
|||||||
makes sense for the caller to recursively search for derivations in
|
makes sense for the caller to recursively search for derivations in
|
||||||
`v'. */
|
`v'. */
|
||||||
static bool getDerivation(EvalState & state, Value & v,
|
static bool getDerivation(EvalState & state, Value & v,
|
||||||
const string & attrPath, DrvInfos & drvs, Done & done)
|
const string & attrPath, DrvInfos & drvs, Done & done,
|
||||||
|
bool ignoreAssertionFailures)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
state.forceValue(v);
|
state.forceValue(v);
|
||||||
@@ -96,7 +138,7 @@ static bool getDerivation(EvalState & state, Value & v,
|
|||||||
done.insert(v.attrs);
|
done.insert(v.attrs);
|
||||||
|
|
||||||
DrvInfo drv;
|
DrvInfo drv;
|
||||||
|
|
||||||
Bindings::iterator i = v.attrs->find(state.sName);
|
Bindings::iterator i = v.attrs->find(state.sName);
|
||||||
/* !!! We really would like to have a decent back trace here. */
|
/* !!! We really would like to have a decent back trace here. */
|
||||||
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
||||||
@@ -114,18 +156,20 @@ static bool getDerivation(EvalState & state, Value & v,
|
|||||||
|
|
||||||
drvs.push_back(drv);
|
drvs.push_back(drv);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} catch (AssertionError & e) {
|
} catch (AssertionError & e) {
|
||||||
return false;
|
if (ignoreAssertionFailures) return false;
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
|
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv,
|
||||||
|
bool ignoreAssertionFailures)
|
||||||
{
|
{
|
||||||
Done done;
|
Done done;
|
||||||
DrvInfos drvs;
|
DrvInfos drvs;
|
||||||
getDerivation(state, v, "", drvs, done);
|
getDerivation(state, v, "", drvs, done, ignoreAssertionFailures);
|
||||||
if (drvs.size() != 1) return false;
|
if (drvs.size() != 1) return false;
|
||||||
drv = drvs.front();
|
drv = drvs.front();
|
||||||
return true;
|
return true;
|
||||||
@@ -140,15 +184,16 @@ static string addToPath(const string & s1, const string & s2)
|
|||||||
|
|
||||||
static void getDerivations(EvalState & state, Value & vIn,
|
static void getDerivations(EvalState & state, Value & vIn,
|
||||||
const string & pathPrefix, Bindings & autoArgs,
|
const string & pathPrefix, Bindings & autoArgs,
|
||||||
DrvInfos & drvs, Done & done)
|
DrvInfos & drvs, Done & done,
|
||||||
|
bool ignoreAssertionFailures)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
state.autoCallFunction(autoArgs, vIn, v);
|
state.autoCallFunction(autoArgs, vIn, v);
|
||||||
|
|
||||||
/* Process the expression. */
|
/* Process the expression. */
|
||||||
DrvInfo drv;
|
DrvInfo drv;
|
||||||
|
|
||||||
if (!getDerivation(state, v, pathPrefix, drvs, done)) ;
|
if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ;
|
||||||
|
|
||||||
else if (v.type == tAttrs) {
|
else if (v.type == tAttrs) {
|
||||||
|
|
||||||
@@ -171,8 +216,8 @@ static void getDerivations(EvalState & state, Value & vIn,
|
|||||||
string pathPrefix2 = addToPath(pathPrefix, i->first);
|
string pathPrefix2 = addToPath(pathPrefix, i->first);
|
||||||
Value & v2(*v.attrs->find(i->second)->value);
|
Value & v2(*v.attrs->find(i->second)->value);
|
||||||
if (combineChannels)
|
if (combineChannels)
|
||||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
|
else if (getDerivation(state, v2, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
|
||||||
/* If the value of this attribute is itself an
|
/* If the value of this attribute is itself an
|
||||||
attribute set, should we recurse into it? => Only
|
attribute set, should we recurse into it? => Only
|
||||||
if it has a `recurseForDerivations = true'
|
if it has a `recurseForDerivations = true'
|
||||||
@@ -180,7 +225,7 @@ static void getDerivations(EvalState & state, Value & vIn,
|
|||||||
if (v2.type == tAttrs) {
|
if (v2.type == tAttrs) {
|
||||||
Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations"));
|
Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations"));
|
||||||
if (j != v2.attrs->end() && state.forceBool(*j->value))
|
if (j != v2.attrs->end() && state.forceBool(*j->value))
|
||||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,8 +236,8 @@ static void getDerivations(EvalState & state, Value & vIn,
|
|||||||
startNest(nest, lvlDebug,
|
startNest(nest, lvlDebug,
|
||||||
format("evaluating list element"));
|
format("evaluating list element"));
|
||||||
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
||||||
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done))
|
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
||||||
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done);
|
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,11 +246,11 @@ static void getDerivations(EvalState & state, Value & vIn,
|
|||||||
|
|
||||||
|
|
||||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||||
Bindings & autoArgs, DrvInfos & drvs)
|
Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures)
|
||||||
{
|
{
|
||||||
Done done;
|
Done done;
|
||||||
getDerivations(state, v, pathPrefix, autoArgs, drvs, done);
|
getDerivations(state, v, pathPrefix, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-11
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __GET_DRVS_H
|
#pragma once
|
||||||
#define __GET_DRVS_H
|
|
||||||
|
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
@@ -26,13 +25,20 @@ typedef std::map<string, MetaValue> MetaInfo;
|
|||||||
|
|
||||||
struct DrvInfo
|
struct DrvInfo
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef std::map<string, Path> Outputs;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string drvPath;
|
string drvPath;
|
||||||
string outPath;
|
string outPath;
|
||||||
|
string outputName;
|
||||||
|
Outputs outputs;
|
||||||
|
|
||||||
bool metaInfoRead;
|
bool metaInfoRead;
|
||||||
MetaInfo meta;
|
MetaInfo meta;
|
||||||
|
|
||||||
|
bool failed; // set if we get an AssertionError
|
||||||
|
|
||||||
public:
|
public:
|
||||||
string name;
|
string name;
|
||||||
string attrPath; /* path towards the derivation */
|
string attrPath; /* path towards the derivation */
|
||||||
@@ -41,10 +47,12 @@ public:
|
|||||||
/* !!! make this private */
|
/* !!! make this private */
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
|
|
||||||
DrvInfo() : metaInfoRead(false), attrs(0) { };
|
DrvInfo() : metaInfoRead(false), failed(false), attrs(0) { };
|
||||||
|
|
||||||
string queryDrvPath(EvalState & state) const;
|
string queryDrvPath(EvalState & state) const;
|
||||||
string queryOutPath(EvalState & state) const;
|
string queryOutPath(EvalState & state) const;
|
||||||
|
string queryOutputName(EvalState & state) const;
|
||||||
|
Outputs queryOutputs(EvalState & state);
|
||||||
MetaInfo queryMetaInfo(EvalState & state) const;
|
MetaInfo queryMetaInfo(EvalState & state) const;
|
||||||
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
|
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
|
||||||
|
|
||||||
@@ -52,13 +60,16 @@ public:
|
|||||||
{
|
{
|
||||||
drvPath = s;
|
drvPath = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOutPath(const string & s)
|
void setOutPath(const string & s)
|
||||||
{
|
{
|
||||||
outPath = s;
|
outPath = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMetaInfo(const MetaInfo & meta);
|
void setMetaInfo(const MetaInfo & meta);
|
||||||
|
|
||||||
|
void setFailed() { failed = true; };
|
||||||
|
bool hasFailed() { return failed; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -71,13 +82,12 @@ typedef list<DrvInfo> DrvInfos;
|
|||||||
|
|
||||||
/* If value `v' denotes a derivation, store information about the
|
/* If value `v' denotes a derivation, store information about the
|
||||||
derivation in `drv' and return true. Otherwise, return false. */
|
derivation in `drv' and return true. Otherwise, return false. */
|
||||||
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv);
|
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv,
|
||||||
|
bool ignoreAssertionFailures);
|
||||||
|
|
||||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||||
Bindings & autoArgs, DrvInfos & drvs);
|
Bindings & autoArgs, DrvInfos & drvs,
|
||||||
|
bool ignoreAssertionFailures);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__GET_DRVS_H */
|
|
||||||
|
|||||||
+12
-9
@@ -9,21 +9,20 @@
|
|||||||
|
|
||||||
%{
|
%{
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#define BISON_HEADER_HACK
|
|
||||||
#include "parser-tab.hh"
|
#include "parser-tab.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
static void initLoc(YYLTYPE * loc)
|
static void initLoc(YYLTYPE * loc)
|
||||||
{
|
{
|
||||||
loc->first_line = loc->last_line = 1;
|
loc->first_line = loc->last_line = 1;
|
||||||
loc->first_column = loc->last_column = 1;
|
loc->first_column = loc->last_column = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
||||||
{
|
{
|
||||||
loc->first_line = loc->last_line;
|
loc->first_line = loc->last_line;
|
||||||
@@ -35,7 +34,7 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
|||||||
if (*s == '\n') /* cr/lf */
|
if (*s == '\n') /* cr/lf */
|
||||||
s++;
|
s++;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case '\n':
|
case '\n':
|
||||||
++loc->last_line;
|
++loc->last_line;
|
||||||
loc->last_column = 1;
|
loc->last_column = 1;
|
||||||
break;
|
break;
|
||||||
@@ -69,7 +68,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
|
|||||||
return new ExprString(symbols.create(t));
|
return new ExprString(symbols.create(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define YY_USER_INIT initLoc(yylloc)
|
#define YY_USER_INIT initLoc(yylloc)
|
||||||
@@ -78,7 +77,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
||||||
ID [a-zA-Z\_][a-zA-Z0-9\_\']*
|
ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
|
||||||
INT [0-9]+
|
INT [0-9]+
|
||||||
PATH [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
|
PATH [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
|
||||||
SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
|
SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
|
||||||
@@ -102,6 +101,8 @@ or { return OR_KW; }
|
|||||||
|
|
||||||
\=\= { return EQ; }
|
\=\= { return EQ; }
|
||||||
\!\= { return NEQ; }
|
\!\= { return NEQ; }
|
||||||
|
\<\= { return LEQ; }
|
||||||
|
\>\= { return GEQ; }
|
||||||
\&\& { return AND; }
|
\&\& { return AND; }
|
||||||
\|\| { return OR; }
|
\|\| { return OR; }
|
||||||
\-\> { return IMPL; }
|
\-\> { return IMPL; }
|
||||||
@@ -109,8 +110,10 @@ or { return OR_KW; }
|
|||||||
\+\+ { return CONCAT; }
|
\+\+ { return CONCAT; }
|
||||||
|
|
||||||
{ID} { yylval->id = strdup(yytext); return ID; }
|
{ID} { yylval->id = strdup(yytext); return ID; }
|
||||||
{INT} { int n = atoi(yytext); /* !!! overflow */
|
{INT} { errno = 0;
|
||||||
yylval->n = n;
|
yylval->n = strtol(yytext, 0, 10);
|
||||||
|
if (errno != 0)
|
||||||
|
throw ParseError(format("invalid integer `%1%'") % yytext);
|
||||||
return INT;
|
return INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +171,7 @@ or { return OR_KW; }
|
|||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* Horrible, disgusting hack: allow the parser to set the scanner
|
/* Horrible, disgusting hack: allow the parser to set the scanner
|
||||||
start condition back to STRING. Necessary in interpolations like
|
start condition back to STRING. Necessary in interpolations like
|
||||||
"foo${expr}bar"; after the close brace we have to go back to the
|
"foo${expr}bar"; after the close brace we have to go back to the
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ static string nextComponent(string::const_iterator & p,
|
|||||||
else
|
else
|
||||||
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
|
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
|
||||||
s += *p++;
|
s += *p++;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ int compareVersions(const string & v1, const string & v2)
|
|||||||
{
|
{
|
||||||
string::const_iterator p1 = v1.begin();
|
string::const_iterator p1 = v1.begin();
|
||||||
string::const_iterator p2 = v2.begin();
|
string::const_iterator p2 = v2.begin();
|
||||||
|
|
||||||
while (p1 != v1.end() || p2 != v2.end()) {
|
while (p1 != v1.end() || p2 != v2.end()) {
|
||||||
string c1 = nextComponent(p1, v1.end());
|
string c1 = nextComponent(p1, v1.end());
|
||||||
string c2 = nextComponent(p2, v2.end());
|
string c2 = nextComponent(p2, v2.end());
|
||||||
@@ -95,11 +95,10 @@ int compareVersions(const string & v1, const string & v2)
|
|||||||
DrvNames drvNamesFromArgs(const Strings & opArgs)
|
DrvNames drvNamesFromArgs(const Strings & opArgs)
|
||||||
{
|
{
|
||||||
DrvNames result;
|
DrvNames result;
|
||||||
for (Strings::const_iterator i = opArgs.begin();
|
foreach (Strings::const_iterator, i, opArgs)
|
||||||
i != opArgs.end(); ++i)
|
|
||||||
result.push_back(DrvName(*i));
|
result.push_back(DrvName(*i));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-10
@@ -1,12 +1,9 @@
|
|||||||
#ifndef __NAMES_H
|
#pragma once
|
||||||
#define __NAMES_H
|
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
struct DrvName
|
struct DrvName
|
||||||
{
|
{
|
||||||
string fullName;
|
string fullName;
|
||||||
@@ -19,15 +16,9 @@ struct DrvName
|
|||||||
bool matches(DrvName & n);
|
bool matches(DrvName & n);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef list<DrvName> DrvNames;
|
typedef list<DrvName> DrvNames;
|
||||||
|
|
||||||
|
|
||||||
int compareVersions(const string & v1, const string & v2);
|
int compareVersions(const string & v1, const string & v2);
|
||||||
DrvNames drvNamesFromArgs(const Strings & opArgs);
|
DrvNames drvNamesFromArgs(const Strings & opArgs);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__NAMES_H */
|
|
||||||
|
|||||||
+32
-15
@@ -224,20 +224,18 @@ void ExprAttrs::bindVars(const StaticEnv & env)
|
|||||||
{
|
{
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env);
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
newEnv.vars[i->first] = i->second.displ = displ++;
|
||||||
|
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
if (i->second.inherited) i->second.var.bind(env);
|
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
||||||
else i->second.e->bindVars(newEnv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
foreach (AttrDefs::iterator, i, attrs)
|
foreach (AttrDefs::iterator, i, attrs)
|
||||||
if (i->second.inherited) i->second.var.bind(env);
|
i->second.e->bindVars(env);
|
||||||
else i->second.e->bindVars(env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprList::bindVars(const StaticEnv & env)
|
void ExprList::bindVars(const StaticEnv & env)
|
||||||
@@ -249,9 +247,9 @@ void ExprList::bindVars(const StaticEnv & env)
|
|||||||
void ExprLambda::bindVars(const StaticEnv & env)
|
void ExprLambda::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env);
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
|
|
||||||
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
||||||
|
|
||||||
if (matchAttrs) {
|
if (matchAttrs) {
|
||||||
@@ -268,15 +266,14 @@ void ExprLambda::bindVars(const StaticEnv & env)
|
|||||||
void ExprLet::bindVars(const StaticEnv & env)
|
void ExprLet::bindVars(const StaticEnv & env)
|
||||||
{
|
{
|
||||||
StaticEnv newEnv(false, &env);
|
StaticEnv newEnv(false, &env);
|
||||||
|
|
||||||
unsigned int displ = 0;
|
unsigned int displ = 0;
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
newEnv.vars[i->first] = i->second.displ = displ++;
|
||||||
|
|
||||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||||
if (i->second.inherited) i->second.var.bind(env);
|
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
||||||
else i->second.e->bindVars(newEnv);
|
|
||||||
|
|
||||||
body->bindVars(newEnv);
|
body->bindVars(newEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,8 +290,8 @@ void ExprWith::bindVars(const StaticEnv & env)
|
|||||||
prevWith = level;
|
prevWith = level;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs->bindVars(env);
|
attrs->bindVars(env);
|
||||||
StaticEnv newEnv(true, &env);
|
StaticEnv newEnv(true, &env);
|
||||||
body->bindVars(newEnv);
|
body->bindVars(newEnv);
|
||||||
}
|
}
|
||||||
@@ -324,4 +321,24 @@ void ExprConcatStrings::bindVars(const StaticEnv & env)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Storing function names. */
|
||||||
|
|
||||||
|
void Expr::setName(Symbol & name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprLambda::setName(Symbol & name)
|
||||||
|
{
|
||||||
|
this->name = name;
|
||||||
|
body->setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string ExprLambda::showNamePos()
|
||||||
|
{
|
||||||
|
return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-13
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __NIXEXPR_H
|
#pragma once
|
||||||
#define __NIXEXPR_H
|
|
||||||
|
|
||||||
#include "value.hh"
|
#include "value.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
@@ -28,6 +27,15 @@ struct Pos
|
|||||||
Pos() : line(0), column(0) { };
|
Pos() : line(0), column(0) { };
|
||||||
Pos(const string & file, unsigned int line, unsigned int column)
|
Pos(const string & file, unsigned int line, unsigned int column)
|
||||||
: file(file), line(line), column(column) { };
|
: file(file), line(line), column(column) { };
|
||||||
|
bool operator < (const Pos & p2) const
|
||||||
|
{
|
||||||
|
int d = file.compare(p2.file);
|
||||||
|
if (d < 0) return true;
|
||||||
|
if (d > 0) return false;
|
||||||
|
if (line < p2.line) return true;
|
||||||
|
if (line > p2.line) return false;
|
||||||
|
return column < p2.column;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Pos noPos;
|
extern Pos noPos;
|
||||||
@@ -55,6 +63,7 @@ struct Expr
|
|||||||
virtual void bindVars(const StaticEnv & env);
|
virtual void bindVars(const StaticEnv & env);
|
||||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||||
virtual Value * maybeThunk(EvalState & state, Env & env);
|
virtual Value * maybeThunk(EvalState & state, Env & env);
|
||||||
|
virtual void setName(Symbol & name);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream & operator << (std::ostream & str, Expr & e);
|
std::ostream & operator << (std::ostream & str, Expr & e);
|
||||||
@@ -66,9 +75,9 @@ std::ostream & operator << (std::ostream & str, Expr & e);
|
|||||||
|
|
||||||
struct ExprInt : Expr
|
struct ExprInt : Expr
|
||||||
{
|
{
|
||||||
int n;
|
NixInt n;
|
||||||
Value v;
|
Value v;
|
||||||
ExprInt(int n) : n(n) { mkInt(v, n); };
|
ExprInt(NixInt n) : n(n) { mkInt(v, n); };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
Value * maybeThunk(EvalState & state, Env & env);
|
Value * maybeThunk(EvalState & state, Env & env);
|
||||||
};
|
};
|
||||||
@@ -105,7 +114,7 @@ struct VarRef
|
|||||||
/* Whether the variable comes from an environment (e.g. a rec, let
|
/* Whether the variable comes from an environment (e.g. a rec, let
|
||||||
or function argument) or from a "with". */
|
or function argument) or from a "with". */
|
||||||
bool fromWith;
|
bool fromWith;
|
||||||
|
|
||||||
/* In the former case, the value is obtained by going `level'
|
/* In the former case, the value is obtained by going `level'
|
||||||
levels up from the current environment and getting the
|
levels up from the current environment and getting the
|
||||||
`displ'th value in that environment. In the latter case, the
|
`displ'th value in that environment. In the latter case, the
|
||||||
@@ -150,12 +159,10 @@ struct ExprAttrs : Expr
|
|||||||
bool recursive;
|
bool recursive;
|
||||||
struct AttrDef {
|
struct AttrDef {
|
||||||
bool inherited;
|
bool inherited;
|
||||||
Expr * e; // if not inherited
|
Expr * e;
|
||||||
VarRef var; // if inherited
|
|
||||||
Pos pos;
|
Pos pos;
|
||||||
unsigned int displ; // displacement
|
unsigned int displ; // displacement
|
||||||
AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { };
|
AttrDef(Expr * e, const Pos & pos, bool inherited=false) : inherited(inherited), e(e), pos(pos) { };
|
||||||
AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { };
|
|
||||||
AttrDef() { };
|
AttrDef() { };
|
||||||
};
|
};
|
||||||
typedef std::map<Symbol, AttrDef> AttrDefs;
|
typedef std::map<Symbol, AttrDef> AttrDefs;
|
||||||
@@ -189,6 +196,7 @@ struct Formals
|
|||||||
struct ExprLambda : Expr
|
struct ExprLambda : Expr
|
||||||
{
|
{
|
||||||
Pos pos;
|
Pos pos;
|
||||||
|
Symbol name;
|
||||||
Symbol arg;
|
Symbol arg;
|
||||||
bool matchAttrs;
|
bool matchAttrs;
|
||||||
Formals * formals;
|
Formals * formals;
|
||||||
@@ -200,6 +208,8 @@ struct ExprLambda : Expr
|
|||||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||||
% arg % pos);
|
% arg % pos);
|
||||||
};
|
};
|
||||||
|
void setName(Symbol & name);
|
||||||
|
string showNamePos();
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -269,8 +279,10 @@ MakeBinOp(OpConcatLists, "++")
|
|||||||
|
|
||||||
struct ExprConcatStrings : Expr
|
struct ExprConcatStrings : Expr
|
||||||
{
|
{
|
||||||
|
bool forceString;
|
||||||
vector<Expr *> * es;
|
vector<Expr *> * es;
|
||||||
ExprConcatStrings(vector<Expr *> * es) : es(es) { };
|
ExprConcatStrings(bool forceString, vector<Expr *> * es)
|
||||||
|
: forceString(forceString), es(es) { };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -290,6 +302,3 @@ struct StaticEnv
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__NIXEXPR_H */
|
|
||||||
|
|||||||
+57
-42
@@ -4,26 +4,26 @@
|
|||||||
%error-verbose
|
%error-verbose
|
||||||
%defines
|
%defines
|
||||||
/* %no-lines */
|
/* %no-lines */
|
||||||
%parse-param { yyscan_t scanner }
|
%parse-param { void * scanner }
|
||||||
%parse-param { ParseData * data }
|
%parse-param { nix::ParseData * data }
|
||||||
%lex-param { yyscan_t scanner }
|
%lex-param { void * scanner }
|
||||||
%lex-param { ParseData * data }
|
%lex-param { nix::ParseData * data }
|
||||||
%expect 1
|
%expect 1
|
||||||
%expect-rr 1
|
%expect-rr 1
|
||||||
|
|
||||||
%code requires {
|
%code requires {
|
||||||
|
|
||||||
#ifndef BISON_HEADER
|
#ifndef BISON_HEADER
|
||||||
#define BISON_HEADER
|
#define BISON_HEADER
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct ParseData
|
struct ParseData
|
||||||
{
|
{
|
||||||
EvalState & state;
|
EvalState & state;
|
||||||
SymbolTable & symbols;
|
SymbolTable & symbols;
|
||||||
@@ -38,7 +38,7 @@ namespace nix {
|
|||||||
, sLetBody(symbols.create("<let-body>"))
|
, sLetBody(symbols.create("<let-body>"))
|
||||||
{ };
|
{ };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define YY_DECL int yylex \
|
#define YY_DECL int yylex \
|
||||||
@@ -52,7 +52,6 @@ namespace nix {
|
|||||||
|
|
||||||
#include "parser-tab.hh"
|
#include "parser-tab.hh"
|
||||||
#include "lexer-tab.hh"
|
#include "lexer-tab.hh"
|
||||||
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -64,14 +63,14 @@ using namespace nix;
|
|||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
|
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
|
||||||
{
|
{
|
||||||
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
||||||
% showAttrPath(attrPath) % pos % prevPos);
|
% showAttrPath(attrPath) % pos % prevPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
|
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
|
||||||
{
|
{
|
||||||
@@ -79,7 +78,7 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
|
|||||||
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
||||||
% showAttrPath(attrPath) % pos % prevPos);
|
% showAttrPath(attrPath) % pos % prevPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||||
Expr * e, const Pos & pos)
|
Expr * e, const Pos & pos)
|
||||||
@@ -105,6 +104,7 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e->setName(attrPath.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
|
|||||||
static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
|
static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
|
||||||
{
|
{
|
||||||
if (es.empty()) return new ExprString(symbols.create(""));
|
if (es.empty()) return new ExprString(symbols.create(""));
|
||||||
|
|
||||||
/* Figure out the minimum indentation. Note that by design
|
/* Figure out the minimum indentation. Note that by design
|
||||||
whitespace-only final lines are not taken into account. (So
|
whitespace-only final lines are not taken into account. (So
|
||||||
the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
|
the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
|
||||||
@@ -170,7 +170,7 @@ static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
|
|||||||
es2->push_back(*i);
|
es2->push_back(*i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string s2;
|
string s2;
|
||||||
for (unsigned int j = 0; j < e->s.size(); ++j) {
|
for (unsigned int j = 0; j < e->s.size(); ++j) {
|
||||||
if (atStartOfLine) {
|
if (atStartOfLine) {
|
||||||
@@ -203,7 +203,7 @@ static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
|
|||||||
es2->push_back(new ExprString(symbols.create(s2)));
|
es2->push_back(new ExprString(symbols.create(s2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExprConcatStrings(es2);
|
return es2->size() == 1 ? (*es2)[0] : new ExprConcatStrings(true, es2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -232,13 +232,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
// !!! We're probably leaking stuff here.
|
// !!! We're probably leaking stuff here.
|
||||||
nix::Expr * e;
|
nix::Expr * e;
|
||||||
nix::ExprList * list;
|
nix::ExprList * list;
|
||||||
nix::ExprAttrs * attrs;
|
nix::ExprAttrs * attrs;
|
||||||
nix::Formals * formals;
|
nix::Formals * formals;
|
||||||
nix::Formal * formal;
|
nix::Formal * formal;
|
||||||
int n;
|
nix::NixInt n;
|
||||||
char * id; // !!! -> Symbol
|
char * id; // !!! -> Symbol
|
||||||
char * path;
|
char * path;
|
||||||
char * uri;
|
char * uri;
|
||||||
@@ -269,12 +269,15 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
|||||||
%left OR
|
%left OR
|
||||||
%left AND
|
%left AND
|
||||||
%nonassoc EQ NEQ
|
%nonassoc EQ NEQ
|
||||||
|
%left '<' '>' LEQ GEQ
|
||||||
%right UPDATE
|
%right UPDATE
|
||||||
%left NEG
|
%left NOT
|
||||||
%left '+'
|
%left '+' '-'
|
||||||
|
%left '*' '/'
|
||||||
%right CONCAT
|
%right CONCAT
|
||||||
%nonassoc '?'
|
%nonassoc '?'
|
||||||
%nonassoc '~'
|
%nonassoc '~'
|
||||||
|
%nonassoc NEGATE
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@@ -306,9 +309,14 @@ expr_if
|
|||||||
;
|
;
|
||||||
|
|
||||||
expr_op
|
expr_op
|
||||||
: '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
|
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
||||||
|
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), new ExprInt(0)), $2); }
|
||||||
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||||
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
||||||
|
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3); }
|
||||||
|
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1)); }
|
||||||
|
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1); }
|
||||||
|
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3)); }
|
||||||
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
||||||
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
|
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
|
||||||
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
|
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
|
||||||
@@ -318,8 +326,11 @@ expr_op
|
|||||||
{ vector<Expr *> * l = new vector<Expr *>;
|
{ vector<Expr *> * l = new vector<Expr *>;
|
||||||
l->push_back($1);
|
l->push_back($1);
|
||||||
l->push_back($3);
|
l->push_back($3);
|
||||||
$$ = new ExprConcatStrings(l);
|
$$ = new ExprConcatStrings(false, l);
|
||||||
}
|
}
|
||||||
|
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), $1), $3); }
|
||||||
|
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__mul")), $1), $3); }
|
||||||
|
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__div")), $1), $3); }
|
||||||
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
||||||
| expr_app
|
| expr_app
|
||||||
;
|
;
|
||||||
@@ -349,7 +360,7 @@ expr_simple
|
|||||||
/* For efficiency, and to simplify parse trees a bit. */
|
/* For efficiency, and to simplify parse trees a bit. */
|
||||||
if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
|
if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
|
||||||
else if ($2->size() == 1) $$ = $2->front();
|
else if ($2->size() == 1) $$ = $2->front();
|
||||||
else $$ = new ExprConcatStrings($2);
|
else $$ = new ExprConcatStrings(true, $2);
|
||||||
}
|
}
|
||||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||||
$$ = stripIndentation(data->symbols, *$2);
|
$$ = stripIndentation(data->symbols, *$2);
|
||||||
@@ -402,7 +413,7 @@ binds
|
|||||||
if ($$->attrs.find(*i) != $$->attrs.end())
|
if ($$->attrs.find(*i) != $$->attrs.end())
|
||||||
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
|
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
|
||||||
Pos pos = makeCurPos(@3, data);
|
Pos pos = makeCurPos(@3, data);
|
||||||
$$->attrs[*i] = ExprAttrs::AttrDef(*i, pos);
|
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(*i), pos, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| binds INHERIT '(' expr ')' attrs ';'
|
| binds INHERIT '(' expr ')' attrs ';'
|
||||||
@@ -454,7 +465,7 @@ formal
|
|||||||
: ID { $$ = new Formal(data->symbols.create($1), 0); }
|
: ID { $$ = new Formal(data->symbols.create($1), 0); }
|
||||||
| ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); }
|
| ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
@@ -467,10 +478,10 @@ formal
|
|||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parse(const char * text,
|
Expr * EvalState::parse(const char * text,
|
||||||
const Path & path, const Path & basePath)
|
const Path & path, const Path & basePath, StaticEnv & staticEnv)
|
||||||
{
|
{
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
ParseData data(*this);
|
ParseData data(*this);
|
||||||
@@ -481,20 +492,20 @@ Expr * EvalState::parse(const char * text,
|
|||||||
yy_scan_string(text, scanner);
|
yy_scan_string(text, scanner);
|
||||||
int res = yyparse(scanner, &data);
|
int res = yyparse(scanner, &data);
|
||||||
yylex_destroy(scanner);
|
yylex_destroy(scanner);
|
||||||
|
|
||||||
if (res) throw ParseError(data.error);
|
if (res) throw ParseError(data.error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data.result->bindVars(staticBaseEnv);
|
data.result->bindVars(staticEnv);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
|
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.result;
|
return data.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromFile(Path path)
|
Path resolveExprPath(Path path)
|
||||||
{
|
{
|
||||||
assert(path[0] == '/');
|
assert(path[0] == '/');
|
||||||
|
|
||||||
@@ -512,21 +523,25 @@ Expr * EvalState::parseExprFromFile(Path path)
|
|||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
path = canonPath(path + "/default.nix");
|
path = canonPath(path + "/default.nix");
|
||||||
|
|
||||||
/* Read and parse the input file, unless it's already in the parse
|
return path;
|
||||||
tree cache. */
|
}
|
||||||
Expr * e = parseTrees[path];
|
|
||||||
if (!e) {
|
|
||||||
e = parse(readFile(path).c_str(), path, dirOf(path));
|
|
||||||
parseTrees[path] = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
|
Expr * EvalState::parseExprFromFile(const Path & path)
|
||||||
|
{
|
||||||
|
return parse(readFile(path).c_str(), path, dirOf(path), staticBaseEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath, StaticEnv & staticEnv)
|
||||||
|
{
|
||||||
|
return parse(s.c_str(), "(string)", basePath, staticEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
|
Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
|
||||||
{
|
{
|
||||||
return parse(s.c_str(), "(string)", basePath);
|
return parseExprFromString(s, basePath, staticBaseEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -541,7 +556,7 @@ void EvalState::addToSearchPath(const string & s)
|
|||||||
prefix = string(s, 0, pos);
|
prefix = string(s, 0, pos);
|
||||||
path = string(s, pos + 1);
|
path = string(s, pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
path = absPath(path);
|
path = absPath(path);
|
||||||
if (pathExists(path)) {
|
if (pathExists(path)) {
|
||||||
debug(format("adding path `%1%' to the search path") % path);
|
debug(format("adding path `%1%' to the search path") % path);
|
||||||
@@ -554,7 +569,7 @@ Path EvalState::findFile(const string & path)
|
|||||||
{
|
{
|
||||||
foreach (SearchPath::iterator, i, searchPath) {
|
foreach (SearchPath::iterator, i, searchPath) {
|
||||||
Path res;
|
Path res;
|
||||||
if (i->first.empty())
|
if (i->first.empty())
|
||||||
res = i->second + "/" + path;
|
res = i->second + "/" + path;
|
||||||
else {
|
else {
|
||||||
if (path.compare(0, i->first.size(), i->first) != 0 ||
|
if (path.compare(0, i->first.size(), i->first) != 0 ||
|
||||||
|
|||||||
+193
-47
@@ -37,7 +37,7 @@ std::pair<string, string> decodeContext(const string & s)
|
|||||||
|
|
||||||
|
|
||||||
/* Load and evaluate an expression from path specified by the
|
/* Load and evaluate an expression from path specified by the
|
||||||
argument. */
|
argument. */
|
||||||
static void prim_import(EvalState & state, Value * * args, Value & v)
|
static void prim_import(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
@@ -51,15 +51,44 @@ static void prim_import(EvalState & state, Value * * args, Value & v)
|
|||||||
% path % ctx);
|
% path % ctx);
|
||||||
if (isDerivation(ctx))
|
if (isDerivation(ctx))
|
||||||
try {
|
try {
|
||||||
|
/* For performance, prefetch all substitute info. */
|
||||||
|
PathSet willBuild, willSubstitute, unknown;
|
||||||
|
unsigned long long downloadSize, narSize;
|
||||||
|
queryMissing(*store, singleton<PathSet>(ctx),
|
||||||
|
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
|
||||||
/* !!! If using a substitute, we only need to fetch
|
/* !!! If using a substitute, we only need to fetch
|
||||||
the selected output of this derivation. */
|
the selected output of this derivation. */
|
||||||
store->buildDerivations(singleton<PathSet>(ctx));
|
store->buildPaths(singleton<PathSet>(ctx));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
throw ImportError(e.msg());
|
throw ImportError(e.msg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.evalFile(path, v);
|
if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {
|
||||||
|
Derivation drv = parseDerivation(readFile(path));
|
||||||
|
Value & w = *state.allocValue();
|
||||||
|
state.mkAttrs(w, 1 + drv.outputs.size());
|
||||||
|
mkString(*state.allocAttr(w, state.sDrvPath), path, singleton<PathSet>("=" + path));
|
||||||
|
state.mkList(*state.allocAttr(w, state.symbols.create("outputs")), drv.outputs.size());
|
||||||
|
unsigned int outputs_index = 0;
|
||||||
|
|
||||||
|
Value * outputsVal = w.attrs->find(state.symbols.create("outputs"))->value;
|
||||||
|
foreach (DerivationOutputs::iterator, i, drv.outputs) {
|
||||||
|
mkString(*state.allocAttr(w, state.symbols.create(i->first)),
|
||||||
|
i->second.path, singleton<PathSet>("!" + i->first + "!" + path));
|
||||||
|
mkString(*(outputsVal->list.elems[outputs_index++] = state.allocValue()),
|
||||||
|
i->first);
|
||||||
|
}
|
||||||
|
w.attrs->sort();
|
||||||
|
Value fun;
|
||||||
|
state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun);
|
||||||
|
state.forceFunction(fun);
|
||||||
|
mkApp(v, fun, w);
|
||||||
|
state.forceAttrs(v);
|
||||||
|
} else {
|
||||||
|
state.evalFile(path, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -153,8 +182,8 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
|||||||
list<Value> res;
|
list<Value> res;
|
||||||
set<Value, CompareValues> doneKeys; // !!! use Value *?
|
set<Value, CompareValues> doneKeys; // !!! use Value *?
|
||||||
while (!workSet.empty()) {
|
while (!workSet.empty()) {
|
||||||
Value * e = *(workSet.begin());
|
Value * e = *(workSet.begin());
|
||||||
workSet.pop_front();
|
workSet.pop_front();
|
||||||
|
|
||||||
state.forceAttrs(*e);
|
state.forceAttrs(*e);
|
||||||
|
|
||||||
@@ -167,7 +196,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
|||||||
if (doneKeys.find(*key->value) != doneKeys.end()) continue;
|
if (doneKeys.find(*key->value) != doneKeys.end()) continue;
|
||||||
doneKeys.insert(*key->value);
|
doneKeys.insert(*key->value);
|
||||||
res.push_back(*e);
|
res.push_back(*e);
|
||||||
|
|
||||||
/* Call the `operator' function with `e' as argument. */
|
/* Call the `operator' function with `e' as argument. */
|
||||||
Value call;
|
Value call;
|
||||||
mkApp(call, *op->value, *e);
|
mkApp(call, *op->value, *e);
|
||||||
@@ -217,7 +246,7 @@ static void prim_addErrorContext(EvalState & state, Value * * args, Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Try evaluating the argument. Success => {success=true; value=something;},
|
/* Try evaluating the argument. Success => {success=true; value=something;},
|
||||||
* else => {success=false; value=false;} */
|
* else => {success=false; value=false;} */
|
||||||
static void prim_tryEval(EvalState & state, Value * * args, Value & v)
|
static void prim_tryEval(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
@@ -280,16 +309,22 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
throw EvalError("required attribute `name' missing");
|
throw EvalError("required attribute `name' missing");
|
||||||
string drvName;
|
string drvName;
|
||||||
Pos & posDrvName(*attr->pos);
|
Pos & posDrvName(*attr->pos);
|
||||||
try {
|
try {
|
||||||
drvName = state.forceStringNoCtx(*attr->value);
|
drvName = state.forceStringNoCtx(*attr->value);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName);
|
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether null attributes should be ignored. */
|
||||||
|
bool ignoreNulls = false;
|
||||||
|
attr = args[0]->attrs->find(state.sIgnoreNulls);
|
||||||
|
if (attr != args[0]->attrs->end())
|
||||||
|
ignoreNulls = state.forceBool(*attr->value);
|
||||||
|
|
||||||
/* Build the derivation expression by processing the attributes. */
|
/* Build the derivation expression by processing the attributes. */
|
||||||
Derivation drv;
|
Derivation drv;
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
|
||||||
string outputHash, outputHashAlgo;
|
string outputHash, outputHashAlgo;
|
||||||
@@ -299,11 +334,17 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
outputs.insert("out");
|
outputs.insert("out");
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
||||||
|
if (i->name == state.sIgnoreNulls) continue;
|
||||||
string key = i->name;
|
string key = i->name;
|
||||||
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
|
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
if (ignoreNulls) {
|
||||||
|
state.forceValue(*i->value);
|
||||||
|
if (i->value->type == tNull) continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* The `args' attribute is special: it supplies the
|
/* The `args' attribute is special: it supplies the
|
||||||
command-line arguments to the builder. */
|
command-line arguments to the builder. */
|
||||||
if (key == "args") {
|
if (key == "args") {
|
||||||
@@ -328,12 +369,12 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
else if (key == "outputHash") outputHash = s;
|
else if (key == "outputHash") outputHash = s;
|
||||||
else if (key == "outputHashAlgo") outputHashAlgo = s;
|
else if (key == "outputHashAlgo") outputHashAlgo = s;
|
||||||
else if (key == "outputHashMode") {
|
else if (key == "outputHashMode") {
|
||||||
if (s == "recursive") outputHashRecursive = true;
|
if (s == "recursive") outputHashRecursive = true;
|
||||||
else if (s == "flat") outputHashRecursive = false;
|
else if (s == "flat") outputHashRecursive = false;
|
||||||
else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s);
|
else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s);
|
||||||
}
|
}
|
||||||
else if (key == "outputs") {
|
else if (key == "outputs") {
|
||||||
Strings tmp = tokenizeString(s);
|
Strings tmp = tokenizeString<Strings>(s);
|
||||||
outputs.clear();
|
outputs.clear();
|
||||||
foreach (Strings::iterator, j, tmp) {
|
foreach (Strings::iterator, j, tmp) {
|
||||||
if (outputs.find(*j) != outputs.end())
|
if (outputs.find(*j) != outputs.end())
|
||||||
@@ -360,13 +401,13 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Everything in the context of the strings in the derivation
|
/* Everything in the context of the strings in the derivation
|
||||||
attributes should be added as dependencies of the resulting
|
attributes should be added as dependencies of the resulting
|
||||||
derivation. */
|
derivation. */
|
||||||
foreach (PathSet::iterator, i, context) {
|
foreach (PathSet::iterator, i, context) {
|
||||||
Path path = *i;
|
Path path = *i;
|
||||||
|
|
||||||
/* Paths marked with `=' denote that the path of a derivation
|
/* Paths marked with `=' denote that the path of a derivation
|
||||||
is explicitly passed to the builder. Since that allows the
|
is explicitly passed to the builder. Since that allows the
|
||||||
builder to gain access to every path in the dependency
|
builder to gain access to every path in the dependency
|
||||||
@@ -403,7 +444,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
else
|
else
|
||||||
drv.inputSrcs.insert(path);
|
drv.inputSrcs.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do we have all required attributes? */
|
/* Do we have all required attributes? */
|
||||||
if (drv.builder == "")
|
if (drv.builder == "")
|
||||||
throw EvalError("required attribute `builder' missing");
|
throw EvalError("required attribute `builder' missing");
|
||||||
@@ -420,14 +461,14 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
/* Handle fixed-output derivations. */
|
/* Handle fixed-output derivations. */
|
||||||
if (outputs.size() != 1 || *(outputs.begin()) != "out")
|
if (outputs.size() != 1 || *(outputs.begin()) != "out")
|
||||||
throw Error("multiple outputs are not supported in fixed-output derivations");
|
throw Error("multiple outputs are not supported in fixed-output derivations");
|
||||||
|
|
||||||
HashType ht = parseHashType(outputHashAlgo);
|
HashType ht = parseHashType(outputHashAlgo);
|
||||||
if (ht == htUnknown)
|
if (ht == htUnknown)
|
||||||
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
|
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
|
||||||
Hash h = parseHash16or32(ht, outputHash);
|
Hash h = parseHash16or32(ht, outputHash);
|
||||||
outputHash = printHash(h);
|
outputHash = printHash(h);
|
||||||
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
|
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
|
||||||
|
|
||||||
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
|
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
|
||||||
drv.env["out"] = outPath;
|
drv.env["out"] = outPath;
|
||||||
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
|
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
|
||||||
@@ -447,7 +488,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
/* Use the masked derivation expression to compute the output
|
/* Use the masked derivation expression to compute the output
|
||||||
path. */
|
path. */
|
||||||
Hash h = hashDerivationModulo(*store, drv);
|
Hash h = hashDerivationModulo(*store, drv);
|
||||||
|
|
||||||
foreach (DerivationOutputs::iterator, i, drv.outputs)
|
foreach (DerivationOutputs::iterator, i, drv.outputs)
|
||||||
if (i->second.path == "") {
|
if (i->second.path == "") {
|
||||||
Path outPath = makeOutputPath(i->first, h, drvName);
|
Path outPath = makeOutputPath(i->first, h, drvName);
|
||||||
@@ -457,7 +498,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the resulting term into the Nix store directory. */
|
/* Write the resulting term into the Nix store directory. */
|
||||||
Path drvPath = writeDerivation(*store, drv, drvName);
|
Path drvPath = writeDerivation(*store, drv, drvName, state.repair);
|
||||||
|
|
||||||
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
|
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
|
||||||
% drvName % drvPath);
|
% drvName % drvPath);
|
||||||
@@ -502,7 +543,11 @@ static void prim_toPath(EvalState & state, Value * * args, Value & v)
|
|||||||
static void prim_storePath(EvalState & state, Value * * args, Value & v)
|
static void prim_storePath(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Path path = canonPath(state.coerceToPath(*args[0], context));
|
Path path = state.coerceToPath(*args[0], context);
|
||||||
|
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||||
|
directly in the store. The latter condition is necessary so
|
||||||
|
e.g. nix-push does the right thing. */
|
||||||
|
if (!isStorePath(path)) path = canonPath(path, true);
|
||||||
if (!isInStore(path))
|
if (!isInStore(path))
|
||||||
throw EvalError(format("path `%1%' is not in the Nix store") % path);
|
throw EvalError(format("path `%1%' is not in the Nix store") % path);
|
||||||
Path path2 = toStorePath(path);
|
Path path2 = toStorePath(path);
|
||||||
@@ -588,10 +633,10 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v)
|
|||||||
throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name);
|
throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name);
|
||||||
refs.insert(path);
|
refs.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path storePath = readOnlyMode
|
Path storePath = settings.readOnlyMode
|
||||||
? computeStorePathForText(name, contents, refs)
|
? computeStorePathForText(name, contents, refs)
|
||||||
: store->addTextToStore(name, contents, refs);
|
: store->addTextToStore(name, contents, refs, state.repair);
|
||||||
|
|
||||||
/* Note: we don't need to add `context' to the context of the
|
/* Note: we don't need to add `context' to the context of the
|
||||||
result, since `storePath' itself has references to the paths
|
result, since `storePath' itself has references to the paths
|
||||||
@@ -605,7 +650,7 @@ struct FilterFromExpr : PathFilter
|
|||||||
{
|
{
|
||||||
EvalState & state;
|
EvalState & state;
|
||||||
Value & filter;
|
Value & filter;
|
||||||
|
|
||||||
FilterFromExpr(EvalState & state, Value & filter)
|
FilterFromExpr(EvalState & state, Value & filter)
|
||||||
: state(state), filter(filter)
|
: state(state), filter(filter)
|
||||||
{
|
{
|
||||||
@@ -626,12 +671,12 @@ struct FilterFromExpr : PathFilter
|
|||||||
state.callFunction(filter, arg1, fun2);
|
state.callFunction(filter, arg1, fun2);
|
||||||
|
|
||||||
Value arg2;
|
Value arg2;
|
||||||
mkString(arg2,
|
mkString(arg2,
|
||||||
S_ISREG(st.st_mode) ? "regular" :
|
S_ISREG(st.st_mode) ? "regular" :
|
||||||
S_ISDIR(st.st_mode) ? "directory" :
|
S_ISDIR(st.st_mode) ? "directory" :
|
||||||
S_ISLNK(st.st_mode) ? "symlink" :
|
S_ISLNK(st.st_mode) ? "symlink" :
|
||||||
"unknown" /* not supported, will fail! */);
|
"unknown" /* not supported, will fail! */);
|
||||||
|
|
||||||
Value res;
|
Value res;
|
||||||
state.callFunction(fun2, arg2, res);
|
state.callFunction(fun2, arg2, res);
|
||||||
|
|
||||||
@@ -653,9 +698,9 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
|
|||||||
|
|
||||||
FilterFromExpr filter(state, *args[0]);
|
FilterFromExpr filter(state, *args[0]);
|
||||||
|
|
||||||
Path dstPath = readOnlyMode
|
Path dstPath = settings.readOnlyMode
|
||||||
? computeStorePathForPath(path, true, htSHA256, filter).first
|
? computeStorePathForPath(path, true, htSHA256, filter).first
|
||||||
: store->addToStore(path, true, htSHA256, filter);
|
: store->addToStore(path, true, htSHA256, filter, state.repair);
|
||||||
|
|
||||||
mkString(v, dstPath, singleton<PathSet>(dstPath));
|
mkString(v, dstPath, singleton<PathSet>(dstPath));
|
||||||
}
|
}
|
||||||
@@ -685,7 +730,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
|||||||
|
|
||||||
|
|
||||||
/* Dynamic version of the `.' operator. */
|
/* Dynamic version of the `.' operator. */
|
||||||
static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0]);
|
string attr = state.forceStringNoCtx(*args[0]);
|
||||||
state.forceAttrs(*args[1]);
|
state.forceAttrs(*args[1]);
|
||||||
@@ -694,6 +739,7 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
|||||||
if (i == args[1]->attrs->end())
|
if (i == args[1]->attrs->end())
|
||||||
throw EvalError(format("attribute `%1%' missing") % attr);
|
throw EvalError(format("attribute `%1%' missing") % attr);
|
||||||
// !!! add to stack trace?
|
// !!! add to stack trace?
|
||||||
|
if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
|
||||||
state.forceValue(*i->value);
|
state.forceValue(*i->value);
|
||||||
v = *i->value;
|
v = *i->value;
|
||||||
}
|
}
|
||||||
@@ -754,12 +800,12 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
|||||||
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
|
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
|
||||||
Value & v2(*args[0]->list.elems[i]);
|
Value & v2(*args[0]->list.elems[i]);
|
||||||
state.forceAttrs(v2);
|
state.forceAttrs(v2);
|
||||||
|
|
||||||
Bindings::iterator j = v2.attrs->find(state.sName);
|
Bindings::iterator j = v2.attrs->find(state.sName);
|
||||||
if (j == v2.attrs->end())
|
if (j == v2.attrs->end())
|
||||||
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
||||||
string name = state.forceStringNoCtx(*j->value);
|
string name = state.forceStringNoCtx(*j->value);
|
||||||
|
|
||||||
Bindings::iterator j2 = v2.attrs->find(state.symbols.create("value"));
|
Bindings::iterator j2 = v2.attrs->find(state.symbols.create("value"));
|
||||||
if (j2 == v2.attrs->end())
|
if (j2 == v2.attrs->end())
|
||||||
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
||||||
@@ -783,7 +829,7 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v)
|
|||||||
{
|
{
|
||||||
state.forceAttrs(*args[0]);
|
state.forceAttrs(*args[0]);
|
||||||
state.forceAttrs(*args[1]);
|
state.forceAttrs(*args[1]);
|
||||||
|
|
||||||
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
|
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
||||||
@@ -839,19 +885,33 @@ static void prim_isList(EvalState & state, Value * * args, Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void elemAt(EvalState & state, Value & list, int n, Value & v)
|
||||||
|
{
|
||||||
|
state.forceList(list);
|
||||||
|
if (n < 0 || n >= list.list.length)
|
||||||
|
throw Error(format("list index %1% is out of bounds") % n);
|
||||||
|
state.forceValue(*list.list.elems[n]);
|
||||||
|
v = *list.list.elems[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the n-1'th element of a list. */
|
||||||
|
static void prim_elemAt(EvalState & state, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
elemAt(state, *args[0], state.forceInt(*args[1]), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the first element of a list. */
|
/* Return the first element of a list. */
|
||||||
static void prim_head(EvalState & state, Value * * args, Value & v)
|
static void prim_head(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(*args[0]);
|
elemAt(state, *args[0], 0, v);
|
||||||
if (args[0]->list.length == 0)
|
|
||||||
throw Error("`head' called on an empty list");
|
|
||||||
state.forceValue(*args[0]->list.elems[0]);
|
|
||||||
v = *args[0]->list.elems[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a list consisting of everything but the the first element of
|
/* Return a list consisting of everything but the the first element of
|
||||||
a list. */
|
a list. Warning: this function takes O(n) time, so you probably
|
||||||
|
don't want to use it! */
|
||||||
static void prim_tail(EvalState & state, Value * * args, Value & v)
|
static void prim_tail(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceList(*args[0]);
|
state.forceList(*args[0]);
|
||||||
@@ -872,11 +932,64 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
|
|||||||
state.mkList(v, args[1]->list.length);
|
state.mkList(v, args[1]->list.length);
|
||||||
|
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
for (unsigned int n = 0; n < v.list.length; ++n)
|
||||||
mkApp(*(v.list.elems[n] = state.allocValue()),
|
mkApp(*(v.list.elems[n] = state.allocValue()),
|
||||||
*args[0], *args[1]->list.elems[n]);
|
*args[0], *args[1]->list.elems[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Filter a list using a predicate; that is, return a list containing
|
||||||
|
every element from the list for which the predicate function
|
||||||
|
returns true. */
|
||||||
|
static void prim_filter(EvalState & state, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
state.forceFunction(*args[0]);
|
||||||
|
state.forceList(*args[1]);
|
||||||
|
|
||||||
|
// FIXME: putting this on the stack is risky.
|
||||||
|
Value * vs[args[1]->list.length];
|
||||||
|
unsigned int k = 0;
|
||||||
|
|
||||||
|
bool same = true;
|
||||||
|
for (unsigned int n = 0; n < args[1]->list.length; ++n) {
|
||||||
|
Value res;
|
||||||
|
state.callFunction(*args[0], *args[1]->list.elems[n], res);
|
||||||
|
if (state.forceBool(res))
|
||||||
|
vs[k++] = args[1]->list.elems[n];
|
||||||
|
else
|
||||||
|
same = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (same)
|
||||||
|
v = *args[1];
|
||||||
|
else {
|
||||||
|
state.mkList(v, k);
|
||||||
|
for (unsigned int n = 0; n < k; ++n) v.list.elems[n] = vs[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if a list contains a given element. */
|
||||||
|
static void prim_elem(EvalState & state, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
state.forceList(*args[1]);
|
||||||
|
for (unsigned int n = 0; n < args[1]->list.length; ++n)
|
||||||
|
if (state.eqValues(*args[0], *args[1]->list.elems[n])) {
|
||||||
|
res = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mkBool(v, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Concatenate a list of lists. */
|
||||||
|
static void prim_concatLists(EvalState & state, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
state.forceList(*args[0]);
|
||||||
|
state.concatLists(v, args[0]->list.length, args[0]->list.elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the length of a list. This is an O(1) time operation. */
|
/* Return the length of a list. This is an O(1) time operation. */
|
||||||
static void prim_length(EvalState & state, Value * * args, Value & v)
|
static void prim_length(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
@@ -910,7 +1023,7 @@ static void prim_mul(EvalState & state, Value * * args, Value & v)
|
|||||||
|
|
||||||
static void prim_div(EvalState & state, Value * * args, Value & v)
|
static void prim_div(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
int i2 = state.forceInt(*args[1]);
|
NixInt i2 = state.forceInt(*args[1]);
|
||||||
if (i2 == 0) throw EvalError("division by zero");
|
if (i2 == 0) throw EvalError("division by zero");
|
||||||
mkInt(v, state.forceInt(*args[0]) / i2);
|
mkInt(v, state.forceInt(*args[0]) / i2);
|
||||||
}
|
}
|
||||||
@@ -918,7 +1031,10 @@ static void prim_div(EvalState & state, Value * * args, Value & v)
|
|||||||
|
|
||||||
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
|
static void prim_lessThan(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
mkBool(v, state.forceInt(*args[0]) < state.forceInt(*args[1]));
|
state.forceValue(*args[0]);
|
||||||
|
state.forceValue(*args[1]);
|
||||||
|
CompareValues comp;
|
||||||
|
mkBool(v, comp(*args[0], *args[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -988,11 +1104,26 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args
|
|||||||
if (p.at(0) == '=') p = "~" + string(p, 1);
|
if (p.at(0) == '=') p = "~" + string(p, 1);
|
||||||
context2.insert(p);
|
context2.insert(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
mkString(v, s, context2);
|
mkString(v, s, context2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the cryptographic hash of a string in base-16. */
|
||||||
|
static void prim_hashString(EvalState & state, Value * * args, Value & v)
|
||||||
|
{
|
||||||
|
string type = state.forceStringNoCtx(*args[0]);
|
||||||
|
HashType ht = parseHashType(type);
|
||||||
|
if (ht == htUnknown)
|
||||||
|
throw Error(format("unknown hash type `%1%'") % type);
|
||||||
|
|
||||||
|
PathSet context; // discarded
|
||||||
|
string s = state.forceString(*args[1], context);
|
||||||
|
|
||||||
|
mkString(v, printHash(hashString(ht, s)), context);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Versions
|
* Versions
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
@@ -1035,19 +1166,29 @@ void EvalState::createBaseEnv()
|
|||||||
|
|
||||||
mkBool(v, true);
|
mkBool(v, true);
|
||||||
addConstant("true", v);
|
addConstant("true", v);
|
||||||
|
|
||||||
mkBool(v, false);
|
mkBool(v, false);
|
||||||
addConstant("false", v);
|
addConstant("false", v);
|
||||||
|
|
||||||
v.type = tNull;
|
v.type = tNull;
|
||||||
addConstant("null", v);
|
addConstant("null", v);
|
||||||
|
|
||||||
mkInt(v, time(0));
|
mkInt(v, time(0));
|
||||||
addConstant("__currentTime", v);
|
addConstant("__currentTime", v);
|
||||||
|
|
||||||
mkString(v, thisSystem.c_str());
|
mkString(v, settings.thisSystem.c_str());
|
||||||
addConstant("__currentSystem", v);
|
addConstant("__currentSystem", v);
|
||||||
|
|
||||||
|
mkString(v, nixVersion.c_str());
|
||||||
|
addConstant("__nixVersion", v);
|
||||||
|
|
||||||
|
/* Language version. This should be increased every time a new
|
||||||
|
language feature gets added. It's not necessary to increase it
|
||||||
|
when primops get added, because you can just use `builtins ?
|
||||||
|
primOp' to check. */
|
||||||
|
mkInt(v, 1);
|
||||||
|
addConstant("__langVersion", v);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
addPrimOp("import", 1, prim_import);
|
addPrimOp("import", 1, prim_import);
|
||||||
addPrimOp("isNull", 1, prim_isNull);
|
addPrimOp("isNull", 1, prim_isNull);
|
||||||
@@ -1088,11 +1229,15 @@ void EvalState::createBaseEnv()
|
|||||||
|
|
||||||
// Lists
|
// Lists
|
||||||
addPrimOp("__isList", 1, prim_isList);
|
addPrimOp("__isList", 1, prim_isList);
|
||||||
|
addPrimOp("__elemAt", 2, prim_elemAt);
|
||||||
addPrimOp("__head", 1, prim_head);
|
addPrimOp("__head", 1, prim_head);
|
||||||
addPrimOp("__tail", 1, prim_tail);
|
addPrimOp("__tail", 1, prim_tail);
|
||||||
addPrimOp("map", 2, prim_map);
|
addPrimOp("map", 2, prim_map);
|
||||||
|
addPrimOp("__filter", 2, prim_filter);
|
||||||
|
addPrimOp("__elem", 2, prim_elem);
|
||||||
|
addPrimOp("__concatLists", 1, prim_concatLists);
|
||||||
addPrimOp("__length", 1, prim_length);
|
addPrimOp("__length", 1, prim_length);
|
||||||
|
|
||||||
// Integer arithmetic
|
// Integer arithmetic
|
||||||
addPrimOp("__add", 2, prim_add);
|
addPrimOp("__add", 2, prim_add);
|
||||||
addPrimOp("__sub", 2, prim_sub);
|
addPrimOp("__sub", 2, prim_sub);
|
||||||
@@ -1106,6 +1251,7 @@ void EvalState::createBaseEnv()
|
|||||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||||
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||||
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||||
|
addPrimOp("__hashString", 2, prim_hashString);
|
||||||
|
|
||||||
// Versions
|
// Versions
|
||||||
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
|
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
|
||||||
@@ -1116,7 +1262,7 @@ void EvalState::createBaseEnv()
|
|||||||
|
|
||||||
/* Add a wrapper around the derivation primop that computes the
|
/* Add a wrapper around the derivation primop that computes the
|
||||||
`drvPath' and `outPath' attributes lazily. */
|
`drvPath' and `outPath' attributes lazily. */
|
||||||
mkThunk_(v, parseExprFromFile(findFile("nix/derivation.nix")));
|
evalFile(findFile("nix/derivation.nix"), v);
|
||||||
addConstant("derivation", v);
|
addConstant("derivation", v);
|
||||||
|
|
||||||
/* Now that we've added all primops, sort the `builtins' attribute
|
/* Now that we've added all primops, sort the `builtins' attribute
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __SYMBOL_TABLE_H
|
#pragma once
|
||||||
#define __SYMBOL_TABLE_H
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -29,17 +28,17 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Symbol() : s(0) { };
|
Symbol() : s(0) { };
|
||||||
|
|
||||||
bool operator == (const Symbol & s2) const
|
bool operator == (const Symbol & s2) const
|
||||||
{
|
{
|
||||||
return s == s2.s;
|
return s == s2.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const Symbol & s2) const
|
bool operator != (const Symbol & s2) const
|
||||||
{
|
{
|
||||||
return s != s2.s;
|
return s != s2.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator < (const Symbol & s2) const
|
bool operator < (const Symbol & s2) const
|
||||||
{
|
{
|
||||||
return s < s2.s;
|
return s < s2.s;
|
||||||
@@ -50,6 +49,11 @@ public:
|
|||||||
return *s;
|
return *s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool set() const
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return s->empty();
|
return s->empty();
|
||||||
@@ -67,7 +71,7 @@ inline std::ostream & operator << (std::ostream & str, const Symbol & sym)
|
|||||||
class SymbolTable
|
class SymbolTable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#if HAVE_TR1_UNORDERED_SET
|
#if HAVE_TR1_UNORDERED_SET
|
||||||
typedef std::tr1::unordered_set<string> Symbols;
|
typedef std::tr1::unordered_set<string> Symbols;
|
||||||
#else
|
#else
|
||||||
typedef std::set<string> Symbols;
|
typedef std::set<string> Symbols;
|
||||||
@@ -88,5 +92,3 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__SYMBOL_TABLE_H */
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __VALUE_TO_XML_H
|
#pragma once
|
||||||
#define __VALUE_TO_XML_H
|
|
||||||
|
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
@@ -13,5 +12,3 @@ void printValueAsXML(EvalState & state, bool strict, bool location,
|
|||||||
Value & v, std::ostream & out, PathSet & context);
|
Value & v, std::ostream & out, PathSet & context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__VALUE_TO_XML_H */
|
|
||||||
|
|||||||
+13
-13
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __VALUE_H
|
#pragma once
|
||||||
#define __VALUE_H
|
|
||||||
|
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
|
|
||||||
@@ -32,17 +31,20 @@ struct PrimOp;
|
|||||||
struct Symbol;
|
struct Symbol;
|
||||||
|
|
||||||
|
|
||||||
|
typedef long NixInt;
|
||||||
|
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
{
|
{
|
||||||
ValueType type;
|
ValueType type;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int integer;
|
NixInt integer;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
|
|
||||||
/* Strings in the evaluator carry a so-called `context' (the
|
/* Strings in the evaluator carry a so-called `context' which
|
||||||
ATermList) which is a list of strings representing store
|
is a list of strings representing store paths. This is to
|
||||||
paths. This is to allow users to write things like
|
allow users to write things like
|
||||||
|
|
||||||
"--with-freetype2-library=" + freetype + "/lib"
|
"--with-freetype2-library=" + freetype + "/lib"
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ struct Value
|
|||||||
const char * s;
|
const char * s;
|
||||||
const char * * context; // must be in sorted order
|
const char * * context; // must be in sorted order
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
const char * path;
|
const char * path;
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
@@ -98,7 +100,7 @@ static inline void clearValue(Value & v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void mkInt(Value & v, int n)
|
static inline void mkInt(Value & v, NixInt n)
|
||||||
{
|
{
|
||||||
clearValue(v);
|
clearValue(v);
|
||||||
v.type = tInt;
|
v.type = tInt;
|
||||||
@@ -132,7 +134,7 @@ static inline void mkStringNoCopy(Value & v, const char * s)
|
|||||||
|
|
||||||
static inline void mkString(Value & v, const Symbol & s)
|
static inline void mkString(Value & v, const Symbol & s)
|
||||||
{
|
{
|
||||||
mkStringNoCopy(v, ((string) s).c_str());
|
mkStringNoCopy(v, ((const string &) s).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,5 +153,3 @@ void mkPath(Value & v, const char * s);
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__VALUE_H */
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
pkglib_LTLIBRARIES = libmain.la
|
pkglib_LTLIBRARIES = libmain.la
|
||||||
|
|
||||||
libmain_la_SOURCES = shared.cc
|
libmain_la_SOURCES = shared.cc stack.cc
|
||||||
|
|
||||||
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
|
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
|
||||||
|
|
||||||
pkginclude_HEADERS = shared.hh
|
pkginclude_HEADERS = shared.hh
|
||||||
|
|
||||||
AM_CXXFLAGS = \
|
AM_CXXFLAGS = \
|
||||||
-DNIX_VERSION=\"$(VERSION)\" \
|
|
||||||
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
||||||
-I$(srcdir)/../libstore
|
-I$(srcdir)/../libstore
|
||||||
|
|||||||
+64
-95
@@ -10,8 +10,10 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
#include <gc/gc.h>
|
#include <gc/gc.h>
|
||||||
@@ -33,20 +35,10 @@ static void sigintHandler(int signo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path makeRootName(const Path & gcRoot, int & counter)
|
|
||||||
{
|
|
||||||
counter++;
|
|
||||||
if (counter == 1)
|
|
||||||
return gcRoot;
|
|
||||||
else
|
|
||||||
return (format("%1%-%2%") % gcRoot % counter).str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void printGCWarning()
|
void printGCWarning()
|
||||||
{
|
{
|
||||||
static bool haveWarned = false;
|
static bool haveWarned = false;
|
||||||
warnOnce(haveWarned,
|
warnOnce(haveWarned,
|
||||||
"you did not specify `--add-root'; "
|
"you did not specify `--add-root'; "
|
||||||
"the result might be removed by the garbage collector");
|
"the result might be removed by the garbage collector");
|
||||||
}
|
}
|
||||||
@@ -57,7 +49,14 @@ void printMissing(StoreAPI & store, const PathSet & paths)
|
|||||||
unsigned long long downloadSize, narSize;
|
unsigned long long downloadSize, narSize;
|
||||||
PathSet willBuild, willSubstitute, unknown;
|
PathSet willBuild, willSubstitute, unknown;
|
||||||
queryMissing(store, paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
queryMissing(store, paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
printMissing(willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void printMissing(const PathSet & willBuild,
|
||||||
|
const PathSet & willSubstitute, const PathSet & unknown,
|
||||||
|
unsigned long long downloadSize, unsigned long long narSize)
|
||||||
|
{
|
||||||
if (!willBuild.empty()) {
|
if (!willBuild.empty()) {
|
||||||
printMsg(lvlInfo, format("these derivations will be built:"));
|
printMsg(lvlInfo, format("these derivations will be built:"));
|
||||||
foreach (PathSet::iterator, i, willBuild)
|
foreach (PathSet::iterator, i, willBuild)
|
||||||
@@ -74,7 +73,7 @@ void printMissing(StoreAPI & store, const PathSet & paths)
|
|||||||
|
|
||||||
if (!unknown.empty()) {
|
if (!unknown.empty()) {
|
||||||
printMsg(lvlInfo, format("don't know how to build these paths%1%:")
|
printMsg(lvlInfo, format("don't know how to build these paths%1%:")
|
||||||
% (readOnlyMode ? " (may be caused by read-only store access)" : ""));
|
% (settings.readOnlyMode ? " (may be caused by read-only store access)" : ""));
|
||||||
foreach (PathSet::iterator, i, unknown)
|
foreach (PathSet::iterator, i, unknown)
|
||||||
printMsg(lvlInfo, format(" %1%") % *i);
|
printMsg(lvlInfo, format(" %1%") % *i);
|
||||||
}
|
}
|
||||||
@@ -93,12 +92,25 @@ static void setLogType(string lt)
|
|||||||
static bool showTrace = false;
|
static bool showTrace = false;
|
||||||
|
|
||||||
|
|
||||||
|
string getArg(const string & opt,
|
||||||
|
Strings::iterator & i, const Strings::iterator & end)
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
|
||||||
|
return *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void detectStackOverflow();
|
||||||
|
|
||||||
|
|
||||||
/* Initialize and reorder arguments, then call the actual argument
|
/* Initialize and reorder arguments, then call the actual argument
|
||||||
processor. */
|
processor. */
|
||||||
static void initAndRun(int argc, char * * argv)
|
static void initAndRun(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
setDefaultsFromEnvironment();
|
settings.processEnvironment();
|
||||||
|
settings.loadConfFile();
|
||||||
|
|
||||||
/* Catch SIGINT. */
|
/* Catch SIGINT. */
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
act.sa_handler = sigintHandler;
|
act.sa_handler = sigintHandler;
|
||||||
@@ -123,12 +135,19 @@ static void initAndRun(int argc, char * * argv)
|
|||||||
if (sigaction(SIGCHLD, &act, 0))
|
if (sigaction(SIGCHLD, &act, 0))
|
||||||
throw SysError("resetting SIGCHLD");
|
throw SysError("resetting SIGCHLD");
|
||||||
|
|
||||||
|
/* Register a SIGSEGV handler to detect stack overflows. */
|
||||||
|
detectStackOverflow();
|
||||||
|
|
||||||
/* There is no privacy in the Nix system ;-) At least not for
|
/* There is no privacy in the Nix system ;-) At least not for
|
||||||
now. In particular, store objects should be readable by
|
now. In particular, store objects should be readable by
|
||||||
everybody. This prevents nasty surprises when using a shared
|
everybody. */
|
||||||
store (with the setuid() hack). */
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
|
/* Initialise the PRNG. */
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
srandom(tv.tv_usec);
|
||||||
|
|
||||||
/* Process the NIX_LOG_TYPE environment variable. */
|
/* Process the NIX_LOG_TYPE environment variable. */
|
||||||
string lt = getEnv("NIX_LOG_TYPE");
|
string lt = getEnv("NIX_LOG_TYPE");
|
||||||
if (lt != "") setLogType(lt);
|
if (lt != "") setLogType(lt);
|
||||||
@@ -137,7 +156,7 @@ static void initAndRun(int argc, char * * argv)
|
|||||||
Strings args, remaining;
|
Strings args, remaining;
|
||||||
while (argc--) args.push_back(*argv++);
|
while (argc--) args.push_back(*argv++);
|
||||||
args.erase(args.begin());
|
args.erase(args.begin());
|
||||||
|
|
||||||
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
|
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
|
||||||
ignore options for the ATerm library. */
|
ignore options for the ATerm library. */
|
||||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||||
@@ -156,46 +175,44 @@ static void initAndRun(int argc, char * * argv)
|
|||||||
remaining.clear();
|
remaining.clear();
|
||||||
|
|
||||||
/* Process default options. */
|
/* Process default options. */
|
||||||
int verbosityDelta = 0;
|
|
||||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||||
string arg = *i;
|
string arg = *i;
|
||||||
if (arg == "--verbose" || arg == "-v") verbosityDelta++;
|
if (arg == "--verbose" || arg == "-v") verbosity = (Verbosity) (verbosity + 1);
|
||||||
else if (arg == "--quiet") verbosityDelta--;
|
else if (arg == "--quiet") verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError;
|
||||||
else if (arg == "--log-type") {
|
else if (arg == "--log-type") {
|
||||||
++i;
|
string s = getArg(arg, i, args.end());
|
||||||
if (i == args.end()) throw UsageError("`--log-type' requires an argument");
|
setLogType(s);
|
||||||
setLogType(*i);
|
|
||||||
}
|
}
|
||||||
else if (arg == "--no-build-output" || arg == "-Q")
|
else if (arg == "--no-build-output" || arg == "-Q")
|
||||||
buildVerbosity = lvlVomit;
|
settings.buildVerbosity = lvlVomit;
|
||||||
else if (arg == "--print-build-trace")
|
else if (arg == "--print-build-trace")
|
||||||
printBuildTrace = true;
|
settings.printBuildTrace = true;
|
||||||
else if (arg == "--help") {
|
else if (arg == "--help") {
|
||||||
printHelp();
|
printHelp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (arg == "--version") {
|
else if (arg == "--version") {
|
||||||
std::cout << format("%1% (Nix) %2%") % programId % NIX_VERSION << std::endl;
|
std::cout << format("%1% (Nix) %2%") % programId % nixVersion << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (arg == "--keep-failed" || arg == "-K")
|
else if (arg == "--keep-failed" || arg == "-K")
|
||||||
keepFailed = true;
|
settings.keepFailed = true;
|
||||||
else if (arg == "--keep-going" || arg == "-k")
|
else if (arg == "--keep-going" || arg == "-k")
|
||||||
keepGoing = true;
|
settings.keepGoing = true;
|
||||||
else if (arg == "--fallback")
|
else if (arg == "--fallback")
|
||||||
tryFallback = true;
|
settings.set("build-fallback", "true");
|
||||||
else if (arg == "--max-jobs" || arg == "-j")
|
else if (arg == "--max-jobs" || arg == "-j")
|
||||||
maxBuildJobs = getIntArg<unsigned int>(arg, i, args.end());
|
settings.set("build-max-jobs", getArg(arg, i, args.end()));
|
||||||
else if (arg == "--cores")
|
else if (arg == "--cores")
|
||||||
buildCores = getIntArg<unsigned int>(arg, i, args.end());
|
settings.set("build-cores", getArg(arg, i, args.end()));
|
||||||
else if (arg == "--readonly-mode")
|
else if (arg == "--readonly-mode")
|
||||||
readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
else if (arg == "--max-silent-time")
|
else if (arg == "--max-silent-time")
|
||||||
maxSilentTime = getIntArg<unsigned int>(arg, i, args.end());
|
settings.set("build-max-silent-time", getArg(arg, i, args.end()));
|
||||||
else if (arg == "--timeout")
|
else if (arg == "--timeout")
|
||||||
buildTimeout = getIntArg<unsigned int>(arg, i, args.end());
|
settings.set("build-timeout", getArg(arg, i, args.end()));
|
||||||
else if (arg == "--no-build-hook")
|
else if (arg == "--no-build-hook")
|
||||||
useBuildHook = false;
|
settings.useBuildHook = false;
|
||||||
else if (arg == "--show-trace")
|
else if (arg == "--show-trace")
|
||||||
showTrace = true;
|
showTrace = true;
|
||||||
else if (arg == "--option") {
|
else if (arg == "--option") {
|
||||||
@@ -203,14 +220,13 @@ static void initAndRun(int argc, char * * argv)
|
|||||||
string name = *i;
|
string name = *i;
|
||||||
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
||||||
string value = *i;
|
string value = *i;
|
||||||
overrideSetting(name, tokenizeString(value));
|
settings.set(name, value);
|
||||||
}
|
}
|
||||||
else remaining.push_back(arg);
|
else remaining.push_back(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosityDelta += queryIntSetting("verbosity", lvlInfo);
|
settings.update();
|
||||||
verbosity = (Verbosity) (verbosityDelta < 0 ? 0 : verbosityDelta);
|
|
||||||
|
|
||||||
run(remaining);
|
run(remaining);
|
||||||
|
|
||||||
/* Close the Nix database. */
|
/* Close the Nix database. */
|
||||||
@@ -218,56 +234,6 @@ static void initAndRun(int argc, char * * argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool setuidMode = false;
|
|
||||||
|
|
||||||
|
|
||||||
static void setuidInit()
|
|
||||||
{
|
|
||||||
/* Don't do anything if this is not a setuid binary. */
|
|
||||||
if (getuid() == geteuid() && getgid() == getegid()) return;
|
|
||||||
|
|
||||||
uid_t nixUid = geteuid();
|
|
||||||
gid_t nixGid = getegid();
|
|
||||||
|
|
||||||
setuidCleanup();
|
|
||||||
|
|
||||||
/* Don't trust the current directory. */
|
|
||||||
if (chdir("/") == -1) abort();
|
|
||||||
|
|
||||||
/* Set the real (and preferably also the save) uid/gid to the
|
|
||||||
effective uid/gid. This matters mostly when we're not using
|
|
||||||
build-users (bad!), since some builders (like Perl) complain
|
|
||||||
when real != effective.
|
|
||||||
|
|
||||||
On systems where setresuid is unavailable, we can't drop the
|
|
||||||
saved uid/gid. This means that we could go back to the
|
|
||||||
original real uid (i.e., the uid of the caller). That's not
|
|
||||||
really a problem, except maybe when we execute a builder and
|
|
||||||
we're not using build-users. In that case, the builder may be
|
|
||||||
able to switch to the uid of the caller and possibly do bad
|
|
||||||
stuff. But note that when not using build-users, the builder
|
|
||||||
could also modify the Nix executables (say, replace them by a
|
|
||||||
Trojan horse), so the problem is already there. */
|
|
||||||
|
|
||||||
#if HAVE_SETRESUID
|
|
||||||
if (setresuid(nixUid, nixUid, nixUid)) abort();
|
|
||||||
if (setresgid(nixGid, nixGid, nixGid)) abort();
|
|
||||||
#elif HAVE_SETREUID
|
|
||||||
/* Note: doesn't set saved uid/gid! */
|
|
||||||
fprintf(stderr, "warning: cannot set saved uid\n");
|
|
||||||
if (setreuid(nixUid, nixUid)) abort();
|
|
||||||
if (setregid(nixGid, nixGid)) abort();
|
|
||||||
#else
|
|
||||||
/* Note: doesn't set real and saved uid/gid! */
|
|
||||||
fprintf(stderr, "warning: cannot set real and saved uids\n");
|
|
||||||
if (setuid(nixUid)) abort();
|
|
||||||
if (setgid(nixGid)) abort();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setuidMode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Called when the Boehm GC runs out of memory. */
|
/* Called when the Boehm GC runs out of memory. */
|
||||||
static void * oomHandler(size_t requested)
|
static void * oomHandler(size_t requested)
|
||||||
{
|
{
|
||||||
@@ -276,6 +242,14 @@ static void * oomHandler(size_t requested)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void showManPage(const string & name)
|
||||||
|
{
|
||||||
|
string cmd = "man " + name;
|
||||||
|
if (system(cmd.c_str()) != 0)
|
||||||
|
throw Error(format("command `%1%' failed") % cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int exitCode = 0;
|
int exitCode = 0;
|
||||||
char * * argvSaved = 0;
|
char * * argvSaved = 0;
|
||||||
|
|
||||||
@@ -290,11 +264,6 @@ int main(int argc, char * * argv)
|
|||||||
|
|
||||||
argvSaved = argv;
|
argvSaved = argv;
|
||||||
|
|
||||||
/* If we're setuid, then we need to take some security precautions
|
|
||||||
right away. */
|
|
||||||
if (argc == 0) abort();
|
|
||||||
setuidInit();
|
|
||||||
|
|
||||||
/* Turn on buffering for cerr. */
|
/* Turn on buffering for cerr. */
|
||||||
#if HAVE_PUBSETBUF
|
#if HAVE_PUBSETBUF
|
||||||
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
|
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
|
||||||
@@ -323,7 +292,7 @@ int main(int argc, char * * argv)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
} catch (UsageError & e) {
|
} catch (UsageError & e) {
|
||||||
printMsg(lvlError,
|
printMsg(lvlError,
|
||||||
format(
|
format(
|
||||||
"error: %1%\n"
|
"error: %1%\n"
|
||||||
"Try `%2% --help' for more information.")
|
"Try `%2% --help' for more information.")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __SHARED_H
|
#pragma once
|
||||||
#define __SHARED_H
|
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
@@ -27,11 +26,14 @@ MakeError(UsageError, nix::Error);
|
|||||||
class StoreAPI;
|
class StoreAPI;
|
||||||
|
|
||||||
/* Ugh. No better place to put this. */
|
/* Ugh. No better place to put this. */
|
||||||
Path makeRootName(const Path & gcRoot, int & counter);
|
|
||||||
void printGCWarning();
|
void printGCWarning();
|
||||||
|
|
||||||
void printMissing(StoreAPI & store, const PathSet & paths);
|
void printMissing(StoreAPI & store, const PathSet & paths);
|
||||||
|
|
||||||
|
void printMissing(const PathSet & willBuild,
|
||||||
|
const PathSet & willSubstitute, const PathSet & unknown,
|
||||||
|
unsigned long long downloadSize, unsigned long long narSize);
|
||||||
|
|
||||||
template<class N> N getIntArg(const string & opt,
|
template<class N> N getIntArg(const string & opt,
|
||||||
Strings::iterator & i, const Strings::iterator & end)
|
Strings::iterator & i, const Strings::iterator & end)
|
||||||
{
|
{
|
||||||
@@ -43,8 +45,8 @@ template<class N> N getIntArg(const string & opt,
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whether we're running setuid. */
|
/* Show the manual page for the specified program. */
|
||||||
extern bool setuidMode;
|
void showManPage(const string & name);
|
||||||
|
|
||||||
extern volatile ::sig_atomic_t blockInt;
|
extern volatile ::sig_atomic_t blockInt;
|
||||||
|
|
||||||
@@ -54,6 +56,3 @@ extern int exitCode;
|
|||||||
extern char * * argvSaved;
|
extern char * * argvSaved;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__SHARED_H */
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "types.hh"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
|
||||||
|
{
|
||||||
|
/* Detect stack overflows by comparing the faulting address with
|
||||||
|
the stack pointer. Unfortunately, getting the stack pointer is
|
||||||
|
not portable. */
|
||||||
|
bool haveSP = true;
|
||||||
|
char * sp;
|
||||||
|
#if defined(__x86_64__) && defined(REG_RSP)
|
||||||
|
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_RSP];
|
||||||
|
#elif defined(REG_ESP)
|
||||||
|
sp = (char *) ((ucontext *) ctx)->uc_mcontext.gregs[REG_ESP];
|
||||||
|
#else
|
||||||
|
haveSP = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (haveSP) {
|
||||||
|
ptrdiff_t diff = (char *) info->si_addr - sp;
|
||||||
|
if (diff < 0) diff = -diff;
|
||||||
|
if (diff < 4096) {
|
||||||
|
char msg[] = "error: stack overflow (possible infinite recursion)\n";
|
||||||
|
write(2, msg, strlen(msg));
|
||||||
|
_exit(1); // maybe abort instead?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore default behaviour (i.e. segfault and dump core). */
|
||||||
|
struct sigaction act;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_handler = SIG_DFL;
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGSEGV, &act, 0)) abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void detectStackOverflow()
|
||||||
|
{
|
||||||
|
#if defined(SA_SIGINFO) && defined (SA_ONSTACK)
|
||||||
|
/* Install a SIGSEGV handler to detect stack overflows. This
|
||||||
|
requires an alternative stack, otherwise the signal cannot be
|
||||||
|
delivered when we're out of stack space. */
|
||||||
|
stack_t stack;
|
||||||
|
stack.ss_size = 4096 * 4 + MINSIGSTKSZ;
|
||||||
|
stack.ss_sp = new char[stack.ss_size];
|
||||||
|
if (!stack.ss_sp) throw Error("cannot allocate alternative stack");
|
||||||
|
stack.ss_flags = 0;
|
||||||
|
if (sigaltstack(&stack, 0) == -1) throw SysError("cannot set alternative stack");
|
||||||
|
|
||||||
|
struct sigaction act;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_sigaction = sigsegvHandler;
|
||||||
|
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
|
if (sigaction(SIGSEGV, &act, 0))
|
||||||
|
throw SysError("resetting SIGCHLD");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ pkginclude_HEADERS = \
|
|||||||
globals.hh references.hh pathlocks.hh \
|
globals.hh references.hh pathlocks.hh \
|
||||||
worker-protocol.hh
|
worker-protocol.hh
|
||||||
|
|
||||||
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @SQLITE3_LIBS@
|
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @SQLITE3_LIBS@ -lbz2
|
||||||
|
|
||||||
EXTRA_DIST = schema.sql
|
EXTRA_DIST = schema.sql
|
||||||
|
|
||||||
@@ -23,10 +23,11 @@ AM_CXXFLAGS = -Wall \
|
|||||||
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
|
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
|
||||||
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
|
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
|
||||||
-DNIX_BIN_DIR=\"$(bindir)\" \
|
-DNIX_BIN_DIR=\"$(bindir)\" \
|
||||||
|
-DNIX_VERSION=\"$(VERSION)\" \
|
||||||
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
||||||
-I$(srcdir)/../libstore
|
-I$(srcdir)/../libstore
|
||||||
|
|
||||||
local-store.lo: schema.sql.hh
|
local-store.lo: schema.sql.hh
|
||||||
|
|
||||||
%.sql.hh: %.sql
|
%.sql.hh: %.sql
|
||||||
../bin2c/bin2c schema < $< > $@ || (rm $@ && exit 1)
|
sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $< > $@ || (rm $@ && exit 1)
|
||||||
|
|||||||
+1069
-571
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user