Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d6418d46e | ||
|
|
dec2f19502 | ||
|
|
6123144933 | ||
|
|
1dacd427cd | ||
|
|
ea6bf0c21f | ||
|
|
36e67ff16b | ||
|
|
fba17a9043 | ||
|
|
2d9bb56e55 | ||
|
|
5bc41d78ff | ||
|
|
9e4bb20455 | ||
|
|
dc341811d6 | ||
|
|
69befd33a9 | ||
|
|
a5684e09d3 | ||
|
|
411a3461dc | ||
|
|
05d02f798f | ||
|
|
6da92d96ae | ||
|
|
543d8a5942 | ||
|
|
fe95650487 | ||
|
|
3139481822 | ||
|
|
c086183843 | ||
|
|
4f4a14453a | ||
|
|
4ea034a5c5 | ||
|
|
792fd51f41 | ||
|
|
f440558acc | ||
|
|
bb659bad81 | ||
|
|
f6a8e7f4c2 | ||
|
|
b08f4b0da9 | ||
|
|
d7625b5c2d | ||
|
|
b8034e5581 | ||
|
|
9d8a80375d | ||
|
|
d6a7aa8f48 | ||
|
|
b8571d68c4 | ||
|
|
a737f51fd9 | ||
|
|
ff02f5336c | ||
|
|
4bd5282573 | ||
|
|
bce14d0f61 | ||
|
|
7cdefdbe73 | ||
|
|
d05bf04444 | ||
|
|
c1994fecf9 | ||
|
|
672c3acc71 | ||
|
|
7bdb85453d | ||
|
|
9deb822180 | ||
|
|
b1e3b1a4ac | ||
|
|
6b47de580f | ||
|
|
a5e0f64db3 | ||
|
|
221a2daf34 | ||
|
|
176c666f36 | ||
|
|
c945f015de | ||
|
|
28e0742966 | ||
|
|
a5fb4b5b7c | ||
|
|
faaae44f2e | ||
|
|
f53574ebd6 | ||
|
|
d5529f5b85 | ||
|
|
b072fc04a7 | ||
|
|
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/manual.html
|
||||
/doc/manual/manual.xmli
|
||||
/doc/manual/manual.pdf
|
||||
/doc/manual/manual.is-valid
|
||||
/doc/manual/*.1
|
||||
/doc/manual/*.5
|
||||
/doc/manual/*.8
|
||||
/doc/manual/images
|
||||
/doc/manual/version.txt
|
||||
@@ -60,14 +63,12 @@ Makefile.in
|
||||
/scripts/GeneratePatches.pm
|
||||
/scripts/download-using-manifests.pl
|
||||
/scripts/copy-from-other-stores.pl
|
||||
/scripts/download-from-binary-cache.pl
|
||||
/scripts/find-runtime-roots.pl
|
||||
/scripts/build-remote.pl
|
||||
/scripts/nix-reduce-build
|
||||
/scripts/nix-http-export.cgi
|
||||
|
||||
# /src/bin2c/
|
||||
/src/bin2c/bin2c
|
||||
|
||||
# /src/bsdiff-4.3/
|
||||
/src/bsdiff-4.3/bsdiff
|
||||
/src/bsdiff-4.3/bspatch
|
||||
@@ -78,26 +79,19 @@ Makefile.in
|
||||
/src/libexpr/parser-tab.cc
|
||||
/src/libexpr/parser-tab.hh
|
||||
/src/libexpr/parser-tab.output
|
||||
/src/libexpr/nixexpr-ast.hh
|
||||
/src/libexpr/nixexpr-ast.cc
|
||||
/src/libexpr/nix.tbl
|
||||
|
||||
# /src/libstore/
|
||||
/src/libstore/derivations-ast.cc
|
||||
/src/libstore/derivations-ast.hh
|
||||
/src/libstore/schema.sql.hh
|
||||
|
||||
# /src/nix-env/
|
||||
/src/nix-env/nix-env
|
||||
/src/nix-env/help.txt.hh
|
||||
|
||||
# /src/nix-hash/
|
||||
/src/nix-hash/nix-hash
|
||||
/src/nix-hash/help.txt.hh
|
||||
|
||||
# /src/nix-instantiate/
|
||||
/src/nix-instantiate/nix-instantiate
|
||||
/src/nix-instantiate/help.txt.hh
|
||||
|
||||
# /src/nix-log2xml/
|
||||
/src/nix-log2xml/nix-log2xml
|
||||
@@ -108,15 +102,12 @@ Makefile.in
|
||||
|
||||
# /src/nix-setuid-helper/
|
||||
/src/nix-setuid-helper/nix-setuid-helper
|
||||
/src/nix-setuid-helper/help.txt.hh
|
||||
|
||||
# /src/nix-store/
|
||||
/src/nix-store/help.txt.hh
|
||||
/src/nix-store/nix-store
|
||||
|
||||
# /src/nix-worker/
|
||||
/src/nix-worker/nix-worker
|
||||
/src/nix-worker/help.txt.hh
|
||||
# /src/nix-daemon/
|
||||
/src/nix-daemon/nix-daemon
|
||||
|
||||
# /tests/
|
||||
/tests/test-tmp
|
||||
|
||||
+1
-7
@@ -1,6 +1,6 @@
|
||||
SUBDIRS = src perl scripts corepkgs doc misc tests
|
||||
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
|
||||
|
||||
@@ -10,10 +10,6 @@ nix.spec: nix.spec.in
|
||||
|
||||
install-data-local: init-state
|
||||
$(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_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/gcroots
|
||||
$(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)$(storedir)
|
||||
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
|
||||
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
|
||||
|
||||
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
|
||||
linux-gnu*)
|
||||
# For backward compatibility, strip the `-gnu' part.
|
||||
system="$machine_name-linux";;
|
||||
# For backward compatibility, strip the `-gnu' part.
|
||||
system="$machine_name-linux";;
|
||||
*)
|
||||
# Strip the version number from names such as `gnu0.3',
|
||||
# `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])
|
||||
|
||||
sys_name=$(uname -s | tr 'A-Z ' 'a-z_')
|
||||
@@ -40,7 +40,7 @@ case $sys_name in
|
||||
sys_name=cygwin
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
AC_MSG_RESULT($system)
|
||||
AC_SUBST(system)
|
||||
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
|
||||
@@ -68,6 +68,8 @@ if test "$sys_name" = sunos; then
|
||||
fi
|
||||
|
||||
|
||||
CFLAGS=${CFLAGS:--g -O3 -Wall}
|
||||
CXXFLAGS=${CXXFLAGS:--g -O3 -Wall}
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
@@ -106,6 +108,7 @@ AC_LANG_POP(C++)
|
||||
# Check for chroot support (requires chroot() and bind mounts).
|
||||
AC_CHECK_FUNCS([chroot])
|
||||
AC_CHECK_FUNCS([unshare])
|
||||
AC_CHECK_FUNCS([statvfs])
|
||||
AC_CHECK_HEADERS([sched.h])
|
||||
AC_CHECK_HEADERS([sys/param.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>.
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_CHECK_HEADERS([locale])
|
||||
@@ -161,9 +189,10 @@ NEED_PROG(perl, perl)
|
||||
NEED_PROG(sed, sed)
|
||||
NEED_PROG(tar, tar)
|
||||
NEED_PROG(bzip2, bzip2)
|
||||
NEED_PROG(gzip, gzip)
|
||||
NEED_PROG(xz, xz)
|
||||
AC_PATH_PROG(dot, dot)
|
||||
AC_PATH_PROG(dblatex, dblatex)
|
||||
AC_PATH_PROG(gzip, gzip)
|
||||
AC_PATH_PROG(pv, pv, pv)
|
||||
|
||||
|
||||
@@ -249,7 +278,7 @@ if test "$gc" = yes; then
|
||||
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"
|
||||
|
||||
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]),
|
||||
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])
|
||||
if ! $perl $perlFlags -e 'use DBI; use DBD::SQLite;' 2>&5; then
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_FAILURE([The Perl modules DBI and/or DBD::SQLite are missing.])
|
||||
fi
|
||||
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)
|
||||
|
||||
|
||||
@@ -310,10 +350,20 @@ eval dynlib_suffix=$shrext_cmds
|
||||
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])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
src/bin2c/Makefile
|
||||
src/boost/Makefile
|
||||
src/boost/format/Makefile
|
||||
src/libutil/Makefile
|
||||
@@ -324,7 +374,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/libexpr/Makefile
|
||||
src/nix-instantiate/Makefile
|
||||
src/nix-env/Makefile
|
||||
src/nix-worker/Makefile
|
||||
src/nix-daemon/Makefile
|
||||
src/nix-setuid-helper/Makefile
|
||||
src/nix-log2xml/Makefile
|
||||
src/bsdiff-4.3/Makefile
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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) -d $(DESTDIR)$(datadir)/nix/corepkgs
|
||||
|
||||
@@ -2,18 +2,22 @@ with import <nix/config.nix>;
|
||||
|
||||
{ derivations, manifest }:
|
||||
|
||||
derivation {
|
||||
derivation {
|
||||
name = "user-environment";
|
||||
system = builtins.currentSystem;
|
||||
builder = perl;
|
||||
args = [ "-w" ./buildenv.pl ];
|
||||
|
||||
|
||||
manifest = manifest;
|
||||
|
||||
# !!! grmbl, need structured data for passing this in a clean way.
|
||||
paths = derivations;
|
||||
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
|
||||
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
|
||||
derivations =
|
||||
map (d:
|
||||
[ (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
|
||||
# network traffic, so don't do that.
|
||||
|
||||
+26
-27
@@ -36,19 +36,16 @@ sub createLinks {
|
||||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
||||
$srcFile =~ /\/nix-support$/ ||
|
||||
$srcFile =~ /\/perllocal.pod$/ ||
|
||||
$srcFile =~ /\/easy-install.pth$/ ||
|
||||
$srcFile =~ /\/site.py$/ ||
|
||||
$srcFile =~ /\/site.pyc$/ ||
|
||||
$srcFile =~ /\/info\/dir$/ ||
|
||||
$srcFile =~ /\/log$/)
|
||||
{
|
||||
# Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
elsif (-d $srcFile) {
|
||||
|
||||
lstat $dstFile;
|
||||
|
||||
|
||||
if (-d _) {
|
||||
createLinks($srcFile, $dstFile, $priority);
|
||||
}
|
||||
@@ -56,10 +53,10 @@ sub createLinks {
|
||||
elsif (-l _) {
|
||||
my $target = readlink $dstFile or die;
|
||||
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': $!";
|
||||
mkdir $dstFile, 0755 ||
|
||||
mkdir $dstFile, 0755 ||
|
||||
die "error creating directory `$dstFile': $!";
|
||||
createLinks($target, $dstFile, $priorities{$dstFile});
|
||||
createLinks($srcFile, $dstFile, $priority);
|
||||
@@ -78,15 +75,15 @@ sub createLinks {
|
||||
if (-l $dstFile) {
|
||||
my $target = readlink $dstFile;
|
||||
my $prevPriority = $priorities{$dstFile};
|
||||
die ( "Collission between `$srcFile' and `$target'. "
|
||||
. "Suggested solution: use `nix-env --set-flag "
|
||||
die ( "collision between `$srcFile' and `$target'; "
|
||||
. "use `nix-env --set-flag "
|
||||
. "priority NUMBER PKGNAME' to change the priority of "
|
||||
. "one of the conflicting packages.\n" )
|
||||
. "one of the conflicting packages\n" )
|
||||
if $prevPriority == $priority;
|
||||
next if $prevPriority < $priority;
|
||||
unlink $dstFile or die;
|
||||
}
|
||||
|
||||
|
||||
symlink($srcFile, $dstFile) ||
|
||||
die "error creating link `$dstFile': $!";
|
||||
$priorities{$dstFile} = $priority;
|
||||
@@ -125,27 +122,29 @@ sub addPkg {
|
||||
|
||||
# Convert the stuff we get from the environment back into a coherent
|
||||
# data type.
|
||||
my @paths = split ' ', $ENV{"paths"};
|
||||
my @active = split ' ', $ENV{"active"};
|
||||
my @priority = split ' ', $ENV{"priority"};
|
||||
|
||||
die if scalar @paths != scalar @active;
|
||||
die if scalar @paths != scalar @priority;
|
||||
|
||||
my %pkgs;
|
||||
|
||||
for (my $n = 0; $n < scalar @paths; $n++) {
|
||||
$pkgs{$paths[$n]} =
|
||||
{ active => $active[$n]
|
||||
, priority => $priority[$n] };
|
||||
my @pkgs;
|
||||
my @derivations = split ' ', $ENV{"derivations"};
|
||||
while (scalar @derivations) {
|
||||
my $active = shift @derivations;
|
||||
my $priority = shift @derivations;
|
||||
my $outputs = shift @derivations;
|
||||
for (my $n = 0; $n < $outputs; $n++) {
|
||||
my $path = shift @derivations;
|
||||
push @pkgs,
|
||||
{ path => $path
|
||||
, active => $active ne "false"
|
||||
, priority => int($priority) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Symlink to the packages that have been installed explicitly by the
|
||||
# user.
|
||||
foreach my $pkg (sort (keys %pkgs)) {
|
||||
# user. Process in priority order to reduce unnecessary
|
||||
# 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";
|
||||
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@";
|
||||
shell = "@shell@";
|
||||
coreutils = "@coreutils@";
|
||||
bzip2 = fromEnv "NIX_BZIP2" "@bzip2@";
|
||||
bzip2 = "@bzip2@";
|
||||
gzip = "@gzip@";
|
||||
xz = "@xz@";
|
||||
tar = "@tar@";
|
||||
tarFlags = "@tarFlags@";
|
||||
tr = "@tr@";
|
||||
curl = "@curl@";
|
||||
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ drvAttrs @ { outputs ? [ "out" ], ... }:
|
||||
let
|
||||
|
||||
strict = derivationStrict drvAttrs;
|
||||
|
||||
|
||||
commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) //
|
||||
{ all = map (x: x.value) outputsList;
|
||||
inherit drvAttrs;
|
||||
@@ -21,7 +21,7 @@ let
|
||||
inherit outputName;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
outputsList = map outputToAttrListElement outputs;
|
||||
|
||||
|
||||
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}
|
||||
|
||||
if [ $compressionType = xz ]; then
|
||||
ext=.xz
|
||||
compressor="| ${xz} -7"
|
||||
elif [ $compressionType = bzip2 ]; then
|
||||
ext=.bz2
|
||||
compressor="| ${bzip2}"
|
||||
else
|
||||
ext=
|
||||
compressor=
|
||||
fi
|
||||
|
||||
echo "packing ‘$storePath’..."
|
||||
mkdir $out
|
||||
dst=$out/tmp.nar.bz2
|
||||
dst=$out/tmp.nar$ext
|
||||
|
||||
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
|
||||
|
||||
{ storePath, hashAlgo }:
|
||||
{ storePath, hashAlgo, compressionType }:
|
||||
|
||||
derivation {
|
||||
name = "nar";
|
||||
system = builtins.currentSystem;
|
||||
builder = shell;
|
||||
args = [ "-e" builder ];
|
||||
inherit storePath hashAlgo;
|
||||
inherit storePath hashAlgo compressionType;
|
||||
|
||||
# Don't build in a chroot because Nix's dependencies may not be there.
|
||||
__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>;
|
||||
|
||||
{ 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 {
|
||||
system = builtins.currentSystem;
|
||||
builder = shell;
|
||||
args = [ "-e" ./unpack-channel.sh ];
|
||||
inherit name channelName src bzip2 tar tr;
|
||||
args = [ "-e" builder ];
|
||||
inherit name channelName src binaryCacheURL;
|
||||
|
||||
PATH = "${nixBinDir}:${coreutils}";
|
||||
|
||||
|
||||
# No point in doing this remotely.
|
||||
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
|
||||
# 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-prefetch-url.1 nix-channel.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
|
||||
|
||||
|
||||
+167
-98
@@ -12,14 +12,14 @@ such as <function>derivation</function>, are always in scope of every
|
||||
Nix expression; you can just access them right away. But to prevent
|
||||
polluting the namespace too much, most built-ins are not in scope.
|
||||
Instead, you can access them through the <varname>builtins</varname>
|
||||
built-in value, which is an attribute set that contains all built-in
|
||||
functions and values. For instance, <function>derivation</function>
|
||||
is also available as <function>builtins.derivation</function>.</para>
|
||||
built-in value, which is a set that contains all built-in functions
|
||||
and values. For instance, <function>derivation</function> is also
|
||||
available as <function>builtins.derivation</function>.</para>
|
||||
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Abort Nix expression evaluation, print error
|
||||
@@ -27,7 +27,7 @@ is also available as <function>builtins.derivation</function>.</para>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.add</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -37,25 +37,25 @@ is also available as <function>builtins.derivation</function>.</para>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.attrNames</function>
|
||||
<replaceable>attrs</replaceable></term>
|
||||
|
||||
<listitem><para>Return the names of the attributes in the
|
||||
attribute set <replaceable>attrs</replaceable> in a sorted list.
|
||||
For instance, <literal>builtins.attrNames { y = 1; x = "foo";
|
||||
}</literal> evaluates to <literal>[ "x" "y" ]</literal>. There is
|
||||
no built-in function <function>attrValues</function>, but you can
|
||||
easily define it yourself:
|
||||
<varlistentry><term><function>builtins.attrNames</function>
|
||||
<replaceable>set</replaceable></term>
|
||||
|
||||
<listitem><para>Return the names of the attributes in the set
|
||||
<replaceable>set</replaceable> in a sorted list. For instance,
|
||||
<literal>builtins.attrNames { y = 1; x = "foo"; }</literal>
|
||||
evaluates to <literal>[ "x" "y" ]</literal>. There is no built-in
|
||||
function <function>attrValues</function>, but you can easily
|
||||
define it yourself:
|
||||
|
||||
<programlisting>
|
||||
attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames attrs);</programlisting>
|
||||
attrValues = set: map (name: builtins.getAttr name set) (builtins.attrNames set);</programlisting>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Return the <emphasis>base name</emphasis> of the
|
||||
@@ -65,11 +65,11 @@ attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><varname>builtins</varname></term>
|
||||
|
||||
<listitem><para>The attribute set <varname>builtins</varname>
|
||||
contains all the built-in functions and values. You can use
|
||||
<listitem><para>The set <varname>builtins</varname> contains all
|
||||
the built-in functions and values. You can use
|
||||
<varname>builtins</varname> to test for the availability of
|
||||
features in the Nix installation, e.g.,
|
||||
|
||||
@@ -82,7 +82,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.compareVersions</function>
|
||||
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
|
||||
|
||||
@@ -99,7 +99,16 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
</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
|
||||
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><term><function>dependencyClosure</function></term>
|
||||
|
||||
@@ -133,7 +142,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
</varlistentry>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>derivation</function>
|
||||
<replaceable>attrs</replaceable></term>
|
||||
|
||||
@@ -152,7 +161,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.div</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -162,7 +171,40 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
</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>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -214,20 +256,20 @@ stdenv.mkDerivation {
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.getAttr</function>
|
||||
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
||||
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
|
||||
|
||||
<listitem><para><function>getAttr</function> returns the attribute
|
||||
named <replaceable>s</replaceable> from the attribute set
|
||||
<replaceable>attrs</replaceable>. Evaluation aborts if the
|
||||
named <replaceable>s</replaceable> from
|
||||
<replaceable>set</replaceable>. Evaluation aborts if the
|
||||
attribute doesn’t exist. This is a dynamic version of the
|
||||
<literal>.</literal> operator, since <replaceable>s</replaceable>
|
||||
is an expression rather than an identifier.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.getEnv</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
@@ -245,21 +287,33 @@ stdenv.mkDerivation {
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.hasAttr</function>
|
||||
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
|
||||
<replaceable>s</replaceable> <replaceable>set</replaceable></term>
|
||||
|
||||
<listitem><para><function>hasAttr</function> returns
|
||||
<literal>true</literal> if the attribute set
|
||||
<replaceable>attrs</replaceable> has an attribute named
|
||||
<replaceable>s</replaceable>, and <literal>false</literal>
|
||||
otherwise. This is a dynamic version of the <literal>?</literal>
|
||||
operator, since <replaceable>s</replaceable> is an expression
|
||||
rather than an identifier.</para></listitem>
|
||||
<literal>true</literal> if <replaceable>set</replaceable> has an
|
||||
attribute named <replaceable>s</replaceable>, and
|
||||
<literal>false</literal> otherwise. This is a dynamic version of
|
||||
the <literal>?</literal> operator, since
|
||||
<replaceable>s</replaceable> is an expression rather than an
|
||||
identifier.</para></listitem>
|
||||
|
||||
</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>
|
||||
<replaceable>list</replaceable></term>
|
||||
|
||||
@@ -270,17 +324,19 @@ stdenv.mkDerivation {
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>import</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
|
||||
<listitem><para>Load, parse and return the Nix expression in the
|
||||
file <replaceable>path</replaceable>. Evaluation aborts if the
|
||||
file doesn’t exist or contains an incorrect Nix
|
||||
expression. <function>import</function> implements Nix’s module
|
||||
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
|
||||
in other files.</para>
|
||||
file <replaceable>path</replaceable>. If <replaceable>path
|
||||
</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 system: you
|
||||
can put any Nix expression (such as a set or a function) in a
|
||||
separate file, and use it from Nix expressions in other
|
||||
files.</para>
|
||||
|
||||
<para>A Nix expression loaded by <function>import</function> must
|
||||
not contain any <emphasis>free variables</emphasis> (identifiers
|
||||
@@ -288,7 +344,7 @@ stdenv.mkDerivation {
|
||||
built-in). Therefore, it cannot refer to variables that are in
|
||||
scope at the call site. For instance, if you have a calling
|
||||
expression
|
||||
|
||||
|
||||
<programlisting>
|
||||
rec {
|
||||
x = 123;
|
||||
@@ -323,27 +379,27 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.intersectAttrs</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Return an attribute set consisting of the
|
||||
attributes in the set <replaceable>e2</replaceable> that also
|
||||
exist in the set <replaceable>e1</replaceable>.</para></listitem>
|
||||
<listitem><para>Return a set consisting of the attributes in the
|
||||
set <replaceable>e2</replaceable> that also exist in the set
|
||||
<replaceable>e1</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isAttrs</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to an attribute set, and
|
||||
<replaceable>e</replaceable> evaluates to a set, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isList</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -353,7 +409,7 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isFunction</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -363,7 +419,7 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isString</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -373,17 +429,17 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isInt</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<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>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isBool</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -393,7 +449,7 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>isNull</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -403,12 +459,12 @@ x: x + 456</programlisting>
|
||||
|
||||
<warning><para>This function is <emphasis>deprecated</emphasis>;
|
||||
just write <literal>e == null</literal> instead.</para></warning>
|
||||
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.length</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -417,7 +473,7 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.lessThan</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -430,13 +486,13 @@ x: x + 456</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.listToAttrs</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Construct an attribute set from a list specifying
|
||||
the names and values of each attribute. Each element of the list
|
||||
should be an attribute set consisting of a string-valued attribute
|
||||
<listitem><para>Construct a set from a list specifying the names
|
||||
and values of each attribute. Each element of the list should be
|
||||
a set consisting of a string-valued attribute
|
||||
<varname>name</varname> specifying the name of the attribute, and
|
||||
an attribute <varname>value</varname> specifying its value.
|
||||
Example:
|
||||
@@ -457,7 +513,7 @@ builtins.listToAttrs
|
||||
</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>map</function>
|
||||
<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"
|
||||
]</literal>.</para></listitem>
|
||||
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.mul</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -483,7 +539,7 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.parseDrvName</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
@@ -491,14 +547,14 @@ map (x: "foo" + x) [ "bar" "bla" "abc" ]</programlisting>
|
||||
a package name and version. The package name is everything up to
|
||||
but not including the first dash followed by a digit, and the
|
||||
version is everything following that dash. The result is returned
|
||||
in an attribute set <literal>{ name, version }</literal>. Thus,
|
||||
in a set <literal>{ name, version }</literal>. Thus,
|
||||
<literal>builtins.parseDrvName "nix-0.12pre12876"</literal>
|
||||
returns <literal>{ name = "nix"; version = "0.12pre12876";
|
||||
}</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.pathExists</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
|
||||
@@ -531,7 +587,7 @@ in config.someSetting</programlisting>
|
||||
</varlistentry>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.readFile</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
|
||||
@@ -539,15 +595,15 @@ in config.someSetting</programlisting>
|
||||
<replaceable>path</replaceable> as a string.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>removeAttrs</function>
|
||||
<replaceable>attrs</replaceable> <replaceable>list</replaceable></term>
|
||||
<replaceable>set</replaceable> <replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Remove the attributes listed in
|
||||
<replaceable>list</replaceable> from the attribute set
|
||||
<replaceable>attrs</replaceable>. The attributes don’t have to
|
||||
exist in <replaceable>attrs</replaceable>. For instance,
|
||||
<replaceable>list</replaceable> from
|
||||
<replaceable>set</replaceable>. The attributes don’t have to
|
||||
exist in <replaceable>set</replaceable>. For instance,
|
||||
|
||||
<screen>
|
||||
removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
@@ -556,7 +612,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.stringLength</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
@@ -566,7 +622,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.sub</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -576,7 +632,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.substring</function>
|
||||
<replaceable>start</replaceable> <replaceable>len</replaceable>
|
||||
<replaceable>s</replaceable></term>
|
||||
@@ -594,7 +650,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.tail</function>
|
||||
<replaceable>list</replaceable></term>
|
||||
|
||||
@@ -604,7 +660,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>throw</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
@@ -618,7 +674,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry
|
||||
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
|
||||
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
|
||||
@@ -636,7 +692,7 @@ removeAttrs { x = 1; y = 2; z = 3; } [ "a" "x" "z" ]</screen>
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "hello-2.1.1";
|
||||
|
||||
|
||||
builder = builtins.toFile "builder.sh" "
|
||||
source $stdenv/setup
|
||||
|
||||
@@ -655,7 +711,7 @@ stdenv.mkDerivation {
|
||||
};
|
||||
inherit perl;
|
||||
}</programlisting>
|
||||
|
||||
|
||||
</para>
|
||||
|
||||
<para>It is even possible for one file to refer to another, e.g.,
|
||||
@@ -693,7 +749,7 @@ in foo</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Convert the string value
|
||||
@@ -706,7 +762,7 @@ in foo</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Convert the expression
|
||||
@@ -718,7 +774,7 @@ in foo</programlisting>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return a string containing an XML representation
|
||||
@@ -736,7 +792,7 @@ in foo</programlisting>
|
||||
servlet container</link>. A servlet container contains a number
|
||||
of servlets (<filename>*.war</filename> files) each exported under
|
||||
a specific URI prefix. So the servlet configuration is a list of
|
||||
attribute sets containing the <varname>path</varname> and
|
||||
sets containing the <varname>path</varname> and
|
||||
<varname>war</varname> of the servlet (<xref
|
||||
linkend='ex-toxml-co-servlets' />). This kind of information is
|
||||
difficult to communicate with the normal method of passing
|
||||
@@ -763,7 +819,7 @@ in foo</programlisting>
|
||||
|
||||
<example xml:id='ex-toxml'><title>Passing information to a builder
|
||||
using <function>toXML</function></title>
|
||||
|
||||
|
||||
<programlisting><![CDATA[
|
||||
{ stdenv, fetchurl, libxslt, jira, uberwiki }:
|
||||
|
||||
@@ -771,7 +827,7 @@ stdenv.mkDerivation (rec {
|
||||
name = "web-server";
|
||||
|
||||
buildInputs = [ libxslt ];
|
||||
|
||||
|
||||
builder = builtins.toFile "builder.sh" "
|
||||
source $stdenv/setup
|
||||
mkdir $out
|
||||
@@ -804,7 +860,7 @@ stdenv.mkDerivation (rec {
|
||||
|
||||
<example xml:id='ex-toxml-result'><title>XML representation produced by
|
||||
<function>toXML</function></title>
|
||||
|
||||
|
||||
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
||||
<expr>
|
||||
<list>
|
||||
@@ -833,7 +889,7 @@ stdenv.mkDerivation (rec {
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.trace</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
@@ -844,7 +900,20 @@ stdenv.mkDerivation (rec {
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.typeOf</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return a string representing the type of the value
|
||||
<replaceable>e</replaceable>, namely <literal>"int"</literal>,
|
||||
<literal>"bool"</literal>, <literal>"string"</literal>,
|
||||
<literal>"path"</literal>, <literal>"null"</literal>,
|
||||
<literal>"set"</literal>, <literal>"list"</literal> or
|
||||
<literal>"lambda"</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
+197
-52
@@ -1,38 +1,50 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="sec-conf-file">
|
||||
<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-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
|
||||
<filename><replaceable>sysconfdir</replaceable>/nix/nix.conf</filename>.
|
||||
This file is a list of <literal><replaceable>name</replaceable> =
|
||||
<replaceable>value</replaceable></literal> pairs, one per line.
|
||||
Comments start with a <literal>#</literal> character. An example
|
||||
configuration file is shown in <xref linkend="ex-nix-conf" />.</para>
|
||||
|
||||
<example xml:id='ex-nix-conf'><title>Nix configuration file</title>
|
||||
Comments start with a <literal>#</literal> character. Here is an example
|
||||
configuration file:</para>
|
||||
|
||||
<programlisting>
|
||||
gc-keep-outputs = true # Nice for developers
|
||||
gc-keep-derivations = true # Idem
|
||||
env-keep-derivations = false
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-gc-keep-outputs"><term><literal>gc-keep-outputs</literal></term>
|
||||
|
||||
<listitem><para>If <literal>true</literal>, the garbage collector
|
||||
will keep the outputs of non-garbage derivations. If
|
||||
<literal>false</literal> (default), outputs will be deleted unless
|
||||
they are GC roots themselves (or reachable from other roots).</para>
|
||||
|
||||
|
||||
<para>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
|
||||
@@ -41,7 +53,7 @@ env-keep-derivations = false
|
||||
this option to <literal>true</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-gc-keep-derivations"><term><literal>gc-keep-derivations</literal></term>
|
||||
|
||||
@@ -59,7 +71,7 @@ env-keep-derivations = false
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><literal>env-keep-derivations</literal></term>
|
||||
|
||||
<listitem><para>If <literal>false</literal> (default), derivations
|
||||
@@ -83,14 +95,14 @@ env-keep-derivations = false
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-build-max-jobs"><term><literal>build-max-jobs</literal></term>
|
||||
|
||||
<listitem><para>This option defines the maximum number of jobs
|
||||
that Nix will try to build in parallel. The default is
|
||||
<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
|
||||
X2). It can be overriden using the <option
|
||||
of CPUs in your system (e.g., <literal>2</literal> on an Athlon 64
|
||||
X2). It can be overridden using the <option
|
||||
linkend='opt-max-jobs'>--max-jobs</option> (<option>-j</option>)
|
||||
command line switch.</para></listitem>
|
||||
|
||||
@@ -107,7 +119,7 @@ env-keep-derivations = false
|
||||
<varname>enableParallelBuilding</varname> is set to
|
||||
<literal>true</literal>, the builder passes the
|
||||
<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
|
||||
defaults to <literal>1</literal>. The value <literal>0</literal>
|
||||
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
|
||||
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
|
||||
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
|
||||
line switch.</para>
|
||||
|
||||
@@ -136,15 +148,16 @@ env-keep-derivations = false
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<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
|
||||
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
|
||||
switch.</para>
|
||||
|
||||
@@ -156,6 +169,20 @@ env-keep-derivations = false
|
||||
</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>
|
||||
|
||||
<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
|
||||
if <envar>NIX_REMOTE</envar> is empty, the uid under which the Nix
|
||||
daemon runs if <envar>NIX_REMOTE</envar> is
|
||||
<literal>daemon</literal>, or the uid that owns the setuid
|
||||
<command>nix-worker</command> program if <envar>NIX_REMOTE</envar>
|
||||
is <literal>slave</literal>). Obviously, this should not be used
|
||||
in multi-user settings with untrusted users.</para>
|
||||
<literal>daemon</literal>). Obviously, this should not be used in
|
||||
multi-user settings with untrusted users.</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
@@ -224,7 +249,27 @@ env-keep-derivations = false
|
||||
|
||||
</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>
|
||||
|
||||
<listitem><para>If set to <literal>true</literal> (default), Nix
|
||||
@@ -233,34 +278,17 @@ env-keep-derivations = false
|
||||
|
||||
</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 (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>
|
||||
<varlistentry><term><literal>build-fallback</literal></term>
|
||||
|
||||
<para>The value used on NixOS is
|
||||
|
||||
<programlisting>
|
||||
build-use-chroot = /dev /proc /bin</programlisting>
|
||||
|
||||
to make the <filename>/bin/sh</filename> symlink available (which
|
||||
is still needed by many builders).</para>
|
||||
|
||||
</listitem>
|
||||
<listitem><para>If set to <literal>true</literal>, Nix will fall
|
||||
back to building from source if a binary substitute fails. This
|
||||
is equivalent to the <option>--fallback</option> flag. The
|
||||
default is <literal>false</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><literal>build-cache-failures</literal></term>
|
||||
|
||||
<listitem><para>If set to <literal>true</literal>, Nix will
|
||||
@@ -276,6 +304,108 @@ build-use-chroot = /dev /proc /bin</programlisting>
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
</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>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</section>
|
||||
</refentry>
|
||||
|
||||
@@ -283,7 +283,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
|
||||
<listitem><para>This variable should be set 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>.
|
||||
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>
|
||||
|
||||
<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"
|
||||
/> for details.</phrase> Each path should be the
|
||||
<filename>/nix</filename> directory of a remote Nix installation
|
||||
@@ -304,14 +304,32 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
<literal>/var/run/nix/remote-stores</literal>.</para>
|
||||
|
||||
<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
|
||||
<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>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><envar>NIX_SHOW_STATS</envar></term>
|
||||
|
||||
<listitem><para>If set to <literal>1</literal>, Nix will print some
|
||||
evaluation statistics, such as the number of values
|
||||
allocated.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><envar>NIX_COUNT_CALLS</envar></term>
|
||||
|
||||
<listitem><para>If set to <literal>1</literal>, Nix will print how
|
||||
often functions were called during Nix expression evaluation. This
|
||||
is useful for profiling your Nix expressions.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><envar>GC_INITIAL_HEAP_SIZE</envar></term>
|
||||
|
||||
<listitem><para>If Nix has been configured to use the Boehm garbage
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
@@ -160,6 +160,18 @@
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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><title>Obtaining Nix</title>
|
||||
<section><title>Installing a binary distribution</title>
|
||||
|
||||
<para>The easiest way to obtain Nix is to download a <link
|
||||
xlink:href="http://nixos.org/">source distribution</link>. RPMs
|
||||
for Red Hat, SuSE, and Fedora Core are also available.</para>
|
||||
<para>The easiest way to install Nix is to use a binary package.
|
||||
Binary packages of the latest stable release are available for Fedora,
|
||||
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/job/nix/trunk/release/latest-finished#tabs-constituents">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/job/nix/trunk/release/latest-finished#tabs-constituents">most
|
||||
recent development release</link>.</para>
|
||||
|
||||
<para>Alternatively, the most recent sources of Nix can be obtained
|
||||
from its <link
|
||||
@@ -63,71 +208,6 @@ repository.</para>
|
||||
</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>
|
||||
|
||||
<para>After unpacking or checking out the Nix sources, issue the
|
||||
@@ -138,7 +218,8 @@ $ ./configure <replaceable>options...</replaceable>
|
||||
$ make
|
||||
$ 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
|
||||
by the command:
|
||||
@@ -180,33 +261,6 @@ options.</para>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -357,11 +411,11 @@ $ chown -R root /nix/store /nix/var/nix</screen>
|
||||
|
||||
</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>):
|
||||
|
||||
<screen>
|
||||
$ nix-worker --daemon</screen>
|
||||
$ nix-daemon</screen>
|
||||
|
||||
You’ll want to put that line somewhere in your system’s boot
|
||||
scripts.</para>
|
||||
@@ -395,11 +449,11 @@ named anything. It should own the Nix store and database:
|
||||
<screen>
|
||||
$ chown -R nix /nix/store /nix/var/nix</screen>
|
||||
|
||||
and of course <command>nix-worker --daemon</command> should be started
|
||||
under that user, e.g.,
|
||||
and of course <command>nix-daemon</command> should be started under
|
||||
that user, e.g.,
|
||||
|
||||
<screen>
|
||||
$ su - nix -c "exec /nix/bin/nix-worker --daemon"</screen>
|
||||
$ su - nix -c "exec /nix/bin/nix-daemon"</screen>
|
||||
|
||||
</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
|
||||
variables is to include the file
|
||||
<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>
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
+15
-9
@@ -19,15 +19,15 @@
|
||||
</author>
|
||||
|
||||
<copyright>
|
||||
<year>2004-2012</year>
|
||||
<year>2004-2013</year>
|
||||
<holder>Eelco Dolstra</holder>
|
||||
</copyright>
|
||||
|
||||
<date>May 2012</date>
|
||||
|
||||
<date>July 2013</date>
|
||||
|
||||
</info>
|
||||
|
||||
|
||||
|
||||
<xi:include href="introduction.xml" />
|
||||
<xi:include href="quick-start.xml" />
|
||||
<xi:include href="installation.xml" />
|
||||
@@ -40,18 +40,18 @@
|
||||
<title>Command Reference</title>
|
||||
<xi:include href="opt-common.xml" />
|
||||
<xi:include href="env-common.xml" />
|
||||
<xi:include href="conf-file.xml" />
|
||||
|
||||
|
||||
<section>
|
||||
<title>Main commands</title>
|
||||
<xi:include href="nix-env.xml" />
|
||||
<xi:include href="nix-instantiate.xml" />
|
||||
<xi:include href="nix-store.xml" />
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Utilities</title>
|
||||
<xi:include href="nix-build.xml" />
|
||||
<xi:include href="nix-shell.xml" />
|
||||
<xi:include href="nix-channel.xml" />
|
||||
<xi:include href="nix-collect-garbage.xml" />
|
||||
<xi:include href="nix-copy-closure.xml" />
|
||||
@@ -60,7 +60,12 @@
|
||||
<xi:include href="nix-prefetch-url.xml" />
|
||||
<xi:include href="nix-pull.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>
|
||||
|
||||
</appendix>
|
||||
@@ -68,11 +73,12 @@
|
||||
<xi:include href="troubleshooting.xml" />
|
||||
<!-- <xi:include href="bugs.xml" /> -->
|
||||
<xi:include href="glossary.xml" />
|
||||
<xi:include href="hacking.xml" />
|
||||
|
||||
<appendix>
|
||||
<title>Nix Release Notes</title>
|
||||
<xi:include href="release-notes.xml"
|
||||
xpointer="xmlns(x=http://docbook.org/ns/docbook)xpointer(x:article/x:section)" />
|
||||
</appendix>
|
||||
|
||||
|
||||
</book>
|
||||
|
||||
+25
-52
@@ -38,11 +38,6 @@
|
||||
</group>
|
||||
<replaceable>outlink</replaceable>
|
||||
</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>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
@@ -75,13 +70,6 @@ a root of the Nix garbage collector. This root disappears
|
||||
automatically when the <filename>result</filename> symlink is deleted
|
||||
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>
|
||||
|
||||
|
||||
@@ -96,7 +84,7 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><option>--drv-link</option> <replaceable>drvlink</replaceable></term>
|
||||
|
||||
|
||||
<listitem><para>Add a symlink named
|
||||
<replaceable>drvlink</replaceable> to the store derivation
|
||||
produced by <command>nix-instantiate</command>. The derivation is
|
||||
@@ -108,14 +96,14 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--add-drv-link</option></term>
|
||||
|
||||
|
||||
<listitem><para>Shorthand for <option>--drv-link</option>
|
||||
<filename>./derivation</filename>.</para></listitem>
|
||||
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--no-out-link</option></term>
|
||||
|
||||
|
||||
<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
|
||||
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> /
|
||||
<option>-o</option> <replaceable>outlink</replaceable></term>
|
||||
|
||||
|
||||
<listitem><para>Change the name of the symlink to the output path
|
||||
created from <filename>result</filename> to
|
||||
<replaceable>outlink</replaceable>.</para></listitem>
|
||||
@@ -134,32 +122,12 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
@@ -176,20 +144,25 @@ lrwxrwxrwx <replaceable>...</replaceable> result -> /nix/store/d18hyl92g30l...
|
||||
$ ls ./result/bin/
|
||||
firefox firefox-config</screen>
|
||||
|
||||
<para>To build the dependencies of the package Pan, and start an
|
||||
interactive shell in which to build it:
|
||||
|
||||
<para>If a derivation has multiple outputs,
|
||||
<command>nix-build</command> will build the default (first) output.
|
||||
You can also build all outputs:
|
||||
<screen>
|
||||
$ nix-build '<nixpkgs>' --run-env -A pan
|
||||
$ tar xf $src
|
||||
$ cd pan-*
|
||||
$ ./configure
|
||||
$ make
|
||||
$ ./pan/gui/pan
|
||||
$ nix-build '<nixpkgs>' -A openssl.all
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
This will create a symlink for each output named
|
||||
<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>
|
||||
|
||||
@@ -201,6 +174,6 @@ $ ./pan/gui/pan
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -103,7 +103,7 @@ respectively.</para>
|
||||
<para>To subscribe to the Nixpkgs channel and install the GNU Hello package:</para>
|
||||
|
||||
<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-env -iA nixpkgs.hello</screen>
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<arg choice='plain'><option>--print-dead</option></arg>
|
||||
<arg choice='plain'><option>--delete</option></arg>
|
||||
</group>
|
||||
<arg><option>--dry-run</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
<arg><option>--xz</option></arg>
|
||||
<arg><option>--show-progress</option></arg>
|
||||
<arg><option>--include-outputs</option></arg>
|
||||
<arg><option>--use-substitutes</option></arg>
|
||||
<arg><option>-s</option></arg>
|
||||
<arg choice='plain'>
|
||||
<replaceable>user@</replaceable><replaceable>machine</replaceable>
|
||||
</arg>
|
||||
@@ -65,7 +67,7 @@ those paths. If this bothers you, use
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
<varlistentry><term><option>--to</option></term>
|
||||
|
||||
<listitem><para>Copy the closure of
|
||||
@@ -119,10 +121,22 @@ those paths. If this bothers you, use
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--include-outputs</option></term>
|
||||
|
||||
<listitem><para>Also copy the outputs of store derivations included
|
||||
in the closure.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Also copy the outputs of store derivations
|
||||
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>
|
||||
|
||||
</variablelist>
|
||||
@@ -140,7 +154,7 @@ those paths. If this bothers you, use
|
||||
<command>ssh</command> on the command line.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
<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-worker">
|
||||
xml:id="sec-nix-daemon">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-worker</refentrytitle>
|
||||
<refentrytitle>nix-daemon</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-worker</refname>
|
||||
<refname>nix-daemon</refname>
|
||||
<refpurpose>Nix multi-user support daemon</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-worker</command>
|
||||
<arg choice="plain"><option>--daemon</option></arg>
|
||||
<command>nix-daemon</command>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
+37
-14
@@ -93,11 +93,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
|
||||
<listitem><para>Specifies the profile to be used by those
|
||||
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
|
||||
which is the <emphasis>current generation</emphasis>. The default
|
||||
profile is the target of the symbolic link
|
||||
<filename>~/.nix-profile</filename> (see below).</para></listitem>
|
||||
which is the <emphasis>current
|
||||
generation</emphasis>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
@@ -105,7 +104,8 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
|
||||
<listitem><para>For the <option>--install</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
|
||||
<command>nix-env</command> to print what
|
||||
<emphasis>would</emphasis> be done if this flag had not been
|
||||
@@ -153,11 +153,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
default.</para>
|
||||
|
||||
<para>The Nix expressions in this directory are combined into a
|
||||
single attribute set, with each file as an attribute that has the
|
||||
name of the file. Thus, if <filename>~/.nix-defexpr</filename>
|
||||
contains two files, <filename>foo</filename> and
|
||||
<filename>bar</filename>, then the default Nix expression will
|
||||
essentially be
|
||||
single set, with each file as an attribute that has the name of
|
||||
the file. Thus, if <filename>~/.nix-defexpr</filename> contains
|
||||
two files, <filename>foo</filename> and <filename>bar</filename>,
|
||||
then the default Nix expression will essentially be
|
||||
|
||||
<programlisting>
|
||||
{
|
||||
@@ -209,6 +208,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
|
||||
<arg choice='plain'><option>--preserve-installed</option></arg>
|
||||
<arg choice='plain'><option>-P</option></arg>
|
||||
</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>
|
||||
</cmdsynopsis>
|
||||
|
||||
@@ -272,7 +275,7 @@ number of possible ways:
|
||||
linkend="ss-functions">functions</link> that are called with the
|
||||
active Nix expression as their single argument. The derivations
|
||||
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
|
||||
name.</para></listitem>
|
||||
|
||||
@@ -318,6 +321,16 @@ number of possible ways:
|
||||
|
||||
</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>
|
||||
|
||||
</refsection>
|
||||
@@ -391,7 +404,7 @@ $ nix-env -f ./foo.nix -i -E \
|
||||
I.e., this evaluates to <literal>(f: (f {system =
|
||||
"i686-linux";}).subversionWithJava) (import ./foo.nix)</literal>, thus
|
||||
selecting the <literal>subversionWithJava</literal> attribute from the
|
||||
attribute set returned by calling the function defined in
|
||||
set returned by calling the function defined in
|
||||
<filename>./foo.nix</filename>.</para>
|
||||
|
||||
<para>A dry-run tells you which paths will be downloaded or built from
|
||||
@@ -692,7 +705,7 @@ firefox-2.0.0.9 <lineannotation>(the current one)</lineannotation>
|
||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
||||
installing `firefox-2.0.0.11'
|
||||
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'.
|
||||
<lineannotation>(i.e., can’t have two active at the same time)</lineannotation>
|
||||
|
||||
@@ -1244,7 +1257,7 @@ wrapper around <option>--list-generations</option> and
|
||||
$ nix-env --rollback
|
||||
switching from generation 92 to 91
|
||||
|
||||
$ nix-env --rolback
|
||||
$ nix-env --rollback
|
||||
error: no generation older than the current (91) exists</screen>
|
||||
|
||||
</refsection>
|
||||
@@ -1255,6 +1268,16 @@ error: no generation older than the current (91) exists</screen>
|
||||
<refsection condition="manpage"><title>Environment variables</title>
|
||||
|
||||
<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']/*)" />
|
||||
</variablelist>
|
||||
|
||||
|
||||
@@ -91,8 +91,9 @@ cryptographic hash as <literal>nix-store --dump
|
||||
|
||||
<varlistentry><term><option>--type</option> <replaceable>hashAlgo</replaceable></term>
|
||||
|
||||
<listitem><para>Specify a cryptographic hash, which can be one of
|
||||
<literal>md5</literal>, <literal>sha1</literal>, and
|
||||
<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>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-prefetch-url</command>
|
||||
<arg><option>--type</option> <replaceable>hashAlgo</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>url</replaceable></arg>
|
||||
<arg><replaceable>hash</replaceable></arg>
|
||||
</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
|
||||
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
|
||||
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
|
||||
@@ -63,6 +59,24 @@ of the downloaded file in the Nix store is also printed.</para>
|
||||
</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>
|
||||
|
||||
<screen>
|
||||
|
||||
+345
-76
@@ -12,24 +12,20 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-push</refname>
|
||||
<refpurpose>push store paths onto a network cache</refpurpose>
|
||||
<refpurpose>generate a binary cache</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-push</command>
|
||||
<group choice='req'>
|
||||
<arg choice='req'>
|
||||
<arg choice='plain'><replaceable>archivesPutURL</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>archivesGetURL</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>manifestPutURL</replaceable></arg>
|
||||
</arg>
|
||||
<arg choice='req'>
|
||||
<arg choice='plain'><option>--copy</option></arg>
|
||||
<arg choice='plain'><replaceable>archivesDir</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>manifestFile</replaceable></arg>
|
||||
</arg>
|
||||
</group>
|
||||
<arg choice='plain'><option>--dest</option> <replaceable>dest-dir</replaceable></arg>
|
||||
<arg><option>--bzip2</option></arg>
|
||||
<arg><option>--none</option></arg>
|
||||
<arg><option>--force</option></arg>
|
||||
<arg><option>--link</option></arg>
|
||||
<arg><option>--manifest</option></arg>
|
||||
<arg><option>--manifest-path</option> <replaceable>filename</replaceable></arg>
|
||||
<arg><option>--url-prefix</option> <replaceable>url</replaceable></arg>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
@@ -37,93 +33,366 @@
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The command <command>nix-push</command> builds a set of store
|
||||
paths (if necessary), and then packages and uploads all store paths in
|
||||
the resulting closures to a server. A network cache thus populated
|
||||
can subsequently be used to speed up software deployment on other
|
||||
machines using the <command>nix-pull</command> command.</para>
|
||||
<para>The command <command>nix-push</command> produces a
|
||||
<emphasis>binary cache</emphasis>, a directory containing compressed
|
||||
Nix archives (NARs) plus some metadata of the closure of the specified
|
||||
store paths. This directory can then be made available through a web
|
||||
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.
|
||||
|
||||
<orderedlist>
|
||||
|
||||
<listitem><para>Each path in <replaceable>paths</replaceable> is
|
||||
realised (using <link
|
||||
linkend='rsec-nix-store-realise'><literal>nix-store
|
||||
--realise</literal></link>).</para></listitem>
|
||||
built (using <link
|
||||
linkend='rsec-nix-store-realise'><command>nix-store
|
||||
--realise</command></link>).</para></listitem>
|
||||
|
||||
<listitem><para>All paths in the closure of the store expressions
|
||||
stored in <replaceable>paths</replaceable> are determined (using
|
||||
<literal>nix-store --query --requisites
|
||||
--include-outputs</literal>). It should be noted that since the
|
||||
<option>--include-outputs</option> flag is used, you get a combined
|
||||
source/binary distribution.</para></listitem>
|
||||
<listitem><para>All paths in the closure of
|
||||
<replaceable>paths</replaceable> are determined (using
|
||||
<command>nix-store --query --requisites
|
||||
--include-outputs</command>). Note that since the
|
||||
<option>--include-outputs</option> flag is used, if
|
||||
<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
|
||||
packaged and compressed into a <command>bzip</command>ped NAR
|
||||
archive (extension <filename>.nar.bz2</filename>).</para></listitem>
|
||||
packaged into a NAR (using <command>nix-store --dump</command>) and
|
||||
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
|
||||
contains information on the store paths, their eventual URLs in the
|
||||
cache, and cryptographic hashes of the contents of the NAR
|
||||
archives.</para></listitem>
|
||||
<listitem><para>Optionally, a single <emphasis>manifest</emphasis>
|
||||
file is created that contains the same metadata as the
|
||||
<filename>.narinfo</filename> files. This is for compatibility with
|
||||
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
|
||||
specified by <replaceable>archivesPutURL</replaceable>. HTTP PUT
|
||||
requests are used to do this. However, before a file
|
||||
<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>A file named <option>nix-cache-info</option> is
|
||||
placed in the destination directory. The existence of this file
|
||||
marks the directory as a binary cache.</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>
|
||||
|
||||
</para>
|
||||
|
||||
<!--
|
||||
<para>TODO: <option>- -copy</option></para>
|
||||
-->
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<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><title>Examples</title>
|
||||
|
||||
<para>To upload files there typically is some CGI script on the server
|
||||
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>
|
||||
<para>To add the closure of Thunderbird to a binary cache:
|
||||
|
||||
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>
|
||||
$ 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>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><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>
|
||||
|
||||
@@ -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
|
||||
done immediately. Otherwise, the path and any missing paths in its
|
||||
closure may be produced through substitutes. If there are no
|
||||
(succesful) subsitutes, realisation fails.</para></listitem>
|
||||
(successful) subsitutes, realisation fails.</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
@@ -174,10 +174,26 @@ the specified store paths. Realisation is a somewhat overloaded term:
|
||||
output. (For non-derivations argument, the argument itself is
|
||||
printed.)</para>
|
||||
|
||||
<para>If the <option>--dry-run</option> option is used, then
|
||||
<command>nix-store</command> will print on standard error a
|
||||
description of what packages would be built or downloaded, and then
|
||||
quit.</para>
|
||||
<para>The following flags are available:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -773,6 +789,7 @@ $ nix-store --add ./foo.c
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--verify</option></arg>
|
||||
<arg><option>--check-contents</option></arg>
|
||||
<arg><option>--repair</option></arg>
|
||||
</cmdsynopsis>
|
||||
</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
|
||||
in Nix itself.</para>
|
||||
|
||||
<para>There is one option:
|
||||
<para>This operation has the following options:
|
||||
|
||||
<variablelist>
|
||||
|
||||
@@ -800,6 +817,16 @@ in Nix itself.</para>
|
||||
|
||||
</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>
|
||||
|
||||
</para>
|
||||
@@ -825,7 +852,7 @@ in Nix itself.</para>
|
||||
|
||||
<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
|
||||
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
|
||||
@@ -848,6 +875,52 @@ $ nix-store --verify-path $(nix-store -qR $(which svn))
|
||||
</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>
|
||||
@@ -1169,9 +1242,9 @@ variable <envar>_args</envar>.</para>
|
||||
$ nix-store --print-env $(nix-instantiate '<nixpkgs>' -A firefox)
|
||||
<replaceable>…</replaceable>
|
||||
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 _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh'
|
||||
export _args; _args='-e /nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25c-default-builder.sh'
|
||||
</screen>
|
||||
|
||||
</refsection>
|
||||
@@ -1246,8 +1319,8 @@ paths.</para>
|
||||
<refsection><title>Example</title>
|
||||
|
||||
<screen>
|
||||
$ nix-store --clear-failed-path /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
|
||||
$ nix-store --clear-failed-path *
|
||||
$ nix-store --clear-failed-paths /nix/store/000zi5dcla86l92jn1g997jb06sidm7x-perl-PerlMagick-6.59
|
||||
$ nix-store --clear-failed-paths *
|
||||
</screen>
|
||||
|
||||
</refsection>
|
||||
|
||||
@@ -37,6 +37,11 @@
|
||||
<option>-I</option>
|
||||
<replaceable>path</replaceable>
|
||||
</arg>
|
||||
<arg>
|
||||
<option>--option</option>
|
||||
<replaceable>name</replaceable>
|
||||
<replaceable>value</replaceable>
|
||||
</arg>
|
||||
<sbr />
|
||||
|
||||
</nop>
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
from, say, a network repository. If the repository is down, the
|
||||
realisation of the derivation will fail. When this option is
|
||||
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
|
||||
for a transient failure in obtaining the substitutes to lead to a
|
||||
full build from source (with the related consumption of
|
||||
@@ -236,7 +236,7 @@
|
||||
interpreted by the <command>nix-log2xml</command> tool in the
|
||||
Nix source distribution. The resulting XML file can be fed into
|
||||
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>
|
||||
|
||||
</varlistentry>
|
||||
@@ -337,20 +337,42 @@
|
||||
|
||||
<listitem><para>Causes Nix to print out a stack trace in case of Nix
|
||||
expression evaluation errors.</para></listitem>
|
||||
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><option>-I</option> <replaceable>path</replaceable></term>
|
||||
|
||||
<listitem><para>Add a path to the Nix expression search path. See
|
||||
the <envar>NIX_PATH</envar> environment variable for details. Paths
|
||||
added through <option>-I</option> take precedence over
|
||||
<envar>NIX_PATH</envar>.</para></listitem>
|
||||
<listitem><para>Add a path to the Nix expression search path. This
|
||||
option may be given multiple times. See the <envar>NIX_PATH</envar>
|
||||
environment variable for information on the semantics of the Nix
|
||||
search path. Paths added through <option>-I</option> take
|
||||
precedence over <envar>NIX_PATH</envar>.</para></listitem>
|
||||
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ downloading binaries from <systemitem
|
||||
class='fqdomainname'>nixos.org</systemitem>, instead of building
|
||||
them from source. This might still take a while since all
|
||||
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:
|
||||
|
||||
@@ -175,21 +175,6 @@ upgrading `coreutils-5.0' to `coreutils-5.2.1'</screen>
|
||||
|
||||
</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>
|
||||
|
||||
|
||||
@@ -240,7 +225,7 @@ uses is to create directory trees of symlinks to
|
||||
themselves (though automatically generated by
|
||||
<command>nix-env</command>), so they too reside in the Nix store. For
|
||||
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
|
||||
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.,
|
||||
|
||||
<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
|
||||
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,
|
||||
|
||||
<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
|
||||
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:
|
||||
|
||||
<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>
|
||||
|
||||
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
|
||||
<filename>/mnt/nix</filename>, then it will just copy from there
|
||||
instead of building it from source.</para>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ to the following chapters.</para>
|
||||
<listitem><para>Download a source tarball or RPM or Debian/Ubuntu
|
||||
package from <link xlink:href='http://nixos.org/'/>. Build source
|
||||
distributions using the regular sequence:
|
||||
|
||||
|
||||
<screen>
|
||||
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
|
||||
$ cd nix-<replaceable>version</replaceable>
|
||||
$ ./configure
|
||||
$ make
|
||||
$ make install <lineannotation>(as root)</lineannotation></screen>
|
||||
@@ -35,13 +36,13 @@ changed using
|
||||
|
||||
<listitem><para>You should add
|
||||
<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>
|
||||
|
||||
<listitem><para>Subscribe to the Nix Packages channel.
|
||||
|
||||
<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>
|
||||
|
||||
@@ -69,7 +70,7 @@ libxslt-1.1.0
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>Install some packages from the channel:
|
||||
|
||||
|
||||
<screen>
|
||||
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
|
||||
|
||||
@@ -87,7 +88,7 @@ $ firefox
|
||||
<lineannotation>(read Slashdot or something)</lineannotation></screen>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Uninstall a package:
|
||||
|
||||
<screen>
|
||||
|
||||
@@ -5,6 +5,582 @@
|
||||
<title>Nix Release Notes</title>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.6.1"><title>Release 1.6.1 (October 28, 2013)</title>
|
||||
|
||||
<para>This is primarily a bug fix release. Changes of interest
|
||||
are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>Nix 1.6 accidentally changed the semantics of antiquoted
|
||||
paths in strings, such as <literal>"${/foo}/bar"</literal>. This
|
||||
release reverts to the Nix 1.5.3 behaviour.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Previously, Nix optimised expressions such as
|
||||
<literal>"${<replaceable>expr</replaceable>}"</literal> to
|
||||
<replaceable>expr</replaceable>. Thus it neither checked whether
|
||||
<replaceable>expr</replaceable> could be coerced to a string, nor
|
||||
applied such coercions. This meant that
|
||||
<literal>"${123}"</literal> evaluatued to <literal>123</literal>,
|
||||
and <literal>"${./foo}"</literal> evaluated to
|
||||
<literal>./foo</literal> (even though
|
||||
<literal>"${./foo} "</literal> evaluates to
|
||||
<literal>"/nix/store/<replaceable>hash</replaceable>-foo "</literal>).
|
||||
Nix now checks the type of antiquoted expressions and
|
||||
applies coercions.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Nix now shows the exact position of undefined variables. In
|
||||
particular, undefined variable errors in a <literal>with</literal>
|
||||
previously didn't show <emphasis>any</emphasis> position
|
||||
information, so this makes it a lot easier to fix such
|
||||
errors.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Undefined variables are now treated consistently.
|
||||
Previously, the <function>tryEval</function> function would catch
|
||||
undefined variables inside a <literal>with</literal> but not
|
||||
outside. Now <function>tryEval</function> never catches undefined
|
||||
variables.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Bash completion in <command>nix-shell</command> now works
|
||||
correctly.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Stack traces are less verbose: they no longer show calls to
|
||||
builtin functions and only show a single line for each derivation
|
||||
on the call stack.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>New built-in function: <function>builtins.typeOf</function>,
|
||||
which returns the type of its argument as a string.</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-1.6.0"><title>Release 1.6 (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>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
@@ -936,7 +1512,7 @@ irreversible.</para></warning>
|
||||
</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>,
|
||||
<command>nix-instantiate</command> and <command>nix-build</command>
|
||||
using the <option>--attr</option> / <option>-A</option> flags, which
|
||||
@@ -1076,7 +1652,7 @@ irreversible.</para></warning>
|
||||
<itemizedlist>
|
||||
|
||||
<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>
|
||||
|
||||
<listitem><para><command>nix-env</command> now locks the profile
|
||||
@@ -1431,7 +2007,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
|
||||
</itemizedlist></para></listitem>
|
||||
|
||||
<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
|
||||
--verify --check-contents</command>.</para></listitem>
|
||||
|
||||
@@ -1595,7 +2171,7 @@ $ nix-env -f .../i686-linux.nix -i -E 'x: x.firefoxWrapper'</screen>
|
||||
<itemizedlist>
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
...
|
||||
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'
|
||||
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
|
||||
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).
|
||||
Furthermore, the <literal>st_nlink</literal> field of the
|
||||
<function>stat</function> system call is a 16-bit value.</para>
|
||||
|
||||
@@ -15,7 +15,7 @@ on to a more in-depth look at the Nix expression language.</para>
|
||||
For more extensive information on adding packages to the Nix Packages
|
||||
collection (such as functions in the standard environment and coding
|
||||
conventions), please consult <link
|
||||
xlink:href="http://hydra.nixos.org/job/nixpkgs/trunk/tarball/latest/download-by-type/doc/manual">its
|
||||
xlink:href="http://nixos.org/nixpkgs/manual/">its
|
||||
manual</link>.</para></note>
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ the single Nix expression in that directory
|
||||
here, the entire remainder of the file is the body of the
|
||||
function; when given the required arguments, the body should
|
||||
describe how to build an instance of the Hello package.</para>
|
||||
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='ex-hello-nix-co-2'>
|
||||
@@ -118,10 +118,10 @@ the single Nix expression in that directory
|
||||
<varname>stdenv.mkDerivation</varname>.
|
||||
<varname>mkDerivation</varname> is a function provided by
|
||||
<varname>stdenv</varname> that builds a package from a set of
|
||||
<emphasis>attributes</emphasis>. An attribute set is just a list
|
||||
of key/value pairs where each value is an arbitrary Nix
|
||||
expression. They take the general form
|
||||
<literal>{ <replaceable>name1</replaceable> =
|
||||
<emphasis>attributes</emphasis>. A set is just a list of
|
||||
key/value pairs where each key is a string and each value is an
|
||||
arbitrary Nix expression. They take the general form <literal>{
|
||||
<replaceable>name1</replaceable> =
|
||||
<replaceable>expr1</replaceable>; <replaceable>...</replaceable>
|
||||
<replaceable>nameN</replaceable> =
|
||||
<replaceable>exprN</replaceable>; }</literal>.</para>
|
||||
@@ -190,7 +190,7 @@ perl = perl;</programlisting>
|
||||
with the same name happen to be in scope.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
|
||||
</calloutlist>
|
||||
|
||||
</para>
|
||||
@@ -301,7 +301,7 @@ steps:</para>
|
||||
(<literal>make install</literal>).</para>
|
||||
|
||||
</callout>
|
||||
|
||||
|
||||
</calloutlist>
|
||||
|
||||
<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' />
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -330,10 +330,10 @@ rec { <co xml:id='ex-hello-composition-co-1' />
|
||||
inherit fetchurl stdenv;
|
||||
};
|
||||
|
||||
fetchurl = import ../build-support/fetchurl {
|
||||
fetchurl = import ../build-support/fetchurl {
|
||||
inherit stdenv; ...
|
||||
};
|
||||
|
||||
|
||||
stdenv = ...;
|
||||
|
||||
}
|
||||
@@ -384,9 +384,9 @@ some fragments of
|
||||
|
||||
<para>This is where the actual composition takes place. Here we
|
||||
<emphasis>call</emphasis> the function imported from
|
||||
<filename>../applications/misc/hello/ex-1</filename> with an
|
||||
attribute set containing the things that the function expects,
|
||||
namely <varname>fetchurl</varname>, <varname>stdenv</varname>, and
|
||||
<filename>../applications/misc/hello/ex-1</filename> with a set
|
||||
containing the things that the function expects, namely
|
||||
<varname>fetchurl</varname>, <varname>stdenv</varname>, and
|
||||
<varname>perl</varname>. We use inherit again to use the
|
||||
attributes defined in the surrounding scope (we could also have
|
||||
written <literal>fetchurl = fetchurl;</literal>, etc.).</para>
|
||||
@@ -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
|
||||
build fails, either because it returns a non-zero exit code, because
|
||||
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 derivation again, Nix will remove the output path if it exists
|
||||
the output paths will not be registered as valid. If you try to build
|
||||
the derivation again, Nix will remove the output paths if they exist
|
||||
(e.g., because the builder died half-way through <literal>make
|
||||
install</literal>) and try again. Note that there is no
|
||||
<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>
|
||||
|
||||
<callout arearefs='ex-hello-builder2-co-1'>
|
||||
|
||||
|
||||
<para>The <envar>buildInputs</envar> variable tells
|
||||
<filename>setup</filename> to use the indicated packages as
|
||||
<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>
|
||||
|
||||
</callout>
|
||||
|
||||
|
||||
<callout arearefs='ex-hello-builder2-co-3'>
|
||||
|
||||
<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>
|
||||
|
||||
</callout>
|
||||
|
||||
|
||||
</calloutlist>
|
||||
|
||||
<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
|
||||
<quote>normal</quote> values that can be passed around and manipulated
|
||||
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
|
||||
packages.</para>
|
||||
|
||||
@@ -701,10 +701,10 @@ configureFlags = "
|
||||
number of spaces equal to the minimal indentation of the string as
|
||||
a whole (disregarding the indentation of empty lines). For
|
||||
instance, the first and second line are indented two space, while
|
||||
the third line is indented three spaces. Thus, two spaces are
|
||||
the third line is indented four spaces. Thus, two spaces are
|
||||
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>
|
||||
|
||||
</para>
|
||||
@@ -714,19 +714,19 @@ configureFlags = "
|
||||
text on the initial line.</para>
|
||||
|
||||
<para>Antiquotation
|
||||
(<literal>${<replaceable>expr</replaceable>}}</literal>) is
|
||||
(<literal>${<replaceable>expr</replaceable>}</literal>) is
|
||||
supported in indented strings.</para>
|
||||
|
||||
<para>Since <literal>${</literal> and <literal>''</literal> have
|
||||
special meaning in indented strings, you need a way to quote them.
|
||||
<literal>${</literal> can be escaped by prefixing it with
|
||||
<literal>''</literal>, i.e., <literal>''${</literal>.
|
||||
<literal>''</literal> can be escaped by prefixing it with
|
||||
<literal>'</literal>, i.e., <literal>'''</literal>. Finally,
|
||||
linefeed, carriage-return and tab characters can be writted as
|
||||
<literal>''\n</literal>, <literal>''\r</literal>,
|
||||
<literal>''\t</literal>.</para>
|
||||
|
||||
<literal>''</literal> (that is, two single quotes), i.e.,
|
||||
<literal>''${</literal>. <literal>''</literal> can be escaped by
|
||||
prefixing it with <literal>'</literal>, i.e.,
|
||||
<literal>'''</literal>. Finally, linefeed, carriage-return and
|
||||
tab characters can be written as <literal>''\n</literal>,
|
||||
<literal>''\r</literal>, <literal>''\t</literal>.</para>
|
||||
|
||||
<para>Indented strings are primarily useful in that they allow
|
||||
multi-line string literals to follow the indentation of the
|
||||
enclosing Nix expression, and that less escaping is typically
|
||||
@@ -745,7 +745,7 @@ stdenv.mkDerivation {
|
||||
${if enableBar then "cp bar $out/bin" else ""}
|
||||
'';
|
||||
<replaceable>...</replaceable>
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
@@ -775,13 +775,13 @@ stdenv.mkDerivation {
|
||||
absolute at parse time relative to the directory of the Nix
|
||||
expression that contained it. For instance, if a Nix expression in
|
||||
<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>
|
||||
|
||||
<listitem><para><emphasis>Booleans</emphasis> with values
|
||||
<literal>true</literal> and
|
||||
<literal>false</literal>.</para></listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
@@ -805,20 +805,21 @@ to be enclosed in parentheses. If they had been omitted, e.g.,
|
||||
[ 123 ./foo.nix "abc" f { x = y; } ]</programlisting>
|
||||
|
||||
the result would be a list of five elements, the fourth one being a
|
||||
function and the fifth being an attribute set.</para>
|
||||
function and the fifth being a set.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Attribute sets</title>
|
||||
<simplesect><title>Sets</title>
|
||||
|
||||
<para>Attribute sets are really the core of the language, since
|
||||
ultimately it's all about creating derivations, which are really just
|
||||
<para>Sets are really the core of the language, since ultimately the
|
||||
Nix language is all about creating derivations, which are really just
|
||||
sets of attributes to be passed to build scripts.</para>
|
||||
|
||||
<para>Attribute sets are just a list of name/value pairs enclosed in
|
||||
curly brackets, where each value is an arbitrary expression terminated
|
||||
by a semicolon. For example:
|
||||
<para>Sets are just a list of name/value pairs (called
|
||||
<emphasis>attributes</emphasis>) enclosed in curly brackets, where
|
||||
each value is an arbitrary expression terminated by a semicolon. For
|
||||
example:
|
||||
|
||||
<programlisting>
|
||||
{ x = 123;
|
||||
@@ -826,12 +827,12 @@ by a semicolon. For example:
|
||||
y = f { bla = 456; };
|
||||
}</programlisting>
|
||||
|
||||
This defines an attribute set with attributes named
|
||||
<varname>x</varname>, <varname>test</varname>, <varname>y</varname>.
|
||||
The order of the attributes is irrelevant. An attribute name may only
|
||||
occur once.</para>
|
||||
This defines a set with attributes named <varname>x</varname>,
|
||||
<varname>text</varname>, <varname>y</varname>. The order of the
|
||||
attributes is irrelevant. An attribute name may only occur
|
||||
once.</para>
|
||||
|
||||
<para>Attributes can be selected from an attribute set using the
|
||||
<para>Attributes can be selected from a set using the
|
||||
<literal>.</literal> operator. For instance,
|
||||
|
||||
<programlisting>
|
||||
@@ -864,10 +865,10 @@ This will evaluate to <literal>123</literal>.</para>
|
||||
<section><title>Language constructs</title>
|
||||
|
||||
|
||||
<simplesect><title>Recursive attribute sets</title>
|
||||
<simplesect><title>Recursive sets</title>
|
||||
|
||||
<para>Recursive attribute sets are just normal attribute sets, but the
|
||||
attributes can refer to each other. For example,
|
||||
<para>Recursive sets are just normal sets, but the attributes can
|
||||
refer to each other. For example,
|
||||
|
||||
<programlisting>
|
||||
rec {
|
||||
@@ -880,11 +881,11 @@ evaluates to <literal>123</literal>. Note that without
|
||||
<literal>rec</literal> the binding <literal>x = y;</literal> would
|
||||
refer to the variable <varname>y</varname> in the surrounding scope,
|
||||
if one exists, and would be invalid if no such variable exists. That
|
||||
is, in a normal (non-recursive) attribute set, attributes are not
|
||||
added to the lexical scope; in a recursive set, they are.</para>
|
||||
is, in a normal (non-recursive) set, attributes are not added to the
|
||||
lexical scope; in a recursive set, they are.</para>
|
||||
|
||||
<para>Recursive attribute sets of course introduce the danger of
|
||||
infinite recursion. For example,
|
||||
<para>Recursive sets of course introduce the danger of infinite
|
||||
recursion. For example,
|
||||
|
||||
<programlisting>
|
||||
rec {
|
||||
@@ -901,8 +902,8 @@ encountered</quote>).</para></footnote>.</para>
|
||||
|
||||
<simplesect><title>Let-expressions</title>
|
||||
|
||||
<para>A let-expression allows you define local
|
||||
variables for an expression. For instance,
|
||||
<para>A let-expression allows you define local variables for an
|
||||
expression. For instance,
|
||||
|
||||
<programlisting>
|
||||
let
|
||||
@@ -914,32 +915,26 @@ evaluates to <literal>"foobar"</literal>.
|
||||
|
||||
</para>
|
||||
|
||||
<note><para>There is also an obsolete form of let-expression,
|
||||
<literal>let { <replaceable>attrs</replaceable> }</literal>, which is
|
||||
translated to <literal>rec { <replaceable>attrs</replaceable>
|
||||
}.body</literal>. That is, the body of the let-expression is the
|
||||
<literal>body</literal> attribute of the attribute set.</para></note>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Inheriting attributes</title>
|
||||
|
||||
<para>When defining an attribute set it is often convenient to copy
|
||||
variables from the surrounding lexical scope (e.g., when you want to
|
||||
propagate attributes). This can be shortened using the
|
||||
<para>When defining a set it is often convenient to copy variables
|
||||
from the surrounding lexical scope (e.g., when you want to propagate
|
||||
attributes). This can be shortened using the
|
||||
<literal>inherit</literal> keyword. For instance,
|
||||
|
||||
<programlisting>
|
||||
let x = 123; in
|
||||
let x = 123; in
|
||||
{ inherit x;
|
||||
y = 456;
|
||||
}</programlisting>
|
||||
|
||||
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that this
|
||||
works because <varname>x</varname> is added to the lexical scope by
|
||||
the <literal>let</literal> construct.) It is also possible to inherit
|
||||
attributes from another attribute set. For instance, in this fragment
|
||||
evaluates to <literal>{ x = 123; y = 456; }</literal>. (Note that
|
||||
this works because <varname>x</varname> is added to the lexical scope
|
||||
by the <literal>let</literal> construct.) It is also possible to
|
||||
inherit attributes from another set. For instance, in this fragment
|
||||
from <filename>all-packages.nix</filename>,
|
||||
|
||||
<programlisting>
|
||||
@@ -958,13 +953,12 @@ from <filename>all-packages.nix</filename>,
|
||||
libjpg = ...;
|
||||
...</programlisting>
|
||||
|
||||
the attribute set used in the function call to the function defined in
|
||||
the set used in the function call to the function defined in
|
||||
<filename>../tools/graphics/graphviz</filename> inherits a number of
|
||||
variables from the surrounding scope (<varname>fetchurl</varname>
|
||||
... <varname>yacc</varname>), but also inherits
|
||||
<varname>libXaw</varname> (the X Athena Widgets) from the
|
||||
<varname>xlibs</varname> (X11 client-side libraries) attribute
|
||||
set.</para>
|
||||
<varname>xlibs</varname> (X11 client-side libraries) set.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
@@ -982,7 +976,7 @@ argument. There are three kinds of patterns:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
|
||||
|
||||
<listitem><para>If a pattern is a single identifier, then the
|
||||
function matches any argument. Example:
|
||||
|
||||
@@ -1002,12 +996,12 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
|
||||
evaluates to <literal>[ "foobar" "foobla"
|
||||
"fooabc" ]</literal>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>An <emphasis>attribute set pattern</emphasis> of the
|
||||
form <literal>{ name1, name2, …, nameN }</literal>
|
||||
matches an attribute set containing the listed attributes, and binds
|
||||
the values of those attributes to variables in the function body.
|
||||
For example, the function
|
||||
|
||||
<listitem><para>A <emphasis>set pattern</emphasis> of the form
|
||||
<literal>{ name1, name2, …, nameN }</literal> matches a set
|
||||
containing the listed attributes, and binds the values of those
|
||||
attributes to variables in the function body. For example, the
|
||||
function
|
||||
|
||||
<programlisting>
|
||||
{ x, y, z }: z + y + x</programlisting>
|
||||
@@ -1016,7 +1010,7 @@ map (concat "foo") [ "bar" "bla" "abc" ]</programlisting>
|
||||
<varname>x</varname>, <varname>y</varname> and
|
||||
<varname>z</varname>. No other attributes are allowed. If you want
|
||||
to allow additional arguments, you can use an ellipsis
|
||||
(<literal>...</literal>):
|
||||
(<literal>...</literal>):
|
||||
|
||||
<programlisting>
|
||||
{ x, y, z, ... }: z + y + x</programlisting>
|
||||
@@ -1164,7 +1158,7 @@ used in the Nix expression for Subversion.</para>
|
||||
</calloutlist>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
|
||||
|
||||
<simplesect><title>With-expressions</title>
|
||||
@@ -1174,9 +1168,8 @@ used in the Nix expression for Subversion.</para>
|
||||
<programlisting>
|
||||
with <replaceable>e1</replaceable>; <replaceable>e2</replaceable></programlisting>
|
||||
|
||||
introduces the attribute set <replaceable>e1</replaceable> into the
|
||||
lexical scope of the expression <replaceable>e2</replaceable>. For
|
||||
instance,
|
||||
introduces the set <replaceable>e1</replaceable> into the lexical
|
||||
scope of the expression <replaceable>e2</replaceable>. For instance,
|
||||
|
||||
<programlisting>
|
||||
let as = { x = "foo"; y = "bar"; };
|
||||
@@ -1235,7 +1228,7 @@ weakest binding).</para>
|
||||
</entry>
|
||||
<entry>none</entry>
|
||||
<entry>Select attribute denoted by the attribute path
|
||||
<replaceable>attrpath</replaceable> from attribute set
|
||||
<replaceable>attrpath</replaceable> from set
|
||||
<replaceable>e</replaceable>. (An attribute path is a
|
||||
dot-separated list of attribute names.) If the attribute
|
||||
doesn’t exist, return <replaceable>def</replaceable> if
|
||||
@@ -1251,8 +1244,8 @@ weakest binding).</para>
|
||||
<entry><replaceable>e</replaceable> <literal>?</literal>
|
||||
<replaceable>attrpath</replaceable></entry>
|
||||
<entry>none</entry>
|
||||
<entry>Test whether attribute set <replaceable>e</replaceable>
|
||||
contains the attribute denoted by <replaceable>attrpath</replaceable>;
|
||||
<entry>Test whether set <replaceable>e</replaceable> contains
|
||||
the attribute denoted by <replaceable>attrpath</replaceable>;
|
||||
return <literal>true</literal> or
|
||||
<literal>false</literal>.</entry>
|
||||
</row>
|
||||
@@ -1275,10 +1268,11 @@ weakest binding).</para>
|
||||
<entry><replaceable>e1</replaceable> <literal>//</literal>
|
||||
<replaceable>e2</replaceable></entry>
|
||||
<entry>right</entry>
|
||||
<entry>Return an attribute set consisting of the attributes in
|
||||
<entry>Return a set consisting of the attributes in
|
||||
<replaceable>e1</replaceable> and
|
||||
<replaceable>e2</replaceable> (with the latter taking
|
||||
precedence over the former in case of equally named attributes).</entry>
|
||||
precedence over the former in case of equally named
|
||||
attributes).</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><replaceable>e1</replaceable> <literal>==</literal>
|
||||
@@ -1322,9 +1316,9 @@ weakest binding).</para>
|
||||
<section xml:id="ssec-derivation"><title>Derivations</title>
|
||||
|
||||
<para>The most important built-in function is
|
||||
<function>derivation</function>, which is used to describe a
|
||||
single derivation (a build action). It takes as input an attribute
|
||||
set, the attributes of which specify the inputs of the build.</para>
|
||||
<function>derivation</function>, which is used to describe a single
|
||||
derivation (a build action). It takes as input a set, the attributes
|
||||
of which specify the inputs of the build.</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
@@ -1343,7 +1337,7 @@ set, the attributes of which specify the inputs of the build.</para>
|
||||
<listitem><para>There must be an attribute named
|
||||
<varname>name</varname> whose value must be a string. This is used
|
||||
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>
|
||||
|
||||
<listitem><para>There must be an attribute named
|
||||
@@ -1358,7 +1352,7 @@ set, the attributes of which specify the inputs of the build.</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para>Strings, URIs, and integers are just passed
|
||||
<listitem><para>Strings and integers are just passed
|
||||
verbatim.</para></listitem>
|
||||
|
||||
<listitem><para>A <emphasis>path</emphasis> (e.g.,
|
||||
@@ -1369,8 +1363,8 @@ set, the attributes of which specify the inputs of the build.</para>
|
||||
should reside in the Nix store.</para></listitem>
|
||||
|
||||
<listitem><para>A <emphasis>derivation</emphasis> causes that
|
||||
derivation to be built prior to the present derivation; the
|
||||
output path is put in the environment
|
||||
derivation to be built prior to the present derivation; its
|
||||
default output path is put in the environment
|
||||
variable.</para></listitem>
|
||||
|
||||
<listitem><para>Lists of the previous types are also allowed.
|
||||
@@ -1389,14 +1383,48 @@ set, the attributes of which specify the inputs of the build.</para>
|
||||
specifies command-line arguments to be passed to the builder. It
|
||||
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>
|
||||
|
||||
<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
|
||||
adds a default value for <varname>system</varname> and always uses
|
||||
Bash as the builder, to which the supplied builder is passed as a
|
||||
command-line argument. See <xref linkend='sec-standard-environment'
|
||||
/>.)</para>
|
||||
/>.</para>
|
||||
|
||||
<para>The builder is executed as follows:
|
||||
|
||||
@@ -1440,17 +1468,19 @@ command-line argument. See <xref linkend='sec-standard-environment'
|
||||
top-level Nix store directory (typically,
|
||||
<filename>/nix/store</filename>).</para></listitem>
|
||||
|
||||
<listitem><para><envar>out</envar> is set to point to the output
|
||||
path of the derivation, which is a subdirectory of the Nix store.
|
||||
The output path is a concatenation of the cryptographic hash of
|
||||
all build inputs, and the <varname>name</varname>
|
||||
attribute.</para></listitem>
|
||||
|
||||
<listitem><para>For each output declared in
|
||||
<varname>outputs</varname>, the corresponding environment variable
|
||||
is set to point to the intended path in the Nix store for that
|
||||
output. Each output path is a concatenation of the cryptographic
|
||||
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>
|
||||
|
||||
</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
|
||||
performing the same build at the same time.</para></listitem>
|
||||
|
||||
@@ -1464,14 +1494,11 @@ command-line argument. See <xref linkend='sec-standard-environment'
|
||||
<listitem><para>The temporary directory is removed (unless the
|
||||
<option>-K</option> option was specified).</para></listitem>
|
||||
|
||||
<listitem><para>If the build was successful, Nix scans the output
|
||||
for references to the paths of the inputs. These so-called
|
||||
<emphasis>retained dependencies</emphasis> could be used when the
|
||||
output of the derivation is used (e.g., when it's executed or used
|
||||
as input to another derivation), so if we deploy the derivation, we
|
||||
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>If the build was successful, Nix scans each output
|
||||
path for references to input paths by looking for the hash parts of
|
||||
the input paths. Since these are potential runtime dependencies,
|
||||
Nix registers them as dependencies of the output
|
||||
paths.</para></listitem>
|
||||
|
||||
<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
|
||||
@@ -1497,7 +1524,7 @@ attributes.</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><varname>allowedReferences</varname></term>
|
||||
|
||||
|
||||
<listitem><para>The optional attribute
|
||||
<varname>allowedReferences</varname> specifies a list of legal
|
||||
references (dependencies) of the output of the builder. For
|
||||
@@ -1515,7 +1542,7 @@ allowedReferences = [];
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><varname>exportReferencesGraph</varname></term>
|
||||
|
||||
<listitem><para>This attribute allows builders access to the
|
||||
@@ -1626,7 +1653,7 @@ stdenv.mkDerivation {
|
||||
outputHashMode = "flat";
|
||||
outputHashAlgo = "md5";
|
||||
outputHash = md5;
|
||||
|
||||
|
||||
inherit url;
|
||||
}
|
||||
</programlisting>
|
||||
@@ -1655,7 +1682,7 @@ stdenv.mkDerivation {
|
||||
<para>This is the default.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>"recursive"</literal></term>
|
||||
|
||||
<listitem><para>The hash is computed over the NAR archive dump
|
||||
@@ -1676,10 +1703,10 @@ stdenv.mkDerivation {
|
||||
linkend="sec-nix-hash"><command>nix-hash</command> command</link>
|
||||
for information about converting to and from base-32
|
||||
notation.)</para></listitem>
|
||||
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><varname>impureEnvVars</varname></term>
|
||||
|
||||
<listitem><para>This attribute allows you to specify a list of
|
||||
@@ -1706,7 +1733,7 @@ impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><varname>preferLocalBuild</varname></term>
|
||||
|
||||
<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)
|
||||
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
|
||||
. 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))
|
||||
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
|
||||
. 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 ""
|
||||
%define nix_user "nix"
|
||||
%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 ""
|
||||
%global nixbld_user "nix-builder-"
|
||||
%global nixbld_group "nix-builders"
|
||||
|
||||
Summary: The Nix software deployment system
|
||||
Name: nix
|
||||
Version: @version@
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: Software Deployment
|
||||
Release: 2%{?dist}
|
||||
License: LGPLv2+
|
||||
%if 0%{?rhel}
|
||||
Group: Applications/System
|
||||
%endif
|
||||
URL: http://nixos.org/
|
||||
Source0: %{name}-@version@.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
||||
Prefix: /usr
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
%if 0%{?el5}
|
||||
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: curl
|
||||
Requires: perl-DBD-SQLite
|
||||
Requires: perl-devel
|
||||
Requires: bzip2
|
||||
Requires: bzip2-libs
|
||||
Requires: sqlite
|
||||
Requires: gzip
|
||||
Requires: xz
|
||||
BuildRequires: bzip2-devel
|
||||
BuildRequires: sqlite-devel
|
||||
|
||||
@@ -31,7 +31,6 @@ BuildRequires: sqlite-devel
|
||||
Provides: perl(Nix::SSH)
|
||||
|
||||
%description
|
||||
|
||||
Nix is a purely functional package manager. It allows multiple
|
||||
versions of a package to be installed side-by-side, ensures that
|
||||
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
|
||||
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
|
||||
%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
|
||||
extraFlags=
|
||||
if test -n "%{enable_setuid}"; then
|
||||
extraFlags="$extraFlags --enable-setuid"
|
||||
if test -n "%{nix_user}"; then
|
||||
extraFlags="$extraFlags --with-nix-user=%{nix_user}"
|
||||
fi
|
||||
if test -n "%{nix_group}"; then
|
||||
extraFlags="$extraFlags --with-nix-group=%{nix_group}"
|
||||
fi
|
||||
fi
|
||||
./configure --prefix=%{_prefix} --sysconfdir=/etc $extraFlags
|
||||
make
|
||||
make check
|
||||
# - override docdir so large documentation files are owned by the
|
||||
# -doc subpackage
|
||||
# - set localstatedir by hand to the preferred nix value
|
||||
%configure --localstatedir=/nix/var \
|
||||
--docdir=%{_defaultdocdir}/%{name}-doc-%{version} \
|
||||
$extraFlags
|
||||
make %{?_smp_flags}
|
||||
%{_emacs_bytecompile} misc/emacs/nix-mode.el
|
||||
|
||||
|
||||
%install
|
||||
%if 0%{?el5}
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
%endif
|
||||
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
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%pre
|
||||
if test -n "%{nix_group_gid}"; then
|
||||
/usr/sbin/groupadd -g %{nix_group_gid} %{nix_group} || true
|
||||
fi
|
||||
if test -n "%{nix_user_uid}"; then
|
||||
/usr/sbin/useradd -c "Nix" -u %{nix_user_uid} \
|
||||
-s /sbin/nologin -r -d /var/empty %{nix_user} \
|
||||
-g %{nix_group} || true
|
||||
fi
|
||||
getent group %{nixbld_group} >/dev/null || groupadd -r %{nixbld_group}
|
||||
for i in $(seq 10);
|
||||
do
|
||||
getent passwd %{nixbld_user}$i >/dev/null || \
|
||||
useradd -r -g %{nixbld_group} -G %{nixbld_group} -d /var/empty \
|
||||
-s %{_sbindir}/nologin \
|
||||
-c "Nix build user $i" %{nixbld_user}$i
|
||||
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
|
||||
#%defattr(-,root,root)
|
||||
%{_prefix}/bin
|
||||
%{_prefix}/lib
|
||||
%{_prefix}/libexec
|
||||
%{_prefix}/include
|
||||
%{_prefix}/share
|
||||
/etc/profile.d/nix.sh
|
||||
/nix/var
|
||||
/nix/store
|
||||
%config
|
||||
/etc/nix
|
||||
%doc COPYING AUTHORS README
|
||||
%{_bindir}/nix-*
|
||||
%dir %{_libdir}/nix
|
||||
%{_libdir}/nix/*.so.*
|
||||
%{perl_vendorarch}/*
|
||||
%exclude %dir %{perl_vendorarch}/auto/
|
||||
%{_prefix}/libexec/*
|
||||
%if ! 0%{?rhel}
|
||||
%{_prefix}/lib/systemd/system/nix-daemon.service
|
||||
%endif
|
||||
%{_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=)
|
||||
|
||||
@@ -26,6 +26,7 @@ AM_CXXFLAGS = \
|
||||
-D_FILE_OFFSET_BITS=64
|
||||
|
||||
lib/Nix/Store.cc: lib/Nix/Store.xs
|
||||
$(INSTALL) -d lib/Nix
|
||||
xsubpp $^ -output $@
|
||||
|
||||
else
|
||||
|
||||
@@ -1,27 +1,39 @@
|
||||
package Nix::Config;
|
||||
|
||||
$version = "@version@";
|
||||
|
||||
$binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@";
|
||||
$stateDir = $ENV{"NIX_STATE_DIR"} || "@localstatedir@/nix";
|
||||
$manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests";
|
||||
$logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/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@";
|
||||
|
||||
$useBindings = "@perlbindings@" eq "yes";
|
||||
|
||||
%config = ();
|
||||
|
||||
sub readConfig {
|
||||
my %config;
|
||||
my $config = "@sysconfdir@/nix/nix.conf";
|
||||
if (defined $ENV{'_NIX_OPTIONS'}) {
|
||||
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;
|
||||
|
||||
|
||||
open CONFIG, "<$config" or die "cannot open `$config'";
|
||||
while (<CONFIG>) {
|
||||
/^\s*([\w|-]+)\s*=\s*(.*)$/ or next;
|
||||
$config{$1} = $2;
|
||||
print "|$1| -> |$2|\n";
|
||||
}
|
||||
close CONFIG;
|
||||
}
|
||||
|
||||
@@ -3,39 +3,50 @@ package Nix::CopyClosure;
|
||||
use strict;
|
||||
use Nix::Config;
|
||||
use Nix::Store;
|
||||
use List::Util qw(sum);
|
||||
|
||||
|
||||
sub copyTo {
|
||||
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign, $progressViewer) = @_;
|
||||
|
||||
$compressor = "$compressor |" if $compressor ne "";
|
||||
$decompressor = "$decompressor |" if $decompressor ne "";
|
||||
$progressViewer = "$progressViewer |" if $progressViewer ne "";
|
||||
my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor,
|
||||
$includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes) = @_;
|
||||
|
||||
# Get the closure of this path.
|
||||
my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs,
|
||||
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
|
||||
# to the command line length, do this in chunks. Eventually,
|
||||
# we'll want to use ‘--from-stdin’, but we can't rely on the
|
||||
# target having this option yet.
|
||||
my @missing = ();
|
||||
my $missingSize = 0;
|
||||
while (scalar(@closure) > 0) {
|
||||
my @ps = splice(@closure, 0, 1500);
|
||||
open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|");
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
push @missing, $_;
|
||||
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($_, 1);
|
||||
$missingSize += $narSize;
|
||||
}
|
||||
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.
|
||||
if (scalar @missing > 0) {
|
||||
print STDERR "copying ", scalar @missing, " missing paths to ‘$sshHost’...\n";
|
||||
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);
|
||||
close SSH or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
|
||||
+94
-28
@@ -2,6 +2,7 @@ package Nix::Manifest;
|
||||
|
||||
use strict;
|
||||
use DBI;
|
||||
use DBD::SQLite;
|
||||
use Cwd;
|
||||
use File::stat;
|
||||
use File::Path;
|
||||
@@ -9,12 +10,12 @@ use Fcntl ':flock';
|
||||
use Nix::Config;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch);
|
||||
our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch deleteOldManifests parseNARInfo);
|
||||
|
||||
|
||||
sub addNAR {
|
||||
my ($narFiles, $storePath, $info) = @_;
|
||||
|
||||
|
||||
$$narFiles{$storePath} = []
|
||||
unless defined $$narFiles{$storePath};
|
||||
|
||||
@@ -24,7 +25,7 @@ sub addNAR {
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
$found = 1 if $narFile->{url} eq $info->{url};
|
||||
}
|
||||
|
||||
|
||||
push @{$narFileList}, $info if !$found;
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ sub addPatch {
|
||||
$patch2->{url} eq $patch->{url} &&
|
||||
$patch2->{basePath} eq $patch->{basePath};
|
||||
}
|
||||
|
||||
|
||||
push @{$patchList}, $patch if !$found;
|
||||
|
||||
return !$found;
|
||||
@@ -68,7 +69,7 @@ sub readManifest_ {
|
||||
my $manifestVersion = 2;
|
||||
|
||||
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>) {
|
||||
chomp;
|
||||
@@ -93,10 +94,11 @@ sub readManifest_ {
|
||||
undef $system;
|
||||
$references = "";
|
||||
$deriver = "";
|
||||
}
|
||||
$compressionType = "bzip2";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (/^\}$/) {
|
||||
$inside = 0;
|
||||
|
||||
@@ -107,6 +109,7 @@ sub readManifest_ {
|
||||
, references => $references
|
||||
, deriver => $deriver
|
||||
, system => $system
|
||||
, compressionType => $compressionType
|
||||
});
|
||||
}
|
||||
|
||||
@@ -120,11 +123,12 @@ sub readManifest_ {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
|
||||
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
|
||||
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $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*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
|
||||
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
|
||||
@@ -172,6 +176,7 @@ sub writeManifest {
|
||||
print MANIFEST "{\n";
|
||||
print MANIFEST " StorePath: $storePath\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 " Size: $narFile->{size}\n" if defined $narFile->{size};
|
||||
print MANIFEST " NarHash: $narFile->{narHash}\n";
|
||||
@@ -184,7 +189,7 @@ sub writeManifest {
|
||||
print MANIFEST "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach my $storePath (sort (keys %{$patches})) {
|
||||
my $patchList = $$patches{$storePath};
|
||||
foreach my $patch (@{$patchList}) {
|
||||
@@ -201,8 +206,8 @@ sub writeManifest {
|
||||
print MANIFEST "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
close MANIFEST;
|
||||
|
||||
rename("$manifest.tmp", $manifest)
|
||||
@@ -211,11 +216,11 @@ sub writeManifest {
|
||||
|
||||
# Create a bzipped manifest.
|
||||
unless (defined $noCompress) {
|
||||
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
|
||||
or die "cannot compress manifest";
|
||||
system("$Nix::Config::bzip2 < $manifest > $manifest.bz2.tmp") == 0
|
||||
or die "cannot compress manifest";
|
||||
|
||||
rename("$manifest.bz2.tmp", "$manifest.bz2")
|
||||
or die "cannot rename $manifest.bz2.tmp: $!";
|
||||
rename("$manifest.bz2.tmp", "$manifest.bz2")
|
||||
or die "cannot rename $manifest.bz2.tmp: $!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,9 +228,13 @@ sub writeManifest {
|
||||
sub updateManifestDB {
|
||||
my $manifestDir = $Nix::Config::manifestDir;
|
||||
|
||||
my @manifests = glob "$manifestDir/*.nixmanifest";
|
||||
return undef if scalar @manifests == 0;
|
||||
|
||||
mkpath($manifestDir);
|
||||
|
||||
my $dbPath = "$manifestDir/cache.sqlite";
|
||||
|
||||
unlink "$manifestDir/cache.sqlite"; # remove obsolete cache
|
||||
my $dbPath = "$manifestDir/cache-v2.sqlite";
|
||||
|
||||
# Open/create the database.
|
||||
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
|
||||
@@ -245,13 +254,14 @@ sub updateManifestDB {
|
||||
timestamp integer not null
|
||||
);
|
||||
EOF
|
||||
|
||||
|
||||
$dbh->do(<<EOF);
|
||||
create table if not exists NARs (
|
||||
id integer primary key autoincrement not null,
|
||||
manifest integer not null,
|
||||
storePath text not null,
|
||||
url text not null,
|
||||
compressionType text not null,
|
||||
hash text,
|
||||
size integer,
|
||||
narHash text,
|
||||
@@ -292,8 +302,8 @@ EOF
|
||||
flock(MAINLOCK, LOCK_EX) or die;
|
||||
|
||||
our $insertNAR = $dbh->prepare(
|
||||
"insert into NARs(manifest, storePath, url, hash, size, narHash, " .
|
||||
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
|
||||
"insert into NARs(manifest, storePath, url, compressionType, hash, size, narHash, " .
|
||||
"narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
|
||||
|
||||
our $insertPatch = $dbh->prepare(
|
||||
"insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " .
|
||||
@@ -304,8 +314,8 @@ EOF
|
||||
# Read each manifest in $manifestDir and add it to the database,
|
||||
# unless we've already done so on a previous run.
|
||||
my %seen;
|
||||
|
||||
for my $manifestLink (glob "$manifestDir/*.nixmanifest") {
|
||||
|
||||
for my $manifestLink (@manifests) {
|
||||
my $manifest = Cwd::abs_path($manifestLink);
|
||||
next unless -f $manifest;
|
||||
my $timestamp = lstat($manifest)->mtime;
|
||||
@@ -316,9 +326,9 @@ EOF
|
||||
{}, $manifest, $timestamp)} == 1;
|
||||
|
||||
print STDERR "caching $manifest...\n";
|
||||
|
||||
|
||||
$dbh->do("delete from Manifests where path = ?", {}, $manifest);
|
||||
|
||||
|
||||
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)",
|
||||
{}, $manifest, $timestamp);
|
||||
|
||||
@@ -327,11 +337,11 @@ EOF
|
||||
sub addNARToDB {
|
||||
my ($storePath, $narFile) = @_;
|
||||
$insertNAR->execute(
|
||||
$id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size},
|
||||
$narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
|
||||
$id, $storePath, $narFile->{url}, $narFile->{compressionType}, $narFile->{hash},
|
||||
$narFile->{size}, $narFile->{narHash}, $narFile->{narSize}, $narFile->{references},
|
||||
$narFile->{deriver}, $narFile->{system});
|
||||
};
|
||||
|
||||
|
||||
sub addPatchToDB {
|
||||
my ($storePath, $patch) = @_;
|
||||
$insertPatch->execute(
|
||||
@@ -341,7 +351,7 @@ EOF
|
||||
};
|
||||
|
||||
my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB);
|
||||
|
||||
|
||||
if ($version < 3) {
|
||||
die "you have an old-style or corrupt manifest `$manifestLink'; please delete it\n";
|
||||
}
|
||||
@@ -364,4 +374,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;
|
||||
|
||||
@@ -44,6 +44,7 @@ sub closeSSHConnection {
|
||||
if ($sshStarted) {
|
||||
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
|
||||
or warn "unable to stop SSH master: $?";
|
||||
$sshStarted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-17
@@ -14,6 +14,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
|
||||
our @EXPORT = qw(
|
||||
isValidPath queryReferences queryPathInfo queryDeriver queryPathHash
|
||||
queryPathFromHashPart
|
||||
topoSortPaths computeFSClosure followLinksToStorePath exportPaths
|
||||
hashPath hashFile hashString
|
||||
addToStore makeFixedOutputPath
|
||||
@@ -41,50 +42,50 @@ if ($Nix::Config::useBindings) {
|
||||
use File::Temp;
|
||||
use Fcntl qw/F_SETFD/;
|
||||
|
||||
sub hashFile {
|
||||
*hashFile = sub {
|
||||
my ($algo, $base32, $path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub hashPath {
|
||||
};
|
||||
|
||||
*hashPath = sub {
|
||||
my ($algo, $base32, $path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub hashString {
|
||||
};
|
||||
|
||||
*hashString = sub {
|
||||
my ($algo, $base32, $s) = @_;
|
||||
my $fh = File::Temp->new();
|
||||
print $fh $s;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub addToStore {
|
||||
};
|
||||
|
||||
*addToStore = sub {
|
||||
my ($srcPath, $recursive, $algo) = @_;
|
||||
die "not implemented" if $recursive || $algo ne "sha256";
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub isValidPath {
|
||||
};
|
||||
|
||||
*isValidPath = sub {
|
||||
my ($path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
|
||||
chomp $res;
|
||||
return $res ne $path;
|
||||
}
|
||||
|
||||
sub queryPathHash {
|
||||
};
|
||||
|
||||
*queryPathHash = sub {
|
||||
my ($path) = @_;
|
||||
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
|
||||
chomp $res;
|
||||
return $res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
+27
-12
@@ -15,11 +15,12 @@
|
||||
using namespace nix;
|
||||
|
||||
|
||||
void doInit()
|
||||
void doInit()
|
||||
{
|
||||
if (!store) {
|
||||
try {
|
||||
setDefaultsFromEnvironment();
|
||||
settings.processEnvironment();
|
||||
settings.lockCPU = false;
|
||||
store = openStore();
|
||||
} catch (Error & e) {
|
||||
croak(e.what());
|
||||
@@ -86,7 +87,7 @@ SV * queryDeriver(char * path)
|
||||
}
|
||||
|
||||
|
||||
SV * queryPathInfo(char * path)
|
||||
SV * queryPathInfo(char * path, int base32)
|
||||
PPCODE:
|
||||
try {
|
||||
doInit();
|
||||
@@ -95,7 +96,7 @@ SV * queryPathInfo(char * path)
|
||||
XPUSHs(&PL_sv_undef);
|
||||
else
|
||||
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)));
|
||||
mXPUSHi(info.registrationTime);
|
||||
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, ...)
|
||||
PPCODE:
|
||||
try {
|
||||
@@ -226,32 +238,35 @@ SV * derivationFromPath(char * drvPath)
|
||||
doInit();
|
||||
Derivation drv = derivationFromPath(*store, drvPath);
|
||||
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();
|
||||
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
||||
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second
|
||||
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
|
||||
|
||||
|
||||
AV * inputSrcs = newAV();
|
||||
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i)
|
||||
av_push(inputSrcs, newSVpv(i->c_str(), 0));
|
||||
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
|
||||
|
||||
|
||||
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
|
||||
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
|
||||
|
||||
|
||||
AV * args = newAV();
|
||||
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i)
|
||||
av_push(args, newSVpv(i->c_str(), 0));
|
||||
hv_stores(hash, "args", newRV((SV *) args));
|
||||
|
||||
|
||||
HV * env = newHV();
|
||||
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_stores(hash, "env", newRV((SV *) env));
|
||||
|
||||
|
||||
RETVAL = newRV_noinc((SV *)hash);
|
||||
} catch (Error & e) {
|
||||
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;
|
||||
}
|
||||
+120
-33
@@ -1,15 +1,19 @@
|
||||
{ nixpkgs ? <nixpkgs>
|
||||
, nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
||||
{ nix ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
|
||||
, officialRelease ? false
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
pkgs = import <nixpkgs> {};
|
||||
|
||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "x86_64-freebsd" "i686-freebsd" ];
|
||||
|
||||
|
||||
jobs = rec {
|
||||
|
||||
|
||||
tarball =
|
||||
with import nixpkgs {};
|
||||
with pkgs;
|
||||
|
||||
releaseTools.sourceTarball {
|
||||
name = "nix-tarball";
|
||||
@@ -19,7 +23,7 @@ let
|
||||
inherit officialRelease;
|
||||
|
||||
buildInputs =
|
||||
[ curl bison25 flex2535 perl libxml2 libxslt w3m bzip2
|
||||
[ curl bison flex2535 perl libxml2 libxslt w3m bzip2
|
||||
tetex dblatex nukeReferences pkgconfig sqlite git
|
||||
];
|
||||
|
||||
@@ -29,6 +33,7 @@ let
|
||||
--with-xml-flags=--nonet
|
||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||
'';
|
||||
|
||||
postUnpack = ''
|
||||
@@ -41,9 +46,18 @@ let
|
||||
export VARTEXFONTS=$TMPDIR/texfonts
|
||||
'';
|
||||
|
||||
distPhase =
|
||||
''
|
||||
runHook preDist
|
||||
make dist-gzip
|
||||
make dist-xz
|
||||
mkdir -p $out/tarballs
|
||||
cp *.tar.* $out/tarballs
|
||||
'';
|
||||
|
||||
preDist = ''
|
||||
make -C doc/manual install prefix=$out
|
||||
|
||||
|
||||
make -C doc/manual manual.pdf prefix=$out
|
||||
cp doc/manual/manual.pdf $out/manual.pdf
|
||||
|
||||
@@ -54,7 +68,7 @@ let
|
||||
# to Windows and Macs, so there should be no Linux binaries
|
||||
# in the closure).
|
||||
nuke-refs $out/manual.pdf
|
||||
|
||||
|
||||
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 release-notes $out/share/doc/nix/release-notes" >> $out/nix-support/hydra-build-products
|
||||
@@ -62,10 +76,9 @@ let
|
||||
};
|
||||
|
||||
|
||||
build =
|
||||
{ system ? "i686-linux" }:
|
||||
build = pkgs.lib.genAttrs systems (system:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.nixBuild {
|
||||
name = "nix";
|
||||
@@ -77,15 +90,54 @@ let
|
||||
--disable-init-state
|
||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||
--enable-gc
|
||||
--sysconfdir=/etc
|
||||
'';
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
makeFlags = "profiledir=$(out)/etc/profile.d";
|
||||
|
||||
installFlags = "sysconfdir=$(out)/etc";
|
||||
|
||||
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 =
|
||||
with import nixpkgs { system = "x86_64-linux"; };
|
||||
with import <nixpkgs> { system = "x86_64-linux"; };
|
||||
|
||||
releaseTools.coverageAnalysis {
|
||||
name = "nix-build";
|
||||
@@ -101,12 +153,13 @@ let
|
||||
--disable-init-state
|
||||
--with-dbi=${perlPackages.DBI}/${perl.libPrefix}
|
||||
--with-dbd-sqlite=${perlPackages.DBDSQLite}/${perl.libPrefix}
|
||||
--with-www-curl=${perlPackages.WWWCurl}/${perl.libPrefix}
|
||||
'';
|
||||
|
||||
dontInstall = false;
|
||||
|
||||
doInstallCheck = true;
|
||||
|
||||
|
||||
lcovFilter = [ "*/boost/*" "*-tab.*" ];
|
||||
|
||||
# We call `dot', and even though we just use it to
|
||||
@@ -115,55 +168,89 @@ let
|
||||
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_fedora16x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora16x86_64) 50;
|
||||
|
||||
rpm_opensuse103i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse103i386) 40;
|
||||
rpm_opensuse110i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.opensuse110i386) 50;
|
||||
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImageFuns: diskImageFuns.opensuse110x86_64) 50;
|
||||
rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) 60;
|
||||
rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) 60;
|
||||
rpm_fedora19i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora19i386) 70;
|
||||
rpm_fedora19x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora19x86_64) 70;
|
||||
|
||||
|
||||
|
||||
deb_debian60i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian60i386) 50;
|
||||
deb_debian60x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian60x86_64) 50;
|
||||
|
||||
deb_ubuntu1004i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1004i386) 50;
|
||||
deb_ubuntu1004x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1004x86_64) 50;
|
||||
deb_debian7i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian7i386) 60;
|
||||
deb_debian7x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian7x86_64) 60;
|
||||
|
||||
deb_ubuntu1010i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1010i386) 50;
|
||||
deb_ubuntu1010x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1010x86_64) 50;
|
||||
deb_ubuntu1110i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1110i386) 60;
|
||||
deb_ubuntu1110x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1110x86_64) 60;
|
||||
deb_ubuntu1204i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1204i386) 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;
|
||||
deb_ubuntu1310i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1310i386) 90;
|
||||
deb_ubuntu1310x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1310x86_64) 90;
|
||||
|
||||
|
||||
# System tests.
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
# Aggregate job containing the release-critical jobs.
|
||||
release = pkgs.releaseTools.aggregate {
|
||||
name = "nix-${tarball.version}";
|
||||
meta.description = "Release-critical builds";
|
||||
constituents =
|
||||
[ tarball
|
||||
build.i686-freebsd
|
||||
build.i686-linux
|
||||
build.x86_64-darwin
|
||||
build.x86_64-freebsd
|
||||
build.x86_64-linux
|
||||
binaryTarball.i686-freebsd
|
||||
binaryTarball.i686-linux
|
||||
binaryTarball.x86_64-darwin
|
||||
binaryTarball.x86_64-freebsd
|
||||
binaryTarball.x86_64-linux
|
||||
deb_debian7i386
|
||||
deb_debian7x86_64
|
||||
deb_ubuntu1304i386
|
||||
deb_ubuntu1304x86_64
|
||||
deb_ubuntu1310i386
|
||||
deb_ubuntu1310x86_64
|
||||
rpm_fedora19i386
|
||||
rpm_fedora19x86_64
|
||||
tests.remote_builds
|
||||
tests.nix_copy_closure
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
makeRPM_i686 = makeRPM "i686-linux";
|
||||
makeRPM_x86_64 = makeRPM "x86_64-linux";
|
||||
|
||||
makeRPM =
|
||||
makeRPM =
|
||||
system: diskImageFun: prio:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.rpmBuild rec {
|
||||
name = "nix-rpm-${diskImage.name}";
|
||||
name = "nix-rpm";
|
||||
src = jobs.tarball;
|
||||
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;
|
||||
meta.schedulingPriority = prio;
|
||||
postRPMInstall = "cd /tmp/rpmout/BUILD/nix-* && make installcheck";
|
||||
@@ -172,21 +259,21 @@ let
|
||||
|
||||
makeDeb_i686 = makeDeb "i686-linux";
|
||||
makeDeb_x86_64 = makeDeb "x86_64-linux";
|
||||
|
||||
|
||||
makeDeb =
|
||||
system: diskImageFun: prio:
|
||||
|
||||
with import nixpkgs { inherit system; };
|
||||
with import <nixpkgs> { inherit system; };
|
||||
|
||||
releaseTools.debBuild {
|
||||
name = "nix-deb";
|
||||
src = jobs.tarball;
|
||||
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;
|
||||
meta.schedulingPriority = prio;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
+7
-6
@@ -7,18 +7,18 @@ noinst_SCRIPTS = nix-profile.sh \
|
||||
find-runtime-roots.pl build-remote.pl nix-reduce-build \
|
||||
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) -d $(DESTDIR)$(sysconfdir)/profile.d
|
||||
$(INSTALL_PROGRAM) nix-profile.sh $(DESTDIR)$(sysconfdir)/profile.d/nix.sh
|
||||
install-exec-local: download-using-manifests.pl copy-from-other-stores.pl download-from-binary-cache.pl find-runtime-roots.pl
|
||||
$(INSTALL) -d $(DESTDIR)$(profiledir)
|
||||
$(INSTALL_DATA) nix-profile.sh $(DESTDIR)$(profiledir)/nix.sh
|
||||
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL) -d $(DESTDIR)$(libexecdir)/nix/substituters
|
||||
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix/substituters
|
||||
$(INSTALL_PROGRAM) copy-from-other-stores.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) -d $(DESTDIR)$(sysconfdir)/nix
|
||||
ln -sf nix-build $(DESTDIR)$(bindir)/nix-shell
|
||||
|
||||
include ../substitute.mk
|
||||
|
||||
@@ -29,6 +29,7 @@ EXTRA_DIST = nix-collect-garbage.in \
|
||||
nix-build.in \
|
||||
download-using-manifests.pl.in \
|
||||
copy-from-other-stores.pl.in \
|
||||
download-from-binary-cache.pl.in \
|
||||
nix-copy-closure.in \
|
||||
find-runtime-roots.pl.in \
|
||||
build-remote.pl.in \
|
||||
|
||||
+28
-23
@@ -6,6 +6,7 @@ use IO::Handle;
|
||||
use Nix::Config;
|
||||
use Nix::SSH qw/sshOpts openSSHConnection/;
|
||||
use Nix::CopyClosure;
|
||||
use Nix::Store;
|
||||
no warnings('once');
|
||||
|
||||
|
||||
@@ -18,7 +19,7 @@ no warnings('once');
|
||||
# less than the maximum load for that machine, we try to get an
|
||||
# exclusive lock on $currentLoad/$machine-$slot (without blocking).
|
||||
# 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 perform the build on $neededSystem.
|
||||
# - We release the exclusive lock on $currentLoad/$machine-$slot.
|
||||
@@ -45,8 +46,7 @@ sub all { $_ || return 0 for @_; 1 }
|
||||
# Initialisation.
|
||||
my $loadIncreased = 0;
|
||||
|
||||
my ($localSystem, $maxSilentTime, $printBuildTrace) = @ARGV;
|
||||
$maxSilentTime = 0 unless defined $maxSilentTime;
|
||||
my ($localSystem, $maxSilentTime, $printBuildTrace, $buildTimeout) = @ARGV;
|
||||
|
||||
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
|
||||
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
|
||||
@@ -102,14 +102,14 @@ REQ: while (1) {
|
||||
sendReply "decline";
|
||||
next;
|
||||
}
|
||||
|
||||
|
||||
# Acquire the exclusive lock on $currentLoad/main-lock.
|
||||
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
|
||||
my $mainLock = "$currentLoad/main-lock";
|
||||
sysopen MAINLOCK, "$mainLock", O_RDWR|O_CREAT, 0600 or die;
|
||||
flock(MAINLOCK, LOCK_EX) or die;
|
||||
|
||||
|
||||
|
||||
|
||||
while (1) {
|
||||
# Find all machine that can execute this build, i.e., that
|
||||
# support builds for the given platform and features, and are
|
||||
@@ -141,7 +141,7 @@ REQ: while (1) {
|
||||
close $slotLock;
|
||||
$slot++;
|
||||
}
|
||||
|
||||
|
||||
push @available, { machine => $cur, load => $load, free => $free }
|
||||
if $load < $cur->{maxJobs};
|
||||
}
|
||||
@@ -160,7 +160,7 @@ REQ: while (1) {
|
||||
if ($rightType && !$canBuildLocally) {
|
||||
sendReply "postpone";
|
||||
} else {
|
||||
sendReply "decline";
|
||||
sendReply "decline";
|
||||
}
|
||||
close MAINLOCK;
|
||||
next REQ;
|
||||
@@ -182,9 +182,9 @@ REQ: while (1) {
|
||||
|
||||
|
||||
# Select the best available machine and lock a free slot.
|
||||
my $selected = $available[0];
|
||||
my $selected = $available[0];
|
||||
my $machine = $selected->{machine};
|
||||
|
||||
|
||||
$slotLock = openSlotLock($machine, $selected->{free});
|
||||
flock($slotLock, LOCK_EX | LOCK_NB) or die;
|
||||
utime undef, undef, $slotLock;
|
||||
@@ -195,9 +195,13 @@ REQ: while (1) {
|
||||
# Connect to the selected machine.
|
||||
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
|
||||
$hostName = $machine->{hostName};
|
||||
last REQ if openSSHConnection $hostName;
|
||||
|
||||
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
|
||||
if (openSSHConnection($hostName)) {
|
||||
last REQ if system("ssh $hostName @sshOpts nix-builds-inhibited < /dev/null > /dev/null 2>&1") != 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -209,7 +213,6 @@ my @inputs = 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;
|
||||
|
||||
|
||||
@@ -257,7 +260,10 @@ close UPLOADLOCK;
|
||||
|
||||
|
||||
# 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 --option build-use-substitutes false";
|
||||
|
||||
# We let the remote side kill its process group when the connection is
|
||||
# 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,
|
||||
# in which case every child receives SIGHUP; however, `-tt' doesn't
|
||||
# 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
|
||||
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
|
||||
# denotes a permanent build failure (as opposed to an SSH problem
|
||||
# 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.
|
||||
foreach my $output (@outputs) {
|
||||
my $maybeSignRemote = "";
|
||||
$maybeSignRemote = "--sign" if $UID != 0;
|
||||
|
||||
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
|
||||
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
|
||||
or die "cannot copy $output from $hostName: $?";
|
||||
my @outputs2 = grep { !isValidPath($_) } @outputs;
|
||||
if (scalar @outputs2 > 0) {
|
||||
system("exec ssh $hostName @sshOpts 'nix-store --export @outputs2'" .
|
||||
"| NIX_HELD_LOCKS='@outputs2' @bindir@/nix-store --import > /dev/null") == 0
|
||||
or die("cannot copy paths " . join(", ", @outputs) . " from `$hostName': $?");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ foreach my $dir (@remoteStoresAll) {
|
||||
push @remoteStores, glob($dir);
|
||||
}
|
||||
|
||||
exit if scalar @remoteStores == 0;
|
||||
print "\n";
|
||||
|
||||
|
||||
$ENV{"NIX_REMOTE"} = "";
|
||||
|
||||
@@ -27,7 +30,7 @@ sub findStorePath {
|
||||
next unless -e $sourcePath || -l $sourcePath;
|
||||
$ENV{"NIX_DB_DIR"} = "$store/var/nix/db";
|
||||
return ($store, $sourcePath) if
|
||||
system("@bindir@/nix-store --check-validity $storePath") == 0;
|
||||
system("$binDir/nix-store --check-validity $storePath") == 0;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
@@ -36,42 +39,45 @@ sub findStorePath {
|
||||
if ($ARGV[0] eq "--query") {
|
||||
|
||||
while (<STDIN>) {
|
||||
my $cmd = $_; chomp $cmd;
|
||||
chomp;
|
||||
my ($cmd, @args) = split " ", $_;
|
||||
|
||||
if ($cmd eq "have") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
print STDOUT (defined findStorePath($storePath) ? "1\n" : "0\n");
|
||||
foreach my $storePath (@args) {
|
||||
print "$storePath\n" if defined findStorePath($storePath);
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
elsif ($cmd eq "info") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
my ($store, $sourcePath) = findStorePath($storePath);
|
||||
if (!defined $store) {
|
||||
foreach my $storePath (@args) {
|
||||
my ($store, $sourcePath) = findStorePath($storePath);
|
||||
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";
|
||||
next; # not an error
|
||||
print "$narSize\n";
|
||||
}
|
||||
print "1\n";
|
||||
|
||||
$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 "$deriver\n";
|
||||
print scalar @references, "\n";
|
||||
print "$_\n" foreach @references;
|
||||
print "$narSize\n";
|
||||
print "$narSize\n";
|
||||
print "\n";
|
||||
}
|
||||
|
||||
else { die "unknown command `$cmd'"; }
|
||||
@@ -80,13 +86,15 @@ if ($ARGV[0] eq "--query") {
|
||||
|
||||
|
||||
elsif ($ARGV[0] eq "--substitute") {
|
||||
die unless scalar @ARGV == 2;
|
||||
die unless scalar @ARGV == 3;
|
||||
my $storePath = $ARGV[1];
|
||||
my $destPath = $ARGV[2];
|
||||
my ($store, $sourcePath) = findStorePath $storePath;
|
||||
die unless $store;
|
||||
print "\n*** Copying `$storePath' from `$sourcePath'\n\n";
|
||||
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $storePath") == 0
|
||||
print STDERR "\n*** Copying `$storePath' from `$sourcePath'\n\n";
|
||||
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $destPath") == 0
|
||||
or die "cannot copy `$sourcePath' to `$storePath'";
|
||||
print "\n"; # no hash to verify
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,589 @@
|
||||
#! @perl@ -w @perlFlags@
|
||||
|
||||
use DBI;
|
||||
use DBD::SQLite;
|
||||
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::Manifest;
|
||||
use Nix::Store;
|
||||
use Nix::Utils;
|
||||
use POSIX qw(strftime);
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
@@ -15,9 +16,14 @@ my $logFile = "$Nix::Config::logDir/downloads";
|
||||
# estimating the expected download size.
|
||||
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.
|
||||
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.
|
||||
@@ -38,7 +44,7 @@ sub parseHash {
|
||||
# given path.
|
||||
sub computeSmallestDownload {
|
||||
my $targetPath = shift;
|
||||
|
||||
|
||||
# Build a graph of all store paths that might contribute to the
|
||||
# construction of $targetPath, and the special node "start". The
|
||||
# edges are either patch operations, or downloads of full NAR
|
||||
@@ -93,7 +99,7 @@ sub computeSmallestDownload {
|
||||
my $patchList = $dbh->selectall_arrayref(
|
||||
"select * from Patches where storePath = ?",
|
||||
{ Slice => {} }, $u);
|
||||
|
||||
|
||||
foreach my $patch (@{$patchList}) {
|
||||
if (isValidPath($patch->{basePath})) {
|
||||
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
|
||||
@@ -106,7 +112,7 @@ sub computeSmallestDownload {
|
||||
$hash =~ s/.*://;
|
||||
$hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash;
|
||||
}
|
||||
|
||||
|
||||
next if $hash ne $baseHash;
|
||||
}
|
||||
push @queue, $patch->{basePath};
|
||||
@@ -117,7 +123,7 @@ sub computeSmallestDownload {
|
||||
my $narFileList = $dbh->selectall_arrayref(
|
||||
"select * from NARs where storePath = ?",
|
||||
{ Slice => {} }, $u);
|
||||
|
||||
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
# !!! how to handle files whose size is not known in advance?
|
||||
# For now, assume some arbitrary size (1 GB).
|
||||
@@ -173,58 +179,56 @@ sub computeSmallestDownload {
|
||||
if ($ARGV[0] eq "--query") {
|
||||
|
||||
while (<STDIN>) {
|
||||
my $cmd = $_; chomp $cmd;
|
||||
chomp;
|
||||
my ($cmd, @args) = split " ", $_;
|
||||
|
||||
if ($cmd eq "have") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
print STDOUT (
|
||||
scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0
|
||||
? "1\n" : "0\n");
|
||||
foreach my $storePath (@args) {
|
||||
print "$storePath\n" if scalar @{$dbh->selectcol_arrayref("select 1 from NARs where storePath = ?", {}, $storePath)} > 0;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
elsif ($cmd eq "info") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
foreach my $storePath (@args) {
|
||||
|
||||
my $infos = $dbh->selectall_arrayref(
|
||||
"select * from NARs where storePath = ?",
|
||||
{ Slice => {} }, $storePath);
|
||||
|
||||
my $info;
|
||||
if (scalar @{$infos} > 0) {
|
||||
$info = @{$infos}[0];
|
||||
}
|
||||
else {
|
||||
print "0\n";
|
||||
next; # not an error
|
||||
}
|
||||
my $infos = $dbh->selectall_arrayref(
|
||||
"select * from NARs where storePath = ?",
|
||||
{ Slice => {} }, $storePath);
|
||||
|
||||
print "1\n";
|
||||
print "$info->{deriver}\n";
|
||||
my @references = split " ", $info->{refs};
|
||||
print scalar @references, "\n";
|
||||
print "$_\n" foreach @references;
|
||||
next unless scalar @{$infos} > 0;
|
||||
my $info = @{$infos}[0];
|
||||
|
||||
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;
|
||||
while (scalar @path > 0) {
|
||||
my $edge = pop @path;
|
||||
my $u = $edge->{start};
|
||||
my $v = $edge->{end};
|
||||
if ($edge->{type} eq "patch") {
|
||||
$downloadSize += $edge->{info}->{size} || 0;
|
||||
}
|
||||
elsif ($edge->{type} eq "narfile") {
|
||||
$downloadSize += $edge->{info}->{size} || 0;
|
||||
my @path = computeSmallestDownload $storePath;
|
||||
|
||||
my $downloadSize = 0;
|
||||
while (scalar @path > 0) {
|
||||
my $edge = pop @path;
|
||||
my $u = $edge->{start};
|
||||
my $v = $edge->{end};
|
||||
if ($edge->{type} eq "patch") {
|
||||
$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";
|
||||
|
||||
my $narSize = $info->{narSize} || 0;
|
||||
print "$narSize\n";
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
||||
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 $destPath = $ARGV[2];
|
||||
$fast = 0;
|
||||
|
||||
|
||||
@@ -273,16 +278,6 @@ $dbh->disconnect;
|
||||
my $curStep = 1;
|
||||
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;
|
||||
|
||||
while (scalar @path > 0) {
|
||||
@@ -314,13 +309,16 @@ while (scalar @path > 0) {
|
||||
|
||||
# Download the patch.
|
||||
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
|
||||
# the already present path) or a later step (for patch sequences).
|
||||
print STDERR " applying patch...\n";
|
||||
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) {
|
||||
# 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
|
||||
# into the target path.
|
||||
print STDERR " unpacking patched archive...\n";
|
||||
system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0
|
||||
or die "cannot unpack $tmpNar2 into `$v'";
|
||||
system("$Nix::Config::binDir/nix-store --restore $destPath < $tmpNar2") == 0
|
||||
or die "cannot unpack $tmpNar2 to `$v'\n";
|
||||
}
|
||||
|
||||
$finalNarHash = $patch->{narHash};
|
||||
@@ -338,24 +336,27 @@ while (scalar @path > 0) {
|
||||
|
||||
elsif ($edge->{type} eq "narfile") {
|
||||
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;
|
||||
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
|
||||
|
||||
# Download the archive.
|
||||
print STDERR " downloading archive...\n";
|
||||
my $narFilePath = downloadFile "$narFile->{url}";
|
||||
|
||||
checkURL $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) {
|
||||
# The archive will be used a base to a patch.
|
||||
system("$Nix::Config::bzip2 -d < '$narFilePath' > $tmpNar") == 0
|
||||
or die "cannot unpack `$narFilePath' into `$v'";
|
||||
system("$curl '$narFile->{url}' $decompressor > $tmpNar") == 0
|
||||
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
|
||||
} else {
|
||||
# Unpack the archive into the target path.
|
||||
print STDERR " unpacking archive...\n";
|
||||
system("$Nix::Config::bzip2 -d < '$narFilePath' | $Nix::Config::binDir/nix-store --restore '$v'") == 0
|
||||
or die "cannot unpack `$narFilePath' into `$v'";
|
||||
# Unpack the archive to the target path.
|
||||
system("$curl '$narFile->{url}' $decompressor | $Nix::Config::binDir/nix-store --restore '$destPath'") == 0
|
||||
or die "cannot download and unpack `$narFile->{url}' to `$v'\n";
|
||||
}
|
||||
|
||||
$finalNarHash = $narFile->{narHash};
|
||||
@@ -365,21 +366,10 @@ while (scalar @path > 0) {
|
||||
}
|
||||
|
||||
|
||||
# Make sure that the hash declared in the manifest matches what we
|
||||
# downloaded and unpacked.
|
||||
|
||||
if (defined $finalNarHash) {
|
||||
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";
|
||||
}
|
||||
# Tell Nix about the expected hash so it can verify it.
|
||||
die "cannot check integrity of the downloaded path since its hash is not known\n"
|
||||
unless defined $finalNarHash;
|
||||
print "$finalNarHash\n";
|
||||
|
||||
|
||||
print STDERR "\n";
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#! @perl@ -w
|
||||
#! @perl@ -w @perlFlags@
|
||||
|
||||
use strict;
|
||||
|
||||
my $procDir = "/proc";
|
||||
use Nix::Utils;
|
||||
use Nix::Config;
|
||||
|
||||
|
||||
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) {
|
||||
next unless $name =~ /^\d+$/;
|
||||
|
||||
my $process = "$procDir/$name";
|
||||
my $process = "/proc/$name";
|
||||
|
||||
#print STDERR "=== $process\n";
|
||||
|
||||
|
||||
my $target;
|
||||
print "$target\n" if $target = readlink "$process/exe";
|
||||
print "$target\n" if $target = readlink "$process/cwd";
|
||||
@@ -36,6 +36,13 @@ sub readProc {
|
||||
}
|
||||
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;
|
||||
@@ -58,18 +65,15 @@ readProc;
|
||||
lsof;
|
||||
|
||||
|
||||
sub readFile {
|
||||
my $path = shift;
|
||||
if (-e $path) {
|
||||
if (open FILE, "$path") {
|
||||
while (<FILE>) {
|
||||
print;
|
||||
}
|
||||
close FILE;
|
||||
}
|
||||
sub printFile {
|
||||
my ($fn) = @_;
|
||||
if (-e $fn) {
|
||||
print Nix::Utils::readFile($fn), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# This is rather NixOS-specific, so it probably shouldn't be here.
|
||||
readFile "/proc/sys/kernel/modprobe";
|
||||
readFile "/proc/sys/kernel/fbsplash";
|
||||
printFile "/proc/sys/kernel/modprobe";
|
||||
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
|
||||
+92
-50
@@ -3,23 +3,27 @@
|
||||
use strict;
|
||||
use Nix::Config;
|
||||
use Nix::Store;
|
||||
use Nix::Utils;
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
|
||||
my $dryRun = 0;
|
||||
my $verbose = 0;
|
||||
my $runEnv = 0;
|
||||
my $runEnv = $0 =~ /nix-shell$/;
|
||||
my $pure = 0;
|
||||
|
||||
my @instArgs = ();
|
||||
my @buildArgs = ();
|
||||
my @exprs = ();
|
||||
|
||||
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 $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";
|
||||
|
||||
my $outLink = "./result";
|
||||
@@ -33,29 +37,12 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
|
||||
my $arg = $ARGV[$n];
|
||||
|
||||
if ($arg eq "--help") {
|
||||
print STDERR <<EOF;
|
||||
Usage: nix-build [OPTION]... [FILE]...
|
||||
exec "man $myName" or die;
|
||||
}
|
||||
|
||||
`nix-build' builds the given Nix expressions (which
|
||||
default to ./default.nix if none are given). A symlink called
|
||||
`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
|
||||
elsif ($arg eq "--version") {
|
||||
print "$myName (Nix) $Nix::Config::version\n";
|
||||
exit 0;
|
||||
# '` hack
|
||||
}
|
||||
|
||||
elsif ($arg eq "--add-drv-link") {
|
||||
@@ -104,7 +91,7 @@ EOF
|
||||
$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++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @buildArgs, ($arg, $ARGV[$n]);
|
||||
@@ -114,30 +101,34 @@ EOF
|
||||
push @buildArgs, "--dry-run";
|
||||
$dryRun = 1;
|
||||
}
|
||||
|
||||
|
||||
elsif ($arg eq "--show-trace") {
|
||||
push @instArgs, $arg;
|
||||
}
|
||||
|
||||
|
||||
elsif ($arg eq "-") {
|
||||
@exprs = ("-");
|
||||
}
|
||||
|
||||
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
|
||||
push @buildArgs, $arg;
|
||||
push @instArgs, $arg;
|
||||
$verbose = 1;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--quiet") {
|
||||
|
||||
elsif ($arg eq "--quiet" || $arg eq "--repair") {
|
||||
push @buildArgs, $arg;
|
||||
push @instArgs, $arg;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--run-env") {
|
||||
|
||||
elsif ($arg eq "--run-env") { # obsolete
|
||||
$runEnv = 1;
|
||||
}
|
||||
|
||||
|
||||
elsif ($arg eq "--command") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
$envCommand = $ARGV[$n];
|
||||
$envCommand = "$ARGV[$n]\nexit $!";
|
||||
}
|
||||
|
||||
elsif ($arg eq "--exclude") {
|
||||
@@ -146,6 +137,10 @@ EOF
|
||||
push @envExclude, $ARGV[$n];
|
||||
}
|
||||
|
||||
elsif ($arg eq "--pure") {
|
||||
$pure = 1;
|
||||
}
|
||||
|
||||
elsif (substr($arg, 0, 1) eq "-") {
|
||||
push @buildArgs, $arg;
|
||||
}
|
||||
@@ -162,17 +157,22 @@ foreach my $expr (@exprs) {
|
||||
|
||||
# Instantiate.
|
||||
my @drvPaths;
|
||||
# !!! would prefer the perl 5.8.0 pipe open feature here.
|
||||
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
||||
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
|
||||
if (!close DRVPATHS) {
|
||||
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||
exit 1;
|
||||
if ($expr !~ /^\/.*\.drv$/) {
|
||||
# !!! would prefer the perl 5.8.0 pipe open feature here.
|
||||
my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
||||
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
|
||||
if (!close DRVPATHS) {
|
||||
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||
exit 1;
|
||||
}
|
||||
} else {
|
||||
push @drvPaths, $expr;
|
||||
}
|
||||
|
||||
if ($runEnv) {
|
||||
die "$0: ‘--run-env’ requires a single derivation\n" if scalar @drvPaths != 1;
|
||||
my $drvPath = readlink $drvPaths[0] or die "cannot read symlink `$drvPaths[0]'";
|
||||
die "$0: a single derivation is required\n" if scalar @drvPaths != 1;
|
||||
my $drvPath = $drvPaths[0];
|
||||
$drvPath = readlink $drvPath or die "cannot read symlink `$drvPath'" if -l $drvPath;
|
||||
my $drv = derivationFromPath($drvPath);
|
||||
|
||||
# Build or fetch all dependencies of the derivation.
|
||||
@@ -181,28 +181,70 @@ foreach my $expr (@exprs) {
|
||||
or die "$0: failed to build all dependencies\n";
|
||||
|
||||
# Set the environment.
|
||||
$ENV{'NIX_BUILD_TOP'} = $ENV{'TMPDIR'} || "/tmp";
|
||||
foreach (keys %{$drv->{env}}) {
|
||||
$ENV{$_} = $drv->{env}->{$_};
|
||||
if ($pure) {
|
||||
foreach my $name (keys %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
|
||||
# convenience, source $stdenv/setup to setup additional
|
||||
# environment variables. Also don't lose the current $PATH
|
||||
# directories.
|
||||
exec($ENV{SHELL}, "-c", $envCommand);
|
||||
# environment variables and shell functions. Also don't lose
|
||||
# the current $PATH directories.
|
||||
my $rcfile = "$tmpDir/rc";
|
||||
writeFile(
|
||||
$rcfile,
|
||||
'unset BASH_ENV; ' .
|
||||
'[ -n "$PS1" ] && [ -e ~/.bashrc ] && source ~/.bashrc; ' .
|
||||
($pure ? '' : 'p=$PATH; ' ) .
|
||||
'dontAddDisableDepTrack=1; ' .
|
||||
'[ -e $stdenv/setup ] && source $stdenv/setup; ' .
|
||||
($pure ? '' : 'PATH=$PATH:$p; ') .
|
||||
'set +e; ' .
|
||||
'[ -n "$PS1" ] && PS1="\n\[\033[1;32m\][nix-shell:\w]$\[\033[0m\] "; ' .
|
||||
'unset NIX_ENFORCE_PURITY; ' .
|
||||
'shopt -u nullglob; ' .
|
||||
$envCommand);
|
||||
$ENV{BASH_ENV} = $rcfile;
|
||||
exec($ENV{NIX_BUILD_SHELL} // "bash", "--rcfile", $rcfile);
|
||||
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) {
|
||||
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;
|
||||
if ($target eq $prevDrvPath) {
|
||||
push @drvPaths2, (pop @drvPaths2) . "," . $output;
|
||||
} else {
|
||||
push @drvPaths2, $target . "!" . $output;
|
||||
$prevDrvPath = $target;
|
||||
}
|
||||
}
|
||||
|
||||
# Build.
|
||||
my @outPaths;
|
||||
$pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
|
||||
@buildArgs, @drvPaths;
|
||||
my $pid = open(OUTPATHS, "-|") || exec "$Nix::Config::binDir/nix-store", "--add-root", $outLink, "--indirect", "-r",
|
||||
@buildArgs, @drvPaths2;
|
||||
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
|
||||
if (!close OUTPATHS) {
|
||||
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||
|
||||
+46
-37
@@ -4,6 +4,9 @@ use strict;
|
||||
use File::Basename;
|
||||
use File::Path qw(mkpath);
|
||||
use Nix::Config;
|
||||
use Nix::Manifest;
|
||||
|
||||
Nix::Config::readConfig;
|
||||
|
||||
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 $profile = "$Nix::Config::stateDir/profiles/per-user/$userName/channels";
|
||||
mkpath(dirname $profile, 0, 0755);
|
||||
|
||||
|
||||
my %channels;
|
||||
|
||||
|
||||
@@ -65,11 +68,13 @@ sub addChannel {
|
||||
sub removeChannel {
|
||||
my ($name) = @_;
|
||||
readChannels;
|
||||
my $url = $channels{$name};
|
||||
deleteOldManifests($url . "/MANIFEST", undef) if defined $url;
|
||||
delete $channels{$name};
|
||||
writeChannels;
|
||||
|
||||
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.
|
||||
sub update {
|
||||
my @channelNames = @_;
|
||||
|
||||
|
||||
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.
|
||||
my $exprs = "";
|
||||
foreach my $name (keys %channels) {
|
||||
next if scalar @channelNames > 0 && ! grep { $_ eq $name } @{channelNames};
|
||||
|
||||
|
||||
my $url = $channels{$name};
|
||||
my $origUrl = "$url/MANIFEST";
|
||||
|
||||
@@ -101,17 +100,34 @@ sub update {
|
||||
die "$0: unable to check `$url'\n" if $? != 0;
|
||||
$headers =~ s/\r//g;
|
||||
$url = $1 if $headers =~ /^Location:\s*(.*)\s*$/m;
|
||||
|
||||
# Pull the channel manifest.
|
||||
$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";
|
||||
|
||||
# Check if the channel advertises a binary cache.
|
||||
my $binaryCacheURL = `$Nix::Config::curl --silent '$url'/binary-cache-url`;
|
||||
my $extraAttrs = "";
|
||||
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.
|
||||
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";
|
||||
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;
|
||||
|
||||
# If the URL contains a version number, append it to the name
|
||||
@@ -120,7 +136,7 @@ sub update {
|
||||
my $cname = $name;
|
||||
$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
|
||||
@@ -139,26 +155,14 @@ sub update {
|
||||
}
|
||||
|
||||
|
||||
sub usageError {
|
||||
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;
|
||||
die "$0: argument expected\n" if scalar @ARGV == 0;
|
||||
|
||||
|
||||
while (scalar @ARGV) {
|
||||
my $arg = shift @ARGV;
|
||||
|
||||
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 $name = shift @ARGV;
|
||||
unless (defined $name) {
|
||||
@@ -171,13 +175,13 @@ while (scalar @ARGV) {
|
||||
}
|
||||
|
||||
if ($arg eq "--remove") {
|
||||
usageError if scalar @ARGV != 1;
|
||||
die "$0: `--remove' requires one argument\n" if scalar @ARGV != 1;
|
||||
removeChannel(shift @ARGV);
|
||||
last;
|
||||
}
|
||||
|
||||
if ($arg eq "--list") {
|
||||
usageError if scalar @ARGV != 0;
|
||||
die "$0: `--list' requires one argument\n" if scalar @ARGV != 0;
|
||||
readChannels;
|
||||
foreach my $name (keys %channels) {
|
||||
print "$name $channels{$name}\n";
|
||||
@@ -189,12 +193,17 @@ while (scalar @ARGV) {
|
||||
update(@ARGV);
|
||||
last;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
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.
|
||||
my @args = ();
|
||||
my $removeOld = 0;
|
||||
my $dryRun = 0;
|
||||
|
||||
for my $arg (@ARGV) {
|
||||
if ($arg eq "--delete-old" || $arg eq "-d") {
|
||||
$removeOld = 1;
|
||||
} elsif ($arg eq "--dry-run") {
|
||||
$dryRun = 1;
|
||||
} elsif ($arg eq "--help") {
|
||||
exec "man nix-collect-garbage" or die;
|
||||
} else {
|
||||
push @args, $arg;
|
||||
}
|
||||
@@ -35,13 +40,13 @@ sub removeOldGenerations {
|
||||
$name = $dir . "/" . $name;
|
||||
if (-l $name && (readlink($name) =~ /link/)) {
|
||||
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) {
|
||||
removeOldGenerations $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
closedir $dh or die;
|
||||
}
|
||||
|
||||
@@ -49,4 +54,4 @@ removeOldGenerations $profilesDir if $removeOld;
|
||||
|
||||
|
||||
# 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::Store;
|
||||
use Nix::CopyClosure;
|
||||
use List::Util qw(sum);
|
||||
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
@@ -17,19 +18,14 @@ EOF
|
||||
|
||||
# Get the target host.
|
||||
my $sshHost;
|
||||
|
||||
my $sign = 0;
|
||||
|
||||
my $compressor = "";
|
||||
my $decompressor = "";
|
||||
|
||||
my $progressViewer = "";
|
||||
|
||||
my $toMode = 1;
|
||||
|
||||
my $includeOutputs = 0;
|
||||
|
||||
my $dryRun = 0;
|
||||
my $useSubstitutes = 0;
|
||||
|
||||
|
||||
# !!! Copied from nix-pack-closure, should put this in a module.
|
||||
@@ -37,8 +33,11 @@ my @storePaths = ();
|
||||
|
||||
while (@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;
|
||||
}
|
||||
elsif ($arg eq "--gzip") {
|
||||
@@ -68,6 +67,9 @@ while (@ARGV) {
|
||||
elsif ($arg eq "--dry-run") {
|
||||
$dryRun = 1;
|
||||
}
|
||||
elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
|
||||
$useSubstitutes = 1;
|
||||
}
|
||||
elsif (!defined $sshHost) {
|
||||
$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";
|
||||
|
||||
|
||||
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.
|
||||
@@ -92,7 +98,7 @@ else { # Copy FROM the remote machine.
|
||||
my $extraOpts = $includeOutputs ? "--include-outputs" : "";
|
||||
my $pid = open(READ,
|
||||
"set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;
|
||||
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
@@ -101,15 +107,23 @@ else { # Copy FROM the remote machine.
|
||||
|
||||
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.
|
||||
if (scalar @missing > 0) {
|
||||
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) {
|
||||
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" : "";
|
||||
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: $?";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,27 +3,11 @@
|
||||
use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
use Nix::Config;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
use Nix::Utils;
|
||||
|
||||
|
||||
# Parse the command line arguments.
|
||||
my @args = @ARGV;
|
||||
usageError if scalar @args == 0;
|
||||
|
||||
my $source;
|
||||
my $fromURL = 0;
|
||||
@@ -33,14 +17,14 @@ my $interactive = 1;
|
||||
while (scalar @args) {
|
||||
my $arg = shift @args;
|
||||
if ($arg eq "--help") {
|
||||
usageError;
|
||||
exec "man nix-install-package" or die;
|
||||
}
|
||||
elsif ($arg eq "--url") {
|
||||
$fromURL = 1;
|
||||
}
|
||||
elsif ($arg eq "--profile" || $arg eq "-p") {
|
||||
my $profile = shift @args;
|
||||
usageError if !defined $profile;
|
||||
die "$0: `--profile' requires an argument\n" if !defined $profile;
|
||||
push @extraNixEnvArgs, "-p", $profile;
|
||||
}
|
||||
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
|
||||
@@ -72,7 +56,7 @@ my $tmpDir = tempdir("nix-install-package.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
|
||||
sub barf {
|
||||
my $msg = shift;
|
||||
print "$msg\n";
|
||||
print "\nInstallation failed: $msg\n";
|
||||
<STDIN> if $interactive;
|
||||
exit 1;
|
||||
}
|
||||
@@ -92,7 +76,6 @@ open PKGFILE, "<$pkgFile" or barf "cannot open `$pkgFile': $!";
|
||||
my $contents = <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 $systemRE = "(?: [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.
|
||||
|
||||
$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";
|
||||
my $version = $1;
|
||||
my $manifestURL = $2;
|
||||
@@ -109,6 +92,7 @@ my $drvName = $3;
|
||||
my $system = $4;
|
||||
my $drvPath = $5;
|
||||
my $outPath = $6;
|
||||
my $binaryCacheURL = $8;
|
||||
|
||||
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
|
||||
# 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} = "";
|
||||
if (defined $binaryCacheURL) {
|
||||
|
||||
push @extraNixEnvArgs, "--option", "binary-caches", $binaryCacheURL;
|
||||
|
||||
print "\nPulling manifests...\n";
|
||||
system("$Nix::Config::binDir/nix-pull", $manifestURL) == 0
|
||||
or barf "nix-pull failed: $?";
|
||||
} else {
|
||||
|
||||
# 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";
|
||||
|
||||
+21
-19
@@ -6,12 +6,30 @@ use File::Temp qw(tempdir);
|
||||
use File::stat;
|
||||
use Nix::Store;
|
||||
use Nix::Config;
|
||||
use Nix::Utils;
|
||||
|
||||
my $url = shift;
|
||||
my $expHash = shift;
|
||||
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256";
|
||||
my $hashType = $ENV{'NIX_HASH_ALGO'} || "sha256"; # obsolete
|
||||
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 "") {
|
||||
print STDERR <<EOF
|
||||
Usage: nix-prefetch-url URL [EXPECTED-HASH]
|
||||
@@ -20,22 +38,6 @@ EOF
|
||||
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)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
if test -n "$HOME"; then
|
||||
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
|
||||
_NIX_DEF_LINK=@localstatedir@/nix/profiles/default
|
||||
@coreutils@/ln -s "$_NIX_DEF_LINK" "$NIX_LINK"
|
||||
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
|
||||
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'";
|
||||
print URL $origUrl;
|
||||
close URL;
|
||||
|
||||
|
||||
my $finalPath = "$manifestDir/$baseName-$hash.nixmanifest";
|
||||
|
||||
unlink $finalPath if -e $finalPath;
|
||||
|
||||
|
||||
symlink("$manifest", "$finalPath")
|
||||
or die "cannot link `$finalPath to `$manifest'";
|
||||
|
||||
# Delete all old manifests downloaded from this URL.
|
||||
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";
|
||||
}
|
||||
deleteOldManifests($origUrl, $urlFile);
|
||||
}
|
||||
|
||||
while (@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.
|
||||
} else {
|
||||
processURL $url;
|
||||
|
||||
+189
-195
@@ -1,85 +1,85 @@
|
||||
#! @perl@ -w @perlFlags@
|
||||
|
||||
use strict;
|
||||
use File::Basename;
|
||||
use File::Temp qw(tempdir);
|
||||
use File::Path qw(mkpath);
|
||||
use File::stat;
|
||||
use File::Copy;
|
||||
use Nix::Config;
|
||||
use Nix::Store;
|
||||
use Nix::Manifest;
|
||||
|
||||
my $hashAlgo = "sha256";
|
||||
use Nix::Utils;
|
||||
|
||||
my $tmpDir = tempdir("nix-push.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
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.
|
||||
my $localCopy;
|
||||
my $localArchivesDir;
|
||||
my $localManifestFile;
|
||||
my $compressionType = "xz";
|
||||
my $force = 0;
|
||||
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;
|
||||
my $archivesGetURL;
|
||||
my $manifestPutURL;
|
||||
|
||||
sub showSyntax {
|
||||
print STDERR <<EOF
|
||||
Usage: nix-push --copy ARCHIVES_DIR MANIFEST_FILE PATHS...
|
||||
or: nix-push ARCHIVES_PUT_URL ARCHIVES_GET_URL MANIFEST_PUT_URL PATHS...
|
||||
|
||||
`nix-push' copies or uploads the closure of PATHS to the given
|
||||
destination.
|
||||
EOF
|
||||
; # `
|
||||
exit 1;
|
||||
}
|
||||
|
||||
showSyntax if scalar @ARGV < 1;
|
||||
|
||||
if ($ARGV[0] eq "--copy") {
|
||||
showSyntax if scalar @ARGV < 3;
|
||||
$localCopy = 1;
|
||||
shift @ARGV;
|
||||
$localArchivesDir = shift @ARGV;
|
||||
$localManifestFile = shift @ARGV;
|
||||
if ($ARGV[0] eq "--target") {
|
||||
shift @ARGV;
|
||||
$targetArchivesUrl = shift @ARGV;
|
||||
}
|
||||
else {
|
||||
$targetArchivesUrl = "file://$localArchivesDir";
|
||||
if ($arg eq "--help") {
|
||||
exec "man nix-push" or die;
|
||||
} elsif ($arg eq "--bzip2") {
|
||||
$compressionType = "bzip2";
|
||||
} elsif ($arg eq "--none") {
|
||||
$compressionType = "none";
|
||||
} elsif ($arg eq "--force") {
|
||||
$force = 1;
|
||||
} elsif ($arg eq "--dest") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
$destDir = $ARGV[$n];
|
||||
mkpath($destDir, 0, 0755);
|
||||
} elsif ($arg eq "--manifest") {
|
||||
$writeManifest = 1;
|
||||
} elsif ($arg eq "--manifest-path") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
$manifestPath = $ARGV[$n];
|
||||
$writeManifest = 1;
|
||||
mkpath(dirname($manifestPath), 0, 0755);
|
||||
} elsif ($arg eq "--url-prefix") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
$archivesURL = $ARGV[$n];
|
||||
} elsif ($arg eq "--link") {
|
||||
$link = 1;
|
||||
} elsif (substr($arg, 0, 1) eq "-") {
|
||||
die "$0: unknown flag `$arg'\n";
|
||||
} else {
|
||||
push @roots, $arg;
|
||||
}
|
||||
}
|
||||
else {
|
||||
showSyntax if scalar @ARGV < 3;
|
||||
$localCopy = 0;
|
||||
$archivesPutURL = shift @ARGV;
|
||||
$archivesGetURL = shift @ARGV;
|
||||
$manifestPutURL = shift @ARGV;
|
||||
}
|
||||
|
||||
die "$0: please specify a destination directory\n" if !defined $destDir;
|
||||
|
||||
$archivesURL = "file://$destDir" unless defined $archivesURL;
|
||||
|
||||
|
||||
# From the given store paths, determine the set of requisite store
|
||||
# paths, i.e, the paths required to realise them.
|
||||
my %storePaths;
|
||||
|
||||
foreach my $path (@ARGV) {
|
||||
die unless $path =~ /^\//;
|
||||
|
||||
# Get all paths referenced by the normalisation of the given
|
||||
foreach my $path (@roots) {
|
||||
# Get all paths referenced by the normalisation of the given
|
||||
# Nix expression.
|
||||
my $pid = open(READ,
|
||||
"$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
|
||||
"--include-outputs '$path'|") or die;
|
||||
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
@@ -92,19 +92,50 @@ foreach my $path (@ARGV) {
|
||||
my @storePaths = keys %storePaths;
|
||||
|
||||
|
||||
# For each path, create a Nix expression that turns the path into
|
||||
# a Nix archive.
|
||||
# Don't create archives for files that are already in the binary cache.
|
||||
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";
|
||||
print NIX "[";
|
||||
|
||||
foreach my $storePath (@storePaths) {
|
||||
foreach my $storePath (@storePaths2) {
|
||||
die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
|
||||
|
||||
# Construct a Nix expression that creates a Nix archive.
|
||||
my $nixexpr =
|
||||
my $nixexpr =
|
||||
"(import <nix/nar.nix> " .
|
||||
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"$hashAlgo\"; }) ";
|
||||
|
||||
"{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"sha256\"; compressionType = \"$compressionType\"; }) ";
|
||||
|
||||
print NIX $nixexpr;
|
||||
}
|
||||
|
||||
@@ -112,172 +143,135 @@ print NIX "]";
|
||||
close NIX;
|
||||
|
||||
|
||||
# Instantiate store derivations from the Nix expression.
|
||||
my @storeExprs;
|
||||
print STDERR "instantiating store derivations...\n";
|
||||
my $pid = open(READ, "$Nix::Config::binDir/nix-instantiate $nixExpr|")
|
||||
or die "cannot run nix-instantiate";
|
||||
# Build the Nix expression.
|
||||
print STDERR "building compressed archives...\n";
|
||||
my @narPaths;
|
||||
my $pid = open(READ, "$Nix::Config::binDir/nix-build $nixExpr -o $tmpDir/result |")
|
||||
or die "cannot run nix-build";
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die unless /^\//;
|
||||
push @storeExprs, $_;
|
||||
push @narPaths, $_;
|
||||
}
|
||||
close READ or die "nix-instantiate failed: $?";
|
||||
close READ or die "nix-build failed: $?";
|
||||
|
||||
|
||||
# Build the derivations.
|
||||
print STDERR "creating archives...\n";
|
||||
|
||||
my @narPaths;
|
||||
|
||||
my @tmp = @storeExprs;
|
||||
while (scalar @tmp > 0) {
|
||||
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: $?";
|
||||
# Write the cache info file.
|
||||
my $cacheInfoFile = "$destDir/nix-cache-info";
|
||||
if (! -e $cacheInfoFile) {
|
||||
open FILE, ">$cacheInfoFile" or die "cannot create $cacheInfoFile: $!";
|
||||
print FILE "StoreDir: $Nix::Config::storeDir\n";
|
||||
print FILE "WantMassQuery: 0\n"; # by default, don't hit this cache for "nix-env -qas"
|
||||
close FILE;
|
||||
}
|
||||
|
||||
|
||||
# Create the manifest.
|
||||
print STDERR "creating manifest...\n";
|
||||
# Copy the archives and the corresponding NAR info files.
|
||||
print STDERR "copying archives...\n";
|
||||
|
||||
my %narFiles;
|
||||
my %patches;
|
||||
my $totalNarSize = 0;
|
||||
my $totalCompressedSize = 0;
|
||||
|
||||
my @narArchives;
|
||||
for (my $n = 0; $n < scalar @storePaths; $n++) {
|
||||
my $storePath = $storePaths[$n];
|
||||
for (my $n = 0; $n < scalar @storePaths2; $n++) {
|
||||
my $storePath = $storePaths2[$n];
|
||||
my $narDir = $narPaths[$n];
|
||||
|
||||
$storePath =~ /\/([^\/]*)$/;
|
||||
my $basename = $1;
|
||||
defined $basename or die;
|
||||
my $baseName = basename $storePath;
|
||||
|
||||
open HASH, "$narDir/narbz2-hash" or die "cannot open narbz2-hash";
|
||||
my $narbz2Hash = <HASH>;
|
||||
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;
|
||||
# Get info about the store path.
|
||||
my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1);
|
||||
|
||||
# In some exceptional cases (such as VM tests that use the Nix
|
||||
# store of the host), the database doesn't contain the hash. So
|
||||
# compute it.
|
||||
if ($narHash =~ /^sha256:0*$/) {
|
||||
$narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 '$storePath'`;
|
||||
die "cannot hash `$storePath'" if $? != 0;
|
||||
my $nar = "$tmpDir/nar";
|
||||
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;
|
||||
$narHash = "sha256:$narHash";
|
||||
$narSize = stat("$nar")->size;
|
||||
unlink $nar or die;
|
||||
}
|
||||
|
||||
my $narSize = `$Nix::Config::binDir/nix-store --query --size '$storePath'`;
|
||||
die "cannot query size for `$storePath'" if $? != 0;
|
||||
chomp $narSize;
|
||||
$totalNarSize += $narSize;
|
||||
|
||||
my $url;
|
||||
if ($localCopy) {
|
||||
$url = "$targetArchivesUrl/$narName";
|
||||
} else {
|
||||
$url = "$archivesGetURL/$narName";
|
||||
# Get info about the compressed NAR.
|
||||
open HASH, "$narDir/nar-compressed-hash" or die "cannot open nar-compressed-hash";
|
||||
my $compressedHash = <HASH>;
|
||||
chomp $compressedHash;
|
||||
$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} = [
|
||||
{ url => $url
|
||||
, hash => "$hashAlgo:$narbz2Hash"
|
||||
, size => $narbz2Size
|
||||
{ url => "$archivesURL/$narName"
|
||||
, hash => "sha256:$compressedHash"
|
||||
, size => $compressedSize
|
||||
, compressionType => $compressionType
|
||||
, narHash => "$narHash"
|
||||
, narSize => $narSize
|
||||
, references => $references
|
||||
, references => join(" ", @{$refs})
|
||||
, 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 {
|
||||
my $src = shift;
|
||||
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: $?";
|
||||
}
|
||||
# Optionally write a manifest.
|
||||
writeManifest($manifestPath // "$destDir/MANIFEST", \%narFiles, \()) if $writeManifest;
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
|
||||
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
|
||||
SUBDIRS = boost libutil libstore libmain nix-store nix-hash \
|
||||
libexpr nix-instantiate nix-env nix-daemon nix-setuid-helper \
|
||||
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;
|
||||
}
|
||||
+26
-26
@@ -6,19 +6,18 @@
|
||||
namespace nix {
|
||||
|
||||
|
||||
// !!! Shouldn't we return a pointer to a Value?
|
||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
Bindings & autoArgs, Expr * e, Value & v)
|
||||
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
Bindings & autoArgs, Value & vIn)
|
||||
{
|
||||
Strings tokens = tokenizeString(attrPath, ".");
|
||||
Strings tokens = tokenizeString<Strings>(attrPath, ".");
|
||||
|
||||
Error attrError =
|
||||
Error(format("attribute selection path `%1%' does not match expression") % attrPath);
|
||||
|
||||
string curPath;
|
||||
|
||||
state.mkThunk_(v, e);
|
||||
|
||||
Value * v = &vIn;
|
||||
|
||||
foreach (Strings::iterator, i, tokens) {
|
||||
|
||||
if (!curPath.empty()) curPath += ".";
|
||||
@@ -27,47 +26,48 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
/* Is *i an index (integer) or a normal attribute name? */
|
||||
enum { apAttr, apIndex } apType = apAttr;
|
||||
string attr = *i;
|
||||
int attrIndex = -1;
|
||||
unsigned int attrIndex;
|
||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||
|
||||
/* Evaluate the expression. */
|
||||
Value vTmp;
|
||||
state.autoCallFunction(autoArgs, v, vTmp);
|
||||
v = vTmp;
|
||||
state.forceValue(v);
|
||||
Value * vNew = state.allocValue();
|
||||
state.autoCallFunction(autoArgs, *v, *vNew);
|
||||
v = vNew;
|
||||
state.forceValue(*v);
|
||||
|
||||
/* It should evaluate to either an attribute set or an
|
||||
expression, according to what is specified in the
|
||||
attrPath. */
|
||||
/* It should evaluate to either a set or an expression,
|
||||
according to what is specified in the attrPath. */
|
||||
|
||||
if (apType == apAttr) {
|
||||
|
||||
if (v.type != tAttrs)
|
||||
if (v->type != tAttrs)
|
||||
throw TypeError(
|
||||
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
||||
% curPath % showType(v));
|
||||
format("the expression selected by the selection path `%1%' should be a set but is %2%")
|
||||
% curPath % showType(*v));
|
||||
|
||||
Bindings::iterator a = v.attrs->find(state.symbols.create(attr));
|
||||
if (a == v.attrs->end())
|
||||
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
||||
if (a == v->attrs->end())
|
||||
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
||||
v = *a->value;
|
||||
v = &*a->value;
|
||||
}
|
||||
|
||||
else if (apType == apIndex) {
|
||||
|
||||
if (v.type != tList)
|
||||
if (v->type != tList)
|
||||
throw TypeError(
|
||||
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);
|
||||
|
||||
v = *v.list.elems[attrIndex];
|
||||
v = v->list.elems[attrIndex];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
#ifndef __ATTR_PATH_H
|
||||
#define __ATTR_PATH_H
|
||||
#pragma once
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
Bindings & autoArgs, Expr * e, Value & v);
|
||||
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
Bindings & autoArgs, Value & vIn);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__ATTR_PATH_H */
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#ifndef __COMMON_OPTS_H
|
||||
#define __COMMON_OPTS_H
|
||||
#pragma once
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
/* 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__COMMON_OPTS_H */
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef __EVAL_INLINE_H
|
||||
#define __EVAL_INLINE_H
|
||||
#pragma once
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
@@ -8,7 +7,6 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
LocalNoInlineNoReturn(void throwEvalError(const char * s))
|
||||
{
|
||||
throw EvalError(s);
|
||||
@@ -23,13 +21,16 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
|
||||
void EvalState::forceValue(Value & v)
|
||||
{
|
||||
if (v.type == tThunk) {
|
||||
ValueType saved = v.type;
|
||||
Env * env = v.thunk.env;
|
||||
Expr * expr = v.thunk.expr;
|
||||
try {
|
||||
v.type = tBlackhole;
|
||||
//checkInterrupt();
|
||||
v.thunk.expr->eval(*this, *v.thunk.env, v);
|
||||
expr->eval(*this, *env, v);
|
||||
} catch (Error & e) {
|
||||
v.type = saved;
|
||||
v.type = tThunk;
|
||||
v.thunk.env = env;
|
||||
v.thunk.expr = expr;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +45,7 @@ inline void EvalState::forceAttrs(Value & v)
|
||||
{
|
||||
forceValue(v);
|
||||
if (v.type != tAttrs)
|
||||
throwTypeError("value is %1% while an attribute set was expected", showType(v));
|
||||
throwTypeError("value is %1% while a set was expected", showType(v));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +56,4 @@ inline void EvalState::forceList(Value & v)
|
||||
throwTypeError("value is %1% while a list was expected", showType(v));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__EVAL_INLINE_H */
|
||||
|
||||
+236
-161
@@ -44,7 +44,7 @@ void Bindings::sort()
|
||||
{
|
||||
std::sort(begin(), end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Value & v)
|
||||
{
|
||||
@@ -116,7 +116,7 @@ string showType(const Value & v)
|
||||
case tString: return "a string";
|
||||
case tPath: return "a path";
|
||||
case tNull: return "null";
|
||||
case tAttrs: return "an attribute set";
|
||||
case tAttrs: return "a set";
|
||||
case tList: return "a list";
|
||||
case tThunk: return "a thunk";
|
||||
case tApp: return "a function application";
|
||||
@@ -136,16 +136,21 @@ EvalState::EvalState()
|
||||
, sType(symbols.create("type"))
|
||||
, sMeta(symbols.create("meta"))
|
||||
, sName(symbols.create("name"))
|
||||
, sValue(symbols.create("value"))
|
||||
, sSystem(symbols.create("system"))
|
||||
, sOverrides(symbols.create("__overrides"))
|
||||
, sOutputs(symbols.create("outputs"))
|
||||
, sOutputName(symbols.create("outputName"))
|
||||
, sIgnoreNulls(symbols.create("__ignoreNulls"))
|
||||
, repair(false)
|
||||
, baseEnv(allocEnv(128))
|
||||
, baseEnvDispl(0)
|
||||
, staticBaseEnv(false, 0)
|
||||
, baseEnvDispl(0)
|
||||
{
|
||||
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
|
||||
nrEvaluated = recursionDepth = maxRecursionDepth = 0;
|
||||
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
|
||||
deepestStack = (char *) -1;
|
||||
nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0;
|
||||
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
static bool gcInitialised = true;
|
||||
@@ -154,7 +159,7 @@ EvalState::EvalState()
|
||||
physical RAM, up to a maximum of 384 MiB) so that in most
|
||||
cases we don't need to garbage collect at all. (Collection
|
||||
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
|
||||
setting for this. Note that GC_expand_hp() causes a lot of
|
||||
virtual, but not physical (resident) memory to be
|
||||
@@ -179,9 +184,9 @@ EvalState::EvalState()
|
||||
|
||||
/* Initialise the Nix expression search path. */
|
||||
searchPathInsertionPoint = searchPath.end();
|
||||
Strings paths = tokenizeString(getEnv("NIX_PATH", ""), ":");
|
||||
Strings paths = tokenizeString<Strings>(getEnv("NIX_PATH", ""), ":");
|
||||
foreach (Strings::iterator, i, paths) addToSearchPath(*i);
|
||||
addToSearchPath("nix=" + nixDataDir + "/nix/corepkgs");
|
||||
addToSearchPath("nix=" + settings.nixDataDir + "/nix/corepkgs");
|
||||
searchPathInsertionPoint = searchPath.begin();
|
||||
|
||||
createBaseEnv();
|
||||
@@ -190,7 +195,6 @@ EvalState::EvalState()
|
||||
|
||||
EvalState::~EvalState()
|
||||
{
|
||||
assert(recursionDepth == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -219,6 +223,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
|
||||
of stack space, which is a real killer in the recursive
|
||||
evaluator. So here are some helper functions for throwing
|
||||
@@ -239,14 +249,9 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s))
|
||||
throw TypeError(s);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const string & s2))
|
||||
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
|
||||
{
|
||||
throw TypeError(format(s) % pos % s2);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
|
||||
{
|
||||
throw TypeError(format(s) % pos);
|
||||
throw TypeError(format(s) % s1 % s2);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
|
||||
@@ -254,16 +259,16 @@ LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
|
||||
throw AssertionError(format(s) % pos);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwUndefinedVarError(const char * s, const string & s1, const Pos & pos))
|
||||
{
|
||||
throw UndefinedVarError(format(s) % s1 % pos);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
|
||||
{
|
||||
e.addPrefix(format(s) % s2);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const Pos & pos))
|
||||
{
|
||||
e.addPrefix(format(s) % pos);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos))
|
||||
{
|
||||
e.addPrefix(format(s) % s2 % pos);
|
||||
@@ -283,7 +288,7 @@ void mkString(Value & v, const string & s, const PathSet & context)
|
||||
unsigned int n = 0;
|
||||
v.string.context = (const 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] = 0;
|
||||
}
|
||||
@@ -296,21 +301,29 @@ void mkPath(Value & v, const char * s)
|
||||
}
|
||||
|
||||
|
||||
inline Value * EvalState::lookupVar(Env * env, const VarRef & var)
|
||||
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
|
||||
{
|
||||
for (unsigned int l = var.level; l; --l, env = env->up) ;
|
||||
|
||||
if (var.fromWith) {
|
||||
while (1) {
|
||||
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
||||
if (j != env->values[0]->attrs->end())
|
||||
return j->value;
|
||||
if (env->prevWith == 0)
|
||||
throwEvalError("undefined variable `%1%'", var.name);
|
||||
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
|
||||
|
||||
if (!var.fromWith) return env->values[var.displ];
|
||||
|
||||
while (1) {
|
||||
if (!env->haveWithAttrs) {
|
||||
if (noEval) return 0;
|
||||
Value * v = allocValue();
|
||||
evalAttrs(*env->up, (Expr *) env->values[0], *v);
|
||||
env->values[0] = v;
|
||||
env->haveWithAttrs = true;
|
||||
}
|
||||
} else
|
||||
return env->values[var.displ];
|
||||
Bindings::iterator j = env->values[0]->attrs->find(var.name);
|
||||
if (j != env->values[0]->attrs->end()) {
|
||||
if (countCalls && j->pos) attrSelects[*j->pos]++;
|
||||
return j->value;
|
||||
}
|
||||
if (!env->prevWith)
|
||||
throwUndefinedVarError("undefined variable `%1%' at %2%", var.name, var.pos);
|
||||
for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -327,10 +340,10 @@ Env & EvalState::allocEnv(unsigned int size)
|
||||
nrValuesInEnvs += size;
|
||||
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)
|
||||
env->values[i] = 0;
|
||||
|
||||
|
||||
return *env;
|
||||
}
|
||||
|
||||
@@ -342,12 +355,12 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EvalState::mkList(Value & v, unsigned int length)
|
||||
{
|
||||
v.type = tList;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -395,7 +408,7 @@ unsigned long nrAvoided = 0;
|
||||
|
||||
Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
Value * v = state.lookupVar(&env, info);
|
||||
Value * v = state.lookupVar(&env, *this, true);
|
||||
/* The value might not be initialised in the environment yet.
|
||||
In that case, ignore it. */
|
||||
if (v) { nrAvoided++; return v; }
|
||||
@@ -424,19 +437,35 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
||||
|
||||
void EvalState::evalFile(const Path & path, Value & v)
|
||||
{
|
||||
FileEvalCache::iterator i = fileEvalCache.find(path);
|
||||
if (i == fileEvalCache.end()) {
|
||||
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
||||
Expr * e = parseExprFromFile(path);
|
||||
try {
|
||||
eval(e, v);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
|
||||
throw;
|
||||
}
|
||||
fileEvalCache[path] = v;
|
||||
} else
|
||||
FileEvalCache::iterator i;
|
||||
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
|
||||
v = i->second;
|
||||
return;
|
||||
}
|
||||
|
||||
Path path2 = resolveExprPath(path);
|
||||
if ((i = fileEvalCache.find(path2)) != fileEvalCache.end()) {
|
||||
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[path] = v;
|
||||
}
|
||||
|
||||
|
||||
void EvalState::resetFileCache()
|
||||
{
|
||||
fileEvalCache.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -460,7 +489,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v)
|
||||
{
|
||||
e->eval(*this, env, v);
|
||||
if (v.type != tAttrs)
|
||||
throwTypeError("value is %1% while an attribute set was expected", showType(v));
|
||||
throwTypeError("value is %1% while a set was expected", showType(v));
|
||||
}
|
||||
|
||||
|
||||
@@ -505,23 +534,17 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
environment, while the inherited attributes are evaluated
|
||||
in the original environment. */
|
||||
unsigned int displ = 0;
|
||||
foreach (AttrDefs::iterator, i, attrs)
|
||||
if (i->second.inherited) {
|
||||
/* !!! handle overrides? */
|
||||
Value * vAttr = state.lookupVar(&env, i->second.var);
|
||||
env2.values[displ++] = vAttr;
|
||||
v.attrs->push_back(Attr(i->first, vAttr, &i->second.pos));
|
||||
} else {
|
||||
Value * vAttr;
|
||||
if (hasOverrides) {
|
||||
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));
|
||||
}
|
||||
|
||||
foreach (AttrDefs::iterator, i, attrs) {
|
||||
Value * vAttr;
|
||||
if (hasOverrides && !i->second.inherited) {
|
||||
vAttr = state.allocValue();
|
||||
mkThunk(*vAttr, env2, i->second.e);
|
||||
} else
|
||||
vAttr = i->second.e->maybeThunk(state, i->second.inherited ? env : 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
|
||||
evaluate it, and add the attributes in that set to the rec.
|
||||
This allows overriding of recursive attributes, which is
|
||||
@@ -547,10 +570,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
else {
|
||||
foreach (AttrDefs::iterator, i, attrs)
|
||||
if (i->second.inherited)
|
||||
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));
|
||||
v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,10 +587,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
|
||||
environment. */
|
||||
unsigned int displ = 0;
|
||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||
if (i->second.inherited)
|
||||
env2.values[displ++] = state.lookupVar(&env, i->second.var);
|
||||
else
|
||||
env2.values[displ++] = i->second.e->maybeThunk(state, env2);
|
||||
env2.values[displ++] = i->second.e->maybeThunk(state, i->second.inherited ? env : env2);
|
||||
|
||||
body->eval(state, env2, v);
|
||||
}
|
||||
@@ -586,7 +603,7 @@ void ExprList::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, *this, false);
|
||||
state.forceValue(*v2);
|
||||
v = *v2;
|
||||
}
|
||||
@@ -603,7 +620,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
e->eval(state, env, vTmp);
|
||||
|
||||
try {
|
||||
|
||||
|
||||
foreach (AttrPath::const_iterator, i, attrPath) {
|
||||
nrLookups++;
|
||||
Bindings::iterator j;
|
||||
@@ -622,17 +639,18 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||
}
|
||||
vAttrs = j->value;
|
||||
pos = j->pos;
|
||||
if (state.countCalls && pos) state.attrSelects[*pos]++;
|
||||
}
|
||||
|
||||
|
||||
state.forceValue(*vAttrs);
|
||||
|
||||
|
||||
} catch (Error & e) {
|
||||
if (pos)
|
||||
if (pos && pos->file != state.sDerivationNix)
|
||||
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
|
||||
showAttrPath(attrPath), *pos);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
v = *vAttrs;
|
||||
}
|
||||
|
||||
@@ -656,7 +674,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||
vAttrs = j->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mkBool(v, true);
|
||||
}
|
||||
|
||||
@@ -691,10 +709,10 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
assert(primOp->type == tPrimOp);
|
||||
unsigned int arity = primOp->primOp->arity;
|
||||
unsigned int argsLeft = arity - argsDone;
|
||||
|
||||
|
||||
if (argsLeft == 1) {
|
||||
/* We have all the arguments, so call the primop. */
|
||||
|
||||
|
||||
/* Put all the arguments in an array. */
|
||||
Value * vArgs[arity];
|
||||
unsigned int n = arity - 1;
|
||||
@@ -703,12 +721,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
vArgs[n--] = arg->primOpApp.right;
|
||||
|
||||
/* And call the primop. */
|
||||
try {
|
||||
primOp->primOp->fun(*this, vArgs, v);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the builtin function `%1%':\n", primOp->primOp->name);
|
||||
throw;
|
||||
}
|
||||
nrPrimOpCalls++;
|
||||
if (countCalls) primOpCalls[primOp->primOp->name]++;
|
||||
primOp->primOp->fun(*this, vArgs, v);
|
||||
} else {
|
||||
v.type = tPrimOpApp;
|
||||
v.primOpApp.left = allocValue();
|
||||
@@ -717,9 +732,9 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
|
||||
unsigned int size =
|
||||
@@ -735,7 +750,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
|
||||
else {
|
||||
forceAttrs(arg);
|
||||
|
||||
|
||||
if (!fun.lambda.fun->arg.empty())
|
||||
env2.values[displ++] = &arg;
|
||||
|
||||
@@ -746,8 +761,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||
Bindings::iterator j = arg.attrs->find(i->name);
|
||||
if (j == arg.attrs->end()) {
|
||||
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
|
||||
fun.lambda.fun->pos, i->name);
|
||||
if (!i->def) throwTypeError("%1% called without required argument `%2%'",
|
||||
fun.lambda.fun->showNamePos(), i->name);
|
||||
env2.values[displ++] = i->def->maybeThunk(*this, env2);
|
||||
} else {
|
||||
attrsUsed++;
|
||||
@@ -756,17 +771,24 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||
}
|
||||
|
||||
/* Check that each actual argument is listed as a formal
|
||||
argument (unless the attribute match specifies a `...').
|
||||
TODO: show the names of the expected/unexpected
|
||||
arguments. */
|
||||
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
|
||||
throwTypeError("function at %1% called with unexpected argument", fun.lambda.fun->pos);
|
||||
argument (unless the attribute match specifies a `...'). */
|
||||
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size()) {
|
||||
/* Nope, so show the first unexpected argument to the
|
||||
user. */
|
||||
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 {
|
||||
fun.lambda.fun->body->eval(*this, env2, v);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -781,20 +803,20 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||
return;
|
||||
}
|
||||
|
||||
Value actualArgs;
|
||||
mkAttrs(actualArgs, fun.lambda.fun->formals->formals.size());
|
||||
Value * actualArgs = allocValue();
|
||||
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
||||
|
||||
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||
Bindings::iterator j = args.find(i->name);
|
||||
if (j != args.end())
|
||||
actualArgs.attrs->push_back(*j);
|
||||
actualArgs->attrs->push_back(*j);
|
||||
else if (!i->def)
|
||||
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 +825,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||
Env & env2(state.allocEnv(1));
|
||||
env2.up = &env;
|
||||
env2.prevWith = prevWith;
|
||||
|
||||
env2.values[0] = state.allocValue();
|
||||
state.evalAttrs(env, attrs, *env2.values[0]);
|
||||
env2.haveWithAttrs = false;
|
||||
env2.values[0] = (Value *) attrs;
|
||||
|
||||
body->eval(state, env2, v);
|
||||
}
|
||||
@@ -816,7 +837,7 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||
(state.evalBool(env, cond) ? then : else_)->eval(state, env, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
if (!state.evalBool(env, cond))
|
||||
@@ -824,7 +845,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
||||
body->eval(state, env, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
mkBool(v, !state.evalBool(env, e));
|
||||
@@ -878,9 +899,8 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
state.mkAttrs(v, v1.attrs->size() + v2.attrs->size());
|
||||
|
||||
/* Merge the attribute sets, preferring values from the second
|
||||
set. Make sure to keep the resulting vector in sorted
|
||||
order. */
|
||||
/* Merge the sets, preferring values from the second set. Make
|
||||
sure to keep the resulting vector in sorted order. */
|
||||
Bindings::iterator i = v1.attrs->begin();
|
||||
Bindings::iterator j = v2.attrs->begin();
|
||||
|
||||
@@ -897,7 +917,7 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
while (i != v1.attrs->end()) v.attrs->push_back(*i++);
|
||||
while (j != v2.attrs->end()) v.attrs->push_back(*j++);
|
||||
|
||||
|
||||
state.nrOpUpdateValuesCopied += v.attrs->size();
|
||||
}
|
||||
|
||||
@@ -905,14 +925,36 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
Value v1; e1->eval(state, env, v1);
|
||||
state.forceList(v1);
|
||||
Value v2; e2->eval(state, env, v2);
|
||||
state.forceList(v2);
|
||||
state.mkList(v, v1.list.length + v2.list.length);
|
||||
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];
|
||||
Value * lists[2] = { &v1, &v2 };
|
||||
state.concatLists(v, 2, lists);
|
||||
}
|
||||
|
||||
|
||||
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 +962,39 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
std::ostringstream s;
|
||||
|
||||
bool first = true, isPath = false;
|
||||
Value vStr;
|
||||
NixInt n = 0;
|
||||
|
||||
bool first = !forceString;
|
||||
ValueType firstType = tString;
|
||||
|
||||
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
|
||||
be a path, we don't copy anything (yet - that's done later,
|
||||
since paths are copied when they are used in a derivation),
|
||||
and none of the strings are allowed to have contexts. */
|
||||
if (first) {
|
||||
isPath = vStr.type == tPath;
|
||||
firstType = vTmp.type;
|
||||
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) {
|
||||
if (vTmp.type != tInt)
|
||||
throwEvalError("cannot add %1% to an integer", showType(vTmp));
|
||||
n += vTmp.integer;
|
||||
} else
|
||||
s << state.coerceToString(vTmp, context, false, firstType == tString);
|
||||
}
|
||||
|
||||
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());
|
||||
else
|
||||
} else
|
||||
mkString(v, s.str(), context);
|
||||
}
|
||||
|
||||
@@ -952,12 +1002,12 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||
void EvalState::strictForceValue(Value & v)
|
||||
{
|
||||
forceValue(v);
|
||||
|
||||
|
||||
if (v.type == tAttrs) {
|
||||
foreach (Bindings::iterator, i, *v.attrs)
|
||||
strictForceValue(*i->value);
|
||||
}
|
||||
|
||||
|
||||
else if (v.type == tList) {
|
||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
||||
strictForceValue(*v.list.elems[n]);
|
||||
@@ -965,7 +1015,7 @@ void EvalState::strictForceValue(Value & v)
|
||||
}
|
||||
|
||||
|
||||
int EvalState::forceInt(Value & v)
|
||||
NixInt EvalState::forceInt(Value & v)
|
||||
{
|
||||
forceValue(v);
|
||||
if (v.type != tInt)
|
||||
@@ -1003,7 +1053,7 @@ string EvalState::forceString(Value & v)
|
||||
void copyContext(const Value & v, PathSet & 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);
|
||||
}
|
||||
|
||||
@@ -1033,7 +1083,7 @@ bool EvalState::isDerivation(Value & v)
|
||||
if (i == v.attrs->end()) return false;
|
||||
forceValue(*i->value);
|
||||
if (i->value->type != tString) return false;
|
||||
return forceStringNoCtx(*i->value) == "derivation";
|
||||
return strcmp(i->value->string.s, "derivation") == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1053,7 +1103,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
||||
Path path(canonPath(v.path));
|
||||
|
||||
if (!copyToStore) return path;
|
||||
|
||||
|
||||
if (nix::isDerivation(path))
|
||||
throwEvalError("file names are not allowed to end in `%1%'", drvExtension);
|
||||
|
||||
@@ -1061,9 +1111,9 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
||||
if (srcToStore[path] != "")
|
||||
dstPath = srcToStore[path];
|
||||
else {
|
||||
dstPath = readOnlyMode
|
||||
dstPath = settings.readOnlyMode
|
||||
? computeStorePathForPath(path).first
|
||||
: store->addToStore(path);
|
||||
: store->addToStore(path, true, htSHA256, defaultPathFilter, repair);
|
||||
srcToStore[path] = dstPath;
|
||||
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
|
||||
% path % dstPath);
|
||||
@@ -1075,8 +1125,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
||||
|
||||
if (v.type == tAttrs) {
|
||||
Bindings::iterator i = v.attrs->find(sOutPath);
|
||||
if (i == v.attrs->end())
|
||||
throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
|
||||
if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string");
|
||||
return coerceToString(*i->value, context, coerceMore, copyToStore);
|
||||
}
|
||||
|
||||
@@ -1102,7 +1151,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throwTypeError("cannot coerce %1% to a string", showType(v));
|
||||
}
|
||||
|
||||
@@ -1122,9 +1171,8 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||
forceValue(v2);
|
||||
|
||||
/* !!! Hack to support some old broken code that relies on pointer
|
||||
equality tests between attribute sets. (Specifically,
|
||||
builderDefs calls uniqList on a list of attribute sets.) Will
|
||||
remove this eventually. */
|
||||
equality tests between sets. (Specifically, builderDefs calls
|
||||
uniqList on a list of sets.) Will remove this eventually. */
|
||||
if (&v1 == &v2) return true;
|
||||
|
||||
if (v1.type != v2.type) return false;
|
||||
@@ -1162,8 +1210,8 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||
return true;
|
||||
|
||||
case tAttrs: {
|
||||
/* If both attribute sets denote a derivation (type =
|
||||
"derivation"), then compare their outPaths. */
|
||||
/* If both sets denote a derivation (type = "derivation"),
|
||||
then compare their outPaths. */
|
||||
if (isDerivation(v1) && isDerivation(v2)) {
|
||||
Bindings::iterator i = v1.attrs->find(sOutPath);
|
||||
Bindings::iterator j = v2.attrs->find(sOutPath);
|
||||
@@ -1178,7 +1226,7 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||
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))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1206,25 +1254,52 @@ void EvalState::printStats()
|
||||
|
||||
printMsg(v, format(" time elapsed: %1%") % cpuTime);
|
||||
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)")
|
||||
% nrEnvs % (nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *)));
|
||||
printMsg(v, format(" list elements: %1% (%2% bytes)")
|
||||
% nrListElems % (nrListElems * sizeof(Value *)));
|
||||
printMsg(v, format(" list concatenations: %1%") % nrListConcats);
|
||||
printMsg(v, format(" values allocated: %1% (%2% bytes)")
|
||||
% nrValues % (nrValues * sizeof(Value)));
|
||||
printMsg(v, format(" attribute sets allocated: %1%") % nrAttrsets);
|
||||
printMsg(v, format(" sets allocated: %1%") % nrAttrsets);
|
||||
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
|
||||
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
|
||||
printMsg(v, format(" symbols in symbol table: %1%") % symbols.size());
|
||||
printMsg(v, format(" size of symbol table: %1%") % symbols.totalSize());
|
||||
printMsg(v, format(" number of thunks: %1%") % nrThunks);
|
||||
printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
|
||||
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) {
|
||||
v = lvlInfo;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+65
-42
@@ -1,5 +1,4 @@
|
||||
#ifndef __EVAL_H
|
||||
#define __EVAL_H
|
||||
#pragma once
|
||||
|
||||
#include "value.hh"
|
||||
#include "nixexpr.hh"
|
||||
@@ -20,8 +19,8 @@ class EvalState;
|
||||
struct Attr;
|
||||
|
||||
|
||||
/* Attribute sets are represented as a vector of attributes, sorted by
|
||||
symbol (i.e. pointer to the attribute name in the symbol table). */
|
||||
/* Sets are represented as a vector of attributes, sorted by symbol
|
||||
(i.e. pointer to the attribute name in the symbol table). */
|
||||
#if HAVE_BOEHMGC
|
||||
typedef std::vector<Attr, gc_allocator<Attr> > BindingsBase;
|
||||
#else
|
||||
@@ -53,7 +52,8 @@ struct PrimOp
|
||||
struct Env
|
||||
{
|
||||
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];
|
||||
};
|
||||
|
||||
@@ -88,19 +88,21 @@ struct EvalState;
|
||||
std::ostream & operator << (std::ostream & str, const Value & v);
|
||||
|
||||
|
||||
class EvalState
|
||||
class EvalState
|
||||
{
|
||||
public:
|
||||
SymbolTable symbols;
|
||||
|
||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName,
|
||||
sSystem, sOverrides;
|
||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
|
||||
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls;
|
||||
Symbol sDerivationNix;
|
||||
|
||||
/* If set, force copying files to the Nix store even if they
|
||||
already exist there. */
|
||||
bool repair;
|
||||
|
||||
private:
|
||||
SrcToStore srcToStore;
|
||||
|
||||
/* A cache from path names to parse trees. */
|
||||
std::map<Path, Expr *> parseTrees;
|
||||
SrcToStore srcToStore;
|
||||
|
||||
/* A cache from path names to values. */
|
||||
#if HAVE_BOEHMGC
|
||||
@@ -115,23 +117,25 @@ private:
|
||||
SearchPath::iterator searchPathInsertionPoint;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
EvalState();
|
||||
~EvalState();
|
||||
|
||||
void addToSearchPath(const string & s);
|
||||
|
||||
/* Parse a Nix expression from the specified file. If `path'
|
||||
refers to a directory, then "/default.nix" is appended. */
|
||||
Expr * parseExprFromFile(Path path);
|
||||
/* Parse a Nix expression from the specified file. */
|
||||
Expr * parseExprFromFile(const Path & path);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
/* Evaluate an expression read from the given file to normal
|
||||
form. */
|
||||
void evalFile(const Path & path, Value & v);
|
||||
|
||||
void resetFileCache();
|
||||
|
||||
/* Look up a file in the search path. */
|
||||
Path findFile(const string & path);
|
||||
|
||||
@@ -155,7 +159,7 @@ public:
|
||||
void strictForceValue(Value & v);
|
||||
|
||||
/* Force `v', and then verify that it has the expected type. */
|
||||
int forceInt(Value & v);
|
||||
NixInt forceInt(Value & v);
|
||||
bool forceBool(Value & v);
|
||||
inline void forceAttrs(Value & v);
|
||||
inline void forceList(Value & v);
|
||||
@@ -171,7 +175,7 @@ public:
|
||||
/* String coercion. Converts strings, paths and derivations to a
|
||||
string. If `coerceMore' is set, also converts nulls, integers,
|
||||
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,
|
||||
bool coerceMore = false, bool copyToStore = true);
|
||||
|
||||
@@ -180,39 +184,43 @@ public:
|
||||
path. Nothing is copied to the store. */
|
||||
Path coerceToPath(Value & v, PathSet & context);
|
||||
|
||||
private:
|
||||
public:
|
||||
|
||||
/* The base environment, containing the builtin functions and
|
||||
values. */
|
||||
Env & baseEnv;
|
||||
|
||||
unsigned int baseEnvDispl;
|
||||
|
||||
public:
|
||||
|
||||
/* The same, but used during parsing to resolve variables. */
|
||||
StaticEnv staticBaseEnv; // !!! should be private
|
||||
|
||||
private:
|
||||
|
||||
|
||||
unsigned int baseEnvDispl;
|
||||
|
||||
void createBaseEnv();
|
||||
|
||||
|
||||
void addConstant(const string & name, Value & v);
|
||||
|
||||
void addPrimOp(const string & name,
|
||||
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 ExprVar & var, bool noEval);
|
||||
|
||||
friend class ExprVar;
|
||||
friend class ExprAttrs;
|
||||
friend class ExprLet;
|
||||
|
||||
Expr * parse(const char * text,
|
||||
const Path & path, const Path & basePath);
|
||||
Expr * parse(const char * text, const Path & path,
|
||||
const Path & basePath, StaticEnv & staticEnv);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/* Do a deep equality test between two values. That is, list
|
||||
elements and attributes are compared recursively. */
|
||||
bool eqValues(Value & v1, Value & v2);
|
||||
@@ -222,7 +230,7 @@ public:
|
||||
/* Automatically call a function for which each argument has a
|
||||
default value or has a binding in the `args' map. */
|
||||
void autoCallFunction(Bindings & args, Value & fun, Value & res);
|
||||
|
||||
|
||||
/* Allocation primitives. */
|
||||
Value * allocValue();
|
||||
Env & allocEnv(unsigned int size);
|
||||
@@ -233,25 +241,39 @@ public:
|
||||
void mkAttrs(Value & v, unsigned int expected);
|
||||
void mkThunk_(Value & v, Expr * expr);
|
||||
|
||||
void concatLists(Value & v, unsigned int nrLists, Value * * lists);
|
||||
|
||||
/* Print statistics. */
|
||||
void printStats();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
unsigned long nrEnvs;
|
||||
unsigned long nrValuesInEnvs;
|
||||
unsigned long nrValues;
|
||||
unsigned long nrListElems;
|
||||
unsigned long nrEvaluated;
|
||||
unsigned long nrAttrsets;
|
||||
unsigned long nrOpUpdates;
|
||||
unsigned long nrOpUpdateValuesCopied;
|
||||
unsigned int recursionDepth;
|
||||
unsigned int maxRecursionDepth;
|
||||
char * deepestStack; /* for measuring stack usage */
|
||||
|
||||
friend class RecursionCounter;
|
||||
unsigned long nrListConcats;
|
||||
unsigned long nrPrimOpCalls;
|
||||
unsigned long nrFunctionCalls;
|
||||
|
||||
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 ExprOpConcatLists;
|
||||
friend class ExprSelect;
|
||||
friend void prim_getAttr(EvalState & state, Value * * args, Value & v);
|
||||
};
|
||||
|
||||
|
||||
@@ -259,7 +281,8 @@ private:
|
||||
string showType(const Value & v);
|
||||
|
||||
|
||||
/* If `path' refers to a directory, then append "/default.nix". */
|
||||
Path resolveExprPath(Path path);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__EVAL_H */
|
||||
|
||||
+73
-30
@@ -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 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
|
||||
{
|
||||
if (metaInfoRead) return meta;
|
||||
|
||||
|
||||
(bool &) metaInfoRead = true;
|
||||
|
||||
|
||||
Bindings::iterator a = attrs->find(state.sMeta);
|
||||
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
||||
|
||||
@@ -78,25 +119,25 @@ void DrvInfo::setMetaInfo(const MetaInfo & meta)
|
||||
typedef set<Bindings *> Done;
|
||||
|
||||
|
||||
/* Evaluate value `v'. If it evaluates to an attribute set of type
|
||||
`derivation', then put information about it in `drvs' (unless it's
|
||||
already in `doneExprs'). The result boolean indicates whether it
|
||||
makes sense for the caller to recursively search for derivations in
|
||||
`v'. */
|
||||
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
|
||||
then put information about it in `drvs' (unless it's already in
|
||||
`doneExprs'). The result boolean indicates whether it makes sense
|
||||
for the caller to recursively search for derivations in `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 {
|
||||
state.forceValue(v);
|
||||
if (!state.isDerivation(v)) return true;
|
||||
|
||||
/* Remove spurious duplicates (e.g., an attribute set like
|
||||
`rec { x = derivation {...}; y = x;}'. */
|
||||
/* Remove spurious duplicates (e.g., a set like `rec { x =
|
||||
derivation {...}; y = x;}'. */
|
||||
if (done.find(v.attrs) != done.end()) return false;
|
||||
done.insert(v.attrs);
|
||||
|
||||
DrvInfo drv;
|
||||
|
||||
|
||||
Bindings::iterator i = v.attrs->find(state.sName);
|
||||
/* !!! We really would like to have a decent back trace here. */
|
||||
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
||||
@@ -114,18 +155,20 @@ static bool getDerivation(EvalState & state, Value & v,
|
||||
|
||||
drvs.push_back(drv);
|
||||
return false;
|
||||
|
||||
|
||||
} 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;
|
||||
DrvInfos drvs;
|
||||
getDerivation(state, v, "", drvs, done);
|
||||
getDerivation(state, v, "", drvs, done, ignoreAssertionFailures);
|
||||
if (drvs.size() != 1) return false;
|
||||
drv = drvs.front();
|
||||
return true;
|
||||
@@ -140,15 +183,16 @@ static string addToPath(const string & s1, const string & s2)
|
||||
|
||||
static void getDerivations(EvalState & state, Value & vIn,
|
||||
const string & pathPrefix, Bindings & autoArgs,
|
||||
DrvInfos & drvs, Done & done)
|
||||
DrvInfos & drvs, Done & done,
|
||||
bool ignoreAssertionFailures)
|
||||
{
|
||||
Value v;
|
||||
state.autoCallFunction(autoArgs, vIn, v);
|
||||
|
||||
|
||||
/* Process the expression. */
|
||||
DrvInfo drv;
|
||||
|
||||
if (!getDerivation(state, v, pathPrefix, drvs, done)) ;
|
||||
if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ;
|
||||
|
||||
else if (v.type == tAttrs) {
|
||||
|
||||
@@ -171,16 +215,15 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||
string pathPrefix2 = addToPath(pathPrefix, i->first);
|
||||
Value & v2(*v.attrs->find(i->second)->value);
|
||||
if (combineChannels)
|
||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
||||
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
|
||||
/* If the value of this attribute is itself an
|
||||
attribute set, should we recurse into it? => Only
|
||||
if it has a `recurseForDerivations = true'
|
||||
attribute. */
|
||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||
else if (getDerivation(state, v2, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
|
||||
/* If the value of this attribute is itself a set,
|
||||
should we recurse into it? => Only if it has a
|
||||
`recurseForDerivations = true' attribute. */
|
||||
if (v2.type == tAttrs) {
|
||||
Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations"));
|
||||
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 +234,8 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||
startNest(nest, lvlDebug,
|
||||
format("evaluating list element"));
|
||||
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
||||
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done))
|
||||
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done);
|
||||
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done, ignoreAssertionFailures))
|
||||
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,11 +244,11 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||
|
||||
|
||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||
Bindings & autoArgs, DrvInfos & drvs)
|
||||
Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures)
|
||||
{
|
||||
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
|
||||
#define __GET_DRVS_H
|
||||
#pragma once
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
@@ -26,13 +25,20 @@ typedef std::map<string, MetaValue> MetaInfo;
|
||||
|
||||
struct DrvInfo
|
||||
{
|
||||
public:
|
||||
typedef std::map<string, Path> Outputs;
|
||||
|
||||
private:
|
||||
string drvPath;
|
||||
string outPath;
|
||||
string outputName;
|
||||
Outputs outputs;
|
||||
|
||||
bool metaInfoRead;
|
||||
MetaInfo meta;
|
||||
|
||||
|
||||
bool failed; // set if we get an AssertionError
|
||||
|
||||
public:
|
||||
string name;
|
||||
string attrPath; /* path towards the derivation */
|
||||
@@ -41,10 +47,12 @@ public:
|
||||
/* !!! make this private */
|
||||
Bindings * attrs;
|
||||
|
||||
DrvInfo() : metaInfoRead(false), attrs(0) { };
|
||||
DrvInfo() : metaInfoRead(false), failed(false), attrs(0) { };
|
||||
|
||||
string queryDrvPath(EvalState & state) const;
|
||||
string queryOutPath(EvalState & state) const;
|
||||
string queryOutputName(EvalState & state) const;
|
||||
Outputs queryOutputs(EvalState & state);
|
||||
MetaInfo queryMetaInfo(EvalState & state) const;
|
||||
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
|
||||
|
||||
@@ -52,13 +60,16 @@ public:
|
||||
{
|
||||
drvPath = s;
|
||||
}
|
||||
|
||||
|
||||
void setOutPath(const string & s)
|
||||
{
|
||||
outPath = s;
|
||||
}
|
||||
|
||||
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
|
||||
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,
|
||||
Bindings & autoArgs, DrvInfos & drvs);
|
||||
Bindings & autoArgs, DrvInfos & drvs,
|
||||
bool ignoreAssertionFailures);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__GET_DRVS_H */
|
||||
|
||||
+12
-9
@@ -9,21 +9,20 @@
|
||||
|
||||
%{
|
||||
#include "nixexpr.hh"
|
||||
#define BISON_HEADER_HACK
|
||||
#include "parser-tab.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
|
||||
static void initLoc(YYLTYPE * loc)
|
||||
{
|
||||
loc->first_line = loc->last_line = 1;
|
||||
loc->first_column = loc->last_column = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
||||
{
|
||||
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 */
|
||||
s++;
|
||||
/* fall through */
|
||||
case '\n':
|
||||
case '\n':
|
||||
++loc->last_line;
|
||||
loc->last_column = 1;
|
||||
break;
|
||||
@@ -69,7 +68,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
|
||||
return new ExprString(symbols.create(t));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#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]+
|
||||
PATH [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 NEQ; }
|
||||
\<\= { return LEQ; }
|
||||
\>\= { return GEQ; }
|
||||
\&\& { return AND; }
|
||||
\|\| { return OR; }
|
||||
\-\> { return IMPL; }
|
||||
@@ -109,8 +110,10 @@ or { return OR_KW; }
|
||||
\+\+ { return CONCAT; }
|
||||
|
||||
{ID} { yylval->id = strdup(yytext); return ID; }
|
||||
{INT} { int n = atoi(yytext); /* !!! overflow */
|
||||
yylval->n = n;
|
||||
{INT} { errno = 0;
|
||||
yylval->n = strtol(yytext, 0, 10);
|
||||
if (errno != 0)
|
||||
throw ParseError(format("invalid integer `%1%'") % yytext);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@@ -168,7 +171,7 @@ or { return OR_KW; }
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
/* Horrible, disgusting hack: allow the parser to set the scanner
|
||||
start condition back to STRING. Necessary in interpolations like
|
||||
"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
|
||||
while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
|
||||
s += *p++;
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ int compareVersions(const string & v1, const string & v2)
|
||||
{
|
||||
string::const_iterator p1 = v1.begin();
|
||||
string::const_iterator p2 = v2.begin();
|
||||
|
||||
|
||||
while (p1 != v1.end() || p2 != v2.end()) {
|
||||
string c1 = nextComponent(p1, v1.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 result;
|
||||
for (Strings::const_iterator i = opArgs.begin();
|
||||
i != opArgs.end(); ++i)
|
||||
foreach (Strings::const_iterator, i, opArgs)
|
||||
result.push_back(DrvName(*i));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-10
@@ -1,12 +1,9 @@
|
||||
#ifndef __NAMES_H
|
||||
#define __NAMES_H
|
||||
#pragma once
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
struct DrvName
|
||||
{
|
||||
string fullName;
|
||||
@@ -19,15 +16,9 @@ struct DrvName
|
||||
bool matches(DrvName & n);
|
||||
};
|
||||
|
||||
|
||||
typedef list<DrvName> DrvNames;
|
||||
|
||||
|
||||
int compareVersions(const string & v1, const string & v2);
|
||||
DrvNames drvNamesFromArgs(const Strings & opArgs);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__NAMES_H */
|
||||
|
||||
+47
-23
@@ -38,7 +38,7 @@ void ExprPath::show(std::ostream & str)
|
||||
|
||||
void ExprVar::show(std::ostream & str)
|
||||
{
|
||||
str << info.name;
|
||||
str << name;
|
||||
}
|
||||
|
||||
void ExprSelect::show(std::ostream & str)
|
||||
@@ -174,7 +174,7 @@ void ExprPath::bindVars(const StaticEnv & env)
|
||||
{
|
||||
}
|
||||
|
||||
void VarRef::bind(const StaticEnv & env)
|
||||
void ExprVar::bindVars(const StaticEnv & env)
|
||||
{
|
||||
/* Check whether the variable appears in the environment. If so,
|
||||
set its level and displacement. */
|
||||
@@ -198,17 +198,12 @@ void VarRef::bind(const StaticEnv & env)
|
||||
/* Otherwise, the variable must be obtained from the nearest
|
||||
enclosing `with'. If there is no `with', then we can issue an
|
||||
"undefined variable" error now. */
|
||||
if (withLevel == -1) throw EvalError(format("undefined variable `%1%'") % name);
|
||||
if (withLevel == -1) throw UndefinedVarError(format("undefined variable `%1%' at %2%") % name % pos);
|
||||
|
||||
fromWith = true;
|
||||
this->level = withLevel;
|
||||
}
|
||||
|
||||
void ExprVar::bindVars(const StaticEnv & env)
|
||||
{
|
||||
info.bind(env);
|
||||
}
|
||||
|
||||
void ExprSelect::bindVars(const StaticEnv & env)
|
||||
{
|
||||
e->bindVars(env);
|
||||
@@ -224,20 +219,18 @@ void ExprAttrs::bindVars(const StaticEnv & env)
|
||||
{
|
||||
if (recursive) {
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
|
||||
unsigned int displ = 0;
|
||||
foreach (AttrDefs::iterator, i, attrs)
|
||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
||||
|
||||
|
||||
foreach (AttrDefs::iterator, i, attrs)
|
||||
if (i->second.inherited) i->second.var.bind(env);
|
||||
else i->second.e->bindVars(newEnv);
|
||||
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
||||
}
|
||||
|
||||
else
|
||||
foreach (AttrDefs::iterator, i, attrs)
|
||||
if (i->second.inherited) i->second.var.bind(env);
|
||||
else i->second.e->bindVars(env);
|
||||
i->second.e->bindVars(env);
|
||||
}
|
||||
|
||||
void ExprList::bindVars(const StaticEnv & env)
|
||||
@@ -249,9 +242,9 @@ void ExprList::bindVars(const StaticEnv & env)
|
||||
void ExprLambda::bindVars(const StaticEnv & env)
|
||||
{
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
|
||||
unsigned int displ = 0;
|
||||
|
||||
|
||||
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
||||
|
||||
if (matchAttrs) {
|
||||
@@ -268,15 +261,14 @@ void ExprLambda::bindVars(const StaticEnv & env)
|
||||
void ExprLet::bindVars(const StaticEnv & env)
|
||||
{
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
|
||||
unsigned int displ = 0;
|
||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||
newEnv.vars[i->first] = i->second.displ = displ++;
|
||||
|
||||
|
||||
foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs)
|
||||
if (i->second.inherited) i->second.var.bind(env);
|
||||
else i->second.e->bindVars(newEnv);
|
||||
|
||||
i->second.e->bindVars(i->second.inherited ? env : newEnv);
|
||||
|
||||
body->bindVars(newEnv);
|
||||
}
|
||||
|
||||
@@ -293,8 +285,8 @@ void ExprWith::bindVars(const StaticEnv & env)
|
||||
prevWith = level;
|
||||
break;
|
||||
}
|
||||
|
||||
attrs->bindVars(env);
|
||||
|
||||
attrs->bindVars(env);
|
||||
StaticEnv newEnv(true, &env);
|
||||
body->bindVars(newEnv);
|
||||
}
|
||||
@@ -324,4 +316,36 @@ 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Symbol table. */
|
||||
|
||||
size_t SymbolTable::totalSize() const
|
||||
{
|
||||
size_t n = 0;
|
||||
foreach (Symbols::const_iterator, i, symbols)
|
||||
n += i->size();
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+32
-27
@@ -1,5 +1,4 @@
|
||||
#ifndef __NIXEXPR_H
|
||||
#define __NIXEXPR_H
|
||||
#pragma once
|
||||
|
||||
#include "value.hh"
|
||||
#include "symbol-table.hh"
|
||||
@@ -17,17 +16,29 @@ MakeError(ThrownError, AssertionError)
|
||||
MakeError(Abort, EvalError)
|
||||
MakeError(TypeError, EvalError)
|
||||
MakeError(ImportError, EvalError) // error building an imported derivation
|
||||
MakeError(UndefinedVarError, Error)
|
||||
|
||||
|
||||
/* Position objects. */
|
||||
|
||||
struct Pos
|
||||
{
|
||||
string file;
|
||||
Symbol file;
|
||||
unsigned int line, column;
|
||||
Pos() : line(0), column(0) { };
|
||||
Pos(const string & file, unsigned int line, unsigned int column)
|
||||
Pos(const Symbol & file, unsigned int line, unsigned int column)
|
||||
: file(file), line(line), column(column) { };
|
||||
bool operator < (const Pos & p2) const
|
||||
{
|
||||
if (!line) return p2.line;
|
||||
if (!p2.line) return false;
|
||||
int d = ((string) file).compare((string) 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;
|
||||
@@ -55,6 +66,7 @@ struct Expr
|
||||
virtual void bindVars(const StaticEnv & env);
|
||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||
virtual Value * maybeThunk(EvalState & state, Env & env);
|
||||
virtual void setName(Symbol & name);
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, Expr & e);
|
||||
@@ -66,9 +78,9 @@ std::ostream & operator << (std::ostream & str, Expr & e);
|
||||
|
||||
struct ExprInt : Expr
|
||||
{
|
||||
int n;
|
||||
NixInt n;
|
||||
Value v;
|
||||
ExprInt(int n) : n(n) { mkInt(v, n); };
|
||||
ExprInt(NixInt n) : n(n) { mkInt(v, n); };
|
||||
COMMON_METHODS
|
||||
Value * maybeThunk(EvalState & state, Env & env);
|
||||
};
|
||||
@@ -98,32 +110,25 @@ struct ExprPath : Expr
|
||||
Value * maybeThunk(EvalState & state, Env & env);
|
||||
};
|
||||
|
||||
struct VarRef
|
||||
struct ExprVar : Expr
|
||||
{
|
||||
Pos pos;
|
||||
Symbol name;
|
||||
|
||||
/* Whether the variable comes from an environment (e.g. a rec, let
|
||||
or function argument) or from a "with". */
|
||||
bool fromWith;
|
||||
|
||||
|
||||
/* In the former case, the value is obtained by going `level'
|
||||
levels up from the current environment and getting the
|
||||
`displ'th value in that environment. In the latter case, the
|
||||
value is obtained by getting the attribute named `name' from
|
||||
the attribute set stored in the environment that is `level'
|
||||
levels up from the current one.*/
|
||||
the set stored in the environment that is `level' levels up
|
||||
from the current one.*/
|
||||
unsigned int level;
|
||||
unsigned int displ;
|
||||
|
||||
VarRef() { };
|
||||
VarRef(const Symbol & name) : name(name) { };
|
||||
void bind(const StaticEnv & env);
|
||||
};
|
||||
|
||||
struct ExprVar : Expr
|
||||
{
|
||||
VarRef info;
|
||||
ExprVar(const Symbol & name) : info(name) { };
|
||||
ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
|
||||
COMMON_METHODS
|
||||
Value * maybeThunk(EvalState & state, Env & env);
|
||||
};
|
||||
@@ -150,12 +155,10 @@ struct ExprAttrs : Expr
|
||||
bool recursive;
|
||||
struct AttrDef {
|
||||
bool inherited;
|
||||
Expr * e; // if not inherited
|
||||
VarRef var; // if inherited
|
||||
Expr * e;
|
||||
Pos pos;
|
||||
unsigned int displ; // displacement
|
||||
AttrDef(Expr * e, const Pos & pos) : inherited(false), e(e), pos(pos) { };
|
||||
AttrDef(const Symbol & name, const Pos & pos) : inherited(true), var(name), pos(pos) { };
|
||||
AttrDef(Expr * e, const Pos & pos, bool inherited=false) : inherited(inherited), e(e), pos(pos) { };
|
||||
AttrDef() { };
|
||||
};
|
||||
typedef std::map<Symbol, AttrDef> AttrDefs;
|
||||
@@ -189,6 +192,7 @@ struct Formals
|
||||
struct ExprLambda : Expr
|
||||
{
|
||||
Pos pos;
|
||||
Symbol name;
|
||||
Symbol arg;
|
||||
bool matchAttrs;
|
||||
Formals * formals;
|
||||
@@ -200,6 +204,8 @@ struct ExprLambda : Expr
|
||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||
% arg % pos);
|
||||
};
|
||||
void setName(Symbol & name);
|
||||
string showNamePos();
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
@@ -269,8 +275,10 @@ MakeBinOp(OpConcatLists, "++")
|
||||
|
||||
struct ExprConcatStrings : Expr
|
||||
{
|
||||
bool forceString;
|
||||
vector<Expr *> * es;
|
||||
ExprConcatStrings(vector<Expr *> * es) : es(es) { };
|
||||
ExprConcatStrings(bool forceString, vector<Expr *> * es)
|
||||
: forceString(forceString), es(es) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
@@ -290,6 +298,3 @@ struct StaticEnv
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__NIXEXPR_H */
|
||||
|
||||
+65
-53
@@ -4,32 +4,32 @@
|
||||
%error-verbose
|
||||
%defines
|
||||
/* %no-lines */
|
||||
%parse-param { yyscan_t scanner }
|
||||
%parse-param { ParseData * data }
|
||||
%lex-param { yyscan_t scanner }
|
||||
%lex-param { ParseData * data }
|
||||
%parse-param { void * scanner }
|
||||
%parse-param { nix::ParseData * data }
|
||||
%lex-param { void * scanner }
|
||||
%lex-param { nix::ParseData * data }
|
||||
%expect 1
|
||||
%expect-rr 1
|
||||
|
||||
%code requires {
|
||||
|
||||
|
||||
#ifndef BISON_HEADER
|
||||
#define BISON_HEADER
|
||||
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
#include "nixexpr.hh"
|
||||
#include "eval.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct ParseData
|
||||
struct ParseData
|
||||
{
|
||||
EvalState & state;
|
||||
SymbolTable & symbols;
|
||||
Expr * result;
|
||||
Path basePath;
|
||||
Path path;
|
||||
Symbol path;
|
||||
string error;
|
||||
Symbol sLetBody;
|
||||
ParseData(EvalState & state)
|
||||
@@ -38,7 +38,7 @@ namespace nix {
|
||||
, sLetBody(symbols.create("<let-body>"))
|
||||
{ };
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define YY_DECL int yylex \
|
||||
@@ -52,7 +52,6 @@ namespace nix {
|
||||
|
||||
#include "parser-tab.hh"
|
||||
#include "lexer-tab.hh"
|
||||
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -64,14 +63,14 @@ using namespace nix;
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
|
||||
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
|
||||
{
|
||||
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
||||
% showAttrPath(attrPath) % 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%")
|
||||
% showAttrPath(attrPath) % pos % prevPos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||
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)
|
||||
{
|
||||
if (es.empty()) return new ExprString(symbols.create(""));
|
||||
|
||||
|
||||
/* Figure out the minimum indentation. Note that by design
|
||||
whitespace-only final lines are not taken into account. (So
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
string s2;
|
||||
for (unsigned int j = 0; j < e->s.size(); ++j) {
|
||||
if (atStartOfLine) {
|
||||
@@ -203,7 +203,8 @@ static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
|
||||
es2->push_back(new ExprString(symbols.create(s2)));
|
||||
}
|
||||
|
||||
return new ExprConcatStrings(es2);
|
||||
/* If this is a single string, then don't do a concatenation. */
|
||||
return es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0]) ? (*es2)[0] : new ExprConcatStrings(true, es2);
|
||||
}
|
||||
|
||||
|
||||
@@ -232,13 +233,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||
%}
|
||||
|
||||
%union {
|
||||
// !!! We're probably leaking stuff here.
|
||||
// !!! We're probably leaking stuff here.
|
||||
nix::Expr * e;
|
||||
nix::ExprList * list;
|
||||
nix::ExprAttrs * attrs;
|
||||
nix::Formals * formals;
|
||||
nix::Formal * formal;
|
||||
int n;
|
||||
nix::NixInt n;
|
||||
char * id; // !!! -> Symbol
|
||||
char * path;
|
||||
char * uri;
|
||||
@@ -269,12 +270,15 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||
%left OR
|
||||
%left AND
|
||||
%nonassoc EQ NEQ
|
||||
%left '<' '>' LEQ GEQ
|
||||
%right UPDATE
|
||||
%left NEG
|
||||
%left '+'
|
||||
%left NOT
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
%right CONCAT
|
||||
%nonassoc '?'
|
||||
%nonassoc '~'
|
||||
%nonassoc NEGATE
|
||||
|
||||
%%
|
||||
|
||||
@@ -306,9 +310,14 @@ expr_if
|
||||
;
|
||||
|
||||
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(noPos, data->symbols.create("__sub")), new ExprInt(0)), $2); }
|
||||
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
||||
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3); }
|
||||
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1)); }
|
||||
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1); }
|
||||
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3)); }
|
||||
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
||||
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
|
||||
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
|
||||
@@ -318,8 +327,11 @@ expr_op
|
||||
{ vector<Expr *> * l = new vector<Expr *>;
|
||||
l->push_back($1);
|
||||
l->push_back($3);
|
||||
$$ = new ExprConcatStrings(l);
|
||||
$$ = new ExprConcatStrings(false, l);
|
||||
}
|
||||
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), $1), $3); }
|
||||
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__mul")), $1), $3); }
|
||||
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__div")), $1), $3); }
|
||||
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
||||
| expr_app
|
||||
;
|
||||
@@ -338,18 +350,18 @@ expr_select
|
||||
| /* Backwards compatibility: because Nixpkgs has a rarely used
|
||||
function named ‘or’, allow stuff like ‘map or [...]’. */
|
||||
expr_simple OR_KW
|
||||
{ $$ = new ExprApp($1, new ExprVar(data->symbols.create("or"))); }
|
||||
{ $$ = new ExprApp($1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
|
||||
| expr_simple { $$ = $1; }
|
||||
;
|
||||
|
||||
expr_simple
|
||||
: ID { $$ = new ExprVar(data->symbols.create($1)); }
|
||||
: ID { $$ = new ExprVar(CUR_POS, data->symbols.create($1)); }
|
||||
| INT { $$ = new ExprInt($1); }
|
||||
| '"' string_parts '"' {
|
||||
/* For efficiency, and to simplify parse trees a bit. */
|
||||
if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
|
||||
else if ($2->size() == 1) $$ = $2->front();
|
||||
else $$ = new ExprConcatStrings($2);
|
||||
else if ($2->size() == 1 && dynamic_cast<ExprString *>($2->front())) $$ = $2->front();
|
||||
else $$ = new ExprConcatStrings(true, $2);
|
||||
}
|
||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||
$$ = stripIndentation(data->symbols, *$2);
|
||||
@@ -361,10 +373,10 @@ expr_simple
|
||||
/* The file wasn't found in the search path. However, we can't
|
||||
throw an error here, because the expression might never be
|
||||
evaluated. So return an expression that lazily calls
|
||||
‘abort’. */
|
||||
‘throw’. */
|
||||
$$ = path2 == ""
|
||||
? (Expr * ) new ExprApp(
|
||||
new ExprVar(data->symbols.create("throw")),
|
||||
new ExprVar(noPos, data->symbols.create("throw")),
|
||||
new ExprString(data->symbols.create(
|
||||
(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str())))
|
||||
: (Expr * ) new ExprPath(path2);
|
||||
@@ -402,7 +414,7 @@ binds
|
||||
if ($$->attrs.find(*i) != $$->attrs.end())
|
||||
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
|
||||
Pos pos = makeCurPos(@3, data);
|
||||
$$->attrs[*i] = ExprAttrs::AttrDef(*i, pos);
|
||||
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, *i), pos, true);
|
||||
}
|
||||
}
|
||||
| binds INHERIT '(' expr ')' attrs ';'
|
||||
@@ -454,7 +466,7 @@ formal
|
||||
: ID { $$ = new Formal(data->symbols.create($1), 0); }
|
||||
| ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); }
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
||||
@@ -467,34 +479,30 @@ formal
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
|
||||
Expr * EvalState::parse(const char * text,
|
||||
const Path & path, const Path & basePath)
|
||||
const Path & path, const Path & basePath, StaticEnv & staticEnv)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
ParseData data(*this);
|
||||
data.basePath = basePath;
|
||||
data.path = path;
|
||||
data.path = data.symbols.create(path);
|
||||
|
||||
yylex_init(&scanner);
|
||||
yy_scan_string(text, scanner);
|
||||
int res = yyparse(scanner, &data);
|
||||
yylex_destroy(scanner);
|
||||
|
||||
|
||||
if (res) throw ParseError(data.error);
|
||||
|
||||
try {
|
||||
data.result->bindVars(staticBaseEnv);
|
||||
} catch (Error & e) {
|
||||
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
|
||||
}
|
||||
|
||||
data.result->bindVars(staticEnv);
|
||||
|
||||
return data.result;
|
||||
}
|
||||
|
||||
|
||||
Expr * EvalState::parseExprFromFile(Path path)
|
||||
Path resolveExprPath(Path path)
|
||||
{
|
||||
assert(path[0] == '/');
|
||||
|
||||
@@ -512,21 +520,25 @@ Expr * EvalState::parseExprFromFile(Path path)
|
||||
if (S_ISDIR(st.st_mode))
|
||||
path = canonPath(path + "/default.nix");
|
||||
|
||||
/* Read and parse the input file, unless it's already in the parse
|
||||
tree cache. */
|
||||
Expr * e = parseTrees[path];
|
||||
if (!e) {
|
||||
e = parse(readFile(path).c_str(), path, dirOf(path));
|
||||
parseTrees[path] = e;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return parse(s.c_str(), "(string)", basePath);
|
||||
return parseExprFromString(s, basePath, staticBaseEnv);
|
||||
}
|
||||
|
||||
|
||||
@@ -541,7 +553,7 @@ void EvalState::addToSearchPath(const string & s)
|
||||
prefix = string(s, 0, pos);
|
||||
path = string(s, pos + 1);
|
||||
}
|
||||
|
||||
|
||||
path = absPath(path);
|
||||
if (pathExists(path)) {
|
||||
debug(format("adding path `%1%' to the search path") % path);
|
||||
@@ -554,7 +566,7 @@ Path EvalState::findFile(const string & path)
|
||||
{
|
||||
foreach (SearchPath::iterator, i, searchPath) {
|
||||
Path res;
|
||||
if (i->first.empty())
|
||||
if (i->first.empty())
|
||||
res = i->second + "/" + path;
|
||||
else {
|
||||
if (path.compare(0, i->first.size(), i->first) != 0 ||
|
||||
|
||||
+269
-89
@@ -37,7 +37,7 @@ std::pair<string, string> decodeContext(const string & s)
|
||||
|
||||
|
||||
/* Load and evaluate an expression from path specified by the
|
||||
argument. */
|
||||
argument. */
|
||||
static void prim_import(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
PathSet context;
|
||||
@@ -51,15 +51,68 @@ static void prim_import(EvalState & state, Value * * args, Value & v)
|
||||
% path % ctx);
|
||||
if (isDerivation(ctx))
|
||||
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
|
||||
the selected output of this derivation. */
|
||||
store->buildDerivations(singleton<PathSet>(ctx));
|
||||
store->buildPaths(singleton<PathSet>(ctx));
|
||||
} catch (Error & e) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return a string representing the type of the expression. */
|
||||
static void prim_typeOf(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
string t;
|
||||
switch (args[0]->type) {
|
||||
case tInt: t = "int"; break;
|
||||
case tBool: t = "bool"; break;
|
||||
case tString: t = "string"; break;
|
||||
case tPath: t = "path"; break;
|
||||
case tNull: t = "null"; break;
|
||||
case tAttrs: t = "set"; break;
|
||||
case tList: t = "list"; break;
|
||||
case tLambda:
|
||||
case tPrimOp:
|
||||
case tPrimOpApp:
|
||||
t = "lambda";
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
mkString(v, state.symbols.create(t));
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +132,7 @@ static void prim_isFunction(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is an Int. */
|
||||
/* Determine whether the argument is an integer. */
|
||||
static void prim_isInt(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
@@ -87,7 +140,7 @@ static void prim_isInt(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is an String. */
|
||||
/* Determine whether the argument is a string. */
|
||||
static void prim_isString(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
@@ -95,7 +148,7 @@ static void prim_isString(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is an Bool. */
|
||||
/* Determine whether the argument is a Boolean. */
|
||||
static void prim_isBool(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
@@ -105,24 +158,31 @@ static void prim_isBool(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
struct CompareValues
|
||||
{
|
||||
bool operator () (const Value & v1, const Value & v2) const
|
||||
bool operator () (const Value * v1, const Value * v2) const
|
||||
{
|
||||
if (v1.type != v2.type)
|
||||
if (v1->type != v2->type)
|
||||
throw EvalError("cannot compare values of different types");
|
||||
switch (v1.type) {
|
||||
switch (v1->type) {
|
||||
case tInt:
|
||||
return v1.integer < v2.integer;
|
||||
return v1->integer < v2->integer;
|
||||
case tString:
|
||||
return strcmp(v1.string.s, v2.string.s) < 0;
|
||||
return strcmp(v1->string.s, v2->string.s) < 0;
|
||||
case tPath:
|
||||
return strcmp(v1.path, v2.path) < 0;
|
||||
return strcmp(v1->path, v2->path) < 0;
|
||||
default:
|
||||
throw EvalError(format("cannot compare %1% with %2%") % showType(v1) % showType(v2));
|
||||
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
typedef list<Value *, gc_allocator<Value *> > ValueList;
|
||||
#else
|
||||
typedef list<Value *> ValueList;
|
||||
#endif
|
||||
|
||||
|
||||
static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
startNest(nest, lvlDebug, "finding dependencies");
|
||||
@@ -136,7 +196,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
throw EvalError("attribute `startSet' required");
|
||||
state.forceList(*startSet->value);
|
||||
|
||||
list<Value *> workSet;
|
||||
ValueList workSet;
|
||||
for (unsigned int n = 0; n < startSet->value->list.length; ++n)
|
||||
workSet.push_back(startSet->value->list.elems[n]);
|
||||
|
||||
@@ -150,11 +210,13 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
/* Construct the closure by applying the operator to element of
|
||||
`workSet', adding the result to `workSet', continuing until
|
||||
no new elements are found. */
|
||||
list<Value> res;
|
||||
set<Value, CompareValues> doneKeys; // !!! use Value *?
|
||||
ValueList res;
|
||||
// `doneKeys' doesn't need to be a GC root, because its values are
|
||||
// reachable from res.
|
||||
set<Value *, CompareValues> doneKeys;
|
||||
while (!workSet.empty()) {
|
||||
Value * e = *(workSet.begin());
|
||||
workSet.pop_front();
|
||||
Value * e = *(workSet.begin());
|
||||
workSet.pop_front();
|
||||
|
||||
state.forceAttrs(*e);
|
||||
|
||||
@@ -164,10 +226,10 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
throw EvalError("attribute `key' required");
|
||||
state.forceValue(*key->value);
|
||||
|
||||
if (doneKeys.find(*key->value) != doneKeys.end()) continue;
|
||||
doneKeys.insert(*key->value);
|
||||
res.push_back(*e);
|
||||
|
||||
if (doneKeys.find(key->value) != doneKeys.end()) continue;
|
||||
doneKeys.insert(key->value);
|
||||
res.push_back(e);
|
||||
|
||||
/* Call the `operator' function with `e' as argument. */
|
||||
Value call;
|
||||
mkApp(call, *op->value, *e);
|
||||
@@ -183,8 +245,8 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||
/* Create the result list. */
|
||||
state.mkList(v, res.size());
|
||||
unsigned int n = 0;
|
||||
foreach (list<Value>::iterator, i, res)
|
||||
*(v.list.elems[n++] = state.allocValue()) = *i;
|
||||
foreach (ValueList::iterator, i, res)
|
||||
v.list.elems[n++] = *i;
|
||||
}
|
||||
|
||||
|
||||
@@ -217,17 +279,17 @@ 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;} */
|
||||
static void prim_tryEval(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.mkAttrs(v, 2);
|
||||
try {
|
||||
state.forceValue(*args[0]);
|
||||
v.attrs->push_back(Attr(state.symbols.create("value"), args[0]));
|
||||
v.attrs->push_back(Attr(state.sValue, args[0]));
|
||||
mkBool(*state.allocAttr(v, state.symbols.create("success")), true);
|
||||
} catch (AssertionError & e) {
|
||||
mkBool(*state.allocAttr(v, state.symbols.create("value")), false);
|
||||
mkBool(*state.allocAttr(v, state.sValue), false);
|
||||
mkBool(*state.allocAttr(v, state.symbols.create("success")), false);
|
||||
}
|
||||
v.attrs->sort();
|
||||
@@ -280,16 +342,22 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
throw EvalError("required attribute `name' missing");
|
||||
string drvName;
|
||||
Pos & posDrvName(*attr->pos);
|
||||
try {
|
||||
try {
|
||||
drvName = state.forceStringNoCtx(*attr->value);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName);
|
||||
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. */
|
||||
Derivation drv;
|
||||
|
||||
|
||||
PathSet context;
|
||||
|
||||
string outputHash, outputHashAlgo;
|
||||
@@ -299,11 +367,17 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
outputs.insert("out");
|
||||
|
||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
||||
if (i->name == state.sIgnoreNulls) continue;
|
||||
string key = i->name;
|
||||
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
|
||||
|
||||
try {
|
||||
|
||||
if (ignoreNulls) {
|
||||
state.forceValue(*i->value);
|
||||
if (i->value->type == tNull) continue;
|
||||
}
|
||||
|
||||
/* The `args' attribute is special: it supplies the
|
||||
command-line arguments to the builder. */
|
||||
if (key == "args") {
|
||||
@@ -328,12 +402,12 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
else if (key == "outputHash") outputHash = s;
|
||||
else if (key == "outputHashAlgo") outputHashAlgo = s;
|
||||
else if (key == "outputHashMode") {
|
||||
if (s == "recursive") outputHashRecursive = true;
|
||||
if (s == "recursive") outputHashRecursive = true;
|
||||
else if (s == "flat") outputHashRecursive = false;
|
||||
else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s);
|
||||
}
|
||||
else if (key == "outputs") {
|
||||
Strings tmp = tokenizeString(s);
|
||||
Strings tmp = tokenizeString<Strings>(s);
|
||||
outputs.clear();
|
||||
foreach (Strings::iterator, j, tmp) {
|
||||
if (outputs.find(*j) != outputs.end())
|
||||
@@ -353,20 +427,18 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the derivation attribute `%1%' at %2%:\n")
|
||||
% key % *i->pos);
|
||||
e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n")
|
||||
% drvName % posDrvName);
|
||||
e.addPrefix(format("while evaluating the attribute `%1%' of the derivation `%2%' at %3%:\n")
|
||||
% key % drvName % posDrvName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Everything in the context of the strings in the derivation
|
||||
attributes should be added as dependencies of the resulting
|
||||
derivation. */
|
||||
foreach (PathSet::iterator, i, context) {
|
||||
Path path = *i;
|
||||
|
||||
|
||||
/* Paths marked with `=' denote that the path of a derivation
|
||||
is explicitly passed to the builder. Since that allows the
|
||||
builder to gain access to every path in the dependency
|
||||
@@ -403,7 +475,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
else
|
||||
drv.inputSrcs.insert(path);
|
||||
}
|
||||
|
||||
|
||||
/* Do we have all required attributes? */
|
||||
if (drv.builder == "")
|
||||
throw EvalError("required attribute `builder' missing");
|
||||
@@ -420,14 +492,14 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
/* Handle fixed-output derivations. */
|
||||
if (outputs.size() != 1 || *(outputs.begin()) != "out")
|
||||
throw Error("multiple outputs are not supported in fixed-output derivations");
|
||||
|
||||
|
||||
HashType ht = parseHashType(outputHashAlgo);
|
||||
if (ht == htUnknown)
|
||||
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
|
||||
Hash h = parseHash16or32(ht, outputHash);
|
||||
outputHash = printHash(h);
|
||||
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
|
||||
|
||||
|
||||
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
|
||||
drv.env["out"] = outPath;
|
||||
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
|
||||
@@ -447,7 +519,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
/* Use the masked derivation expression to compute the output
|
||||
path. */
|
||||
Hash h = hashDerivationModulo(*store, drv);
|
||||
|
||||
|
||||
foreach (DerivationOutputs::iterator, i, drv.outputs)
|
||||
if (i->second.path == "") {
|
||||
Path outPath = makeOutputPath(i->first, h, drvName);
|
||||
@@ -457,7 +529,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
/* 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%'")
|
||||
% drvName % drvPath);
|
||||
@@ -502,7 +574,11 @@ static void prim_toPath(EvalState & state, Value * * args, Value & v)
|
||||
static void prim_storePath(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
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))
|
||||
throw EvalError(format("path `%1%' is not in the Nix store") % path);
|
||||
Path path2 = toStorePath(path);
|
||||
@@ -588,10 +664,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);
|
||||
refs.insert(path);
|
||||
}
|
||||
|
||||
Path storePath = readOnlyMode
|
||||
|
||||
Path storePath = settings.readOnlyMode
|
||||
? 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
|
||||
result, since `storePath' itself has references to the paths
|
||||
@@ -605,7 +681,7 @@ struct FilterFromExpr : PathFilter
|
||||
{
|
||||
EvalState & state;
|
||||
Value & filter;
|
||||
|
||||
|
||||
FilterFromExpr(EvalState & state, Value & filter)
|
||||
: state(state), filter(filter)
|
||||
{
|
||||
@@ -626,12 +702,12 @@ struct FilterFromExpr : PathFilter
|
||||
state.callFunction(filter, arg1, fun2);
|
||||
|
||||
Value arg2;
|
||||
mkString(arg2,
|
||||
mkString(arg2,
|
||||
S_ISREG(st.st_mode) ? "regular" :
|
||||
S_ISDIR(st.st_mode) ? "directory" :
|
||||
S_ISLNK(st.st_mode) ? "symlink" :
|
||||
"unknown" /* not supported, will fail! */);
|
||||
|
||||
|
||||
Value res;
|
||||
state.callFunction(fun2, arg2, res);
|
||||
|
||||
@@ -653,21 +729,21 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
FilterFromExpr filter(state, *args[0]);
|
||||
|
||||
Path dstPath = readOnlyMode
|
||||
Path dstPath = settings.readOnlyMode
|
||||
? 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));
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* Attribute sets
|
||||
* Sets
|
||||
*************************************************************/
|
||||
|
||||
|
||||
/* Return the names of the attributes in an attribute set as a sorted
|
||||
list of strings. */
|
||||
/* Return the names of the attributes in a set as a sorted list of
|
||||
strings. */
|
||||
static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0]);
|
||||
@@ -685,7 +761,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
||||
|
||||
|
||||
/* 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]);
|
||||
state.forceAttrs(*args[1]);
|
||||
@@ -694,6 +770,7 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
||||
if (i == args[1]->attrs->end())
|
||||
throw EvalError(format("attribute `%1%' missing") % attr);
|
||||
// !!! add to stack trace?
|
||||
if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
|
||||
state.forceValue(*i->value);
|
||||
v = *i->value;
|
||||
}
|
||||
@@ -708,7 +785,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is an attribute set. */
|
||||
/* Determine whether the argument is a set. */
|
||||
static void prim_isAttrs(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceValue(*args[0]);
|
||||
@@ -739,10 +816,11 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
|
||||
}
|
||||
|
||||
|
||||
/* Builds an attribute set from a list specifying (name, value)
|
||||
pairs. To be precise, a list [{name = "name1"; value = value1;}
|
||||
... {name = "nameN"; value = valueN;}] is transformed to {name1 =
|
||||
value1; ... nameN = valueN;}. */
|
||||
/* Builds a set from a list specifying (name, value) pairs. To be
|
||||
precise, a list [{name = "name1"; value = value1;} ... {name =
|
||||
"nameN"; value = valueN;}] is transformed to {name1 = value1;
|
||||
... nameN = valueN;}. In case of duplicate occurences of the same
|
||||
name, the first takes precedence. */
|
||||
static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0]);
|
||||
@@ -754,36 +832,35 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
||||
for (unsigned int i = 0; i < args[0]->list.length; ++i) {
|
||||
Value & v2(*args[0]->list.elems[i]);
|
||||
state.forceAttrs(v2);
|
||||
|
||||
|
||||
Bindings::iterator j = v2.attrs->find(state.sName);
|
||||
if (j == v2.attrs->end())
|
||||
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
||||
string name = state.forceStringNoCtx(*j->value);
|
||||
|
||||
Bindings::iterator j2 = v2.attrs->find(state.symbols.create("value"));
|
||||
if (j2 == v2.attrs->end())
|
||||
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
||||
|
||||
Symbol sym = state.symbols.create(name);
|
||||
if (seen.find(sym) == seen.end()) {
|
||||
Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
|
||||
if (j2 == v2.attrs->end())
|
||||
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
||||
|
||||
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
|
||||
seen.insert(sym);
|
||||
}
|
||||
/* !!! Throw an error if `name' already exists? */
|
||||
}
|
||||
|
||||
v.attrs->sort();
|
||||
}
|
||||
|
||||
|
||||
/* Return the right-biased intersection of two attribute sets as1 and
|
||||
as2, i.e. a set that contains every attribute from as2 that is also
|
||||
a member of as1. */
|
||||
/* Return the right-biased intersection of two sets as1 and as2,
|
||||
i.e. a set that contains every attribute from as2 that is also a
|
||||
member of as1. */
|
||||
static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceAttrs(*args[0]);
|
||||
state.forceAttrs(*args[1]);
|
||||
|
||||
|
||||
state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
|
||||
|
||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
||||
@@ -839,19 +916,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. */
|
||||
static void prim_head(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0]);
|
||||
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];
|
||||
elemAt(state, *args[0], 0, v);
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
state.forceList(*args[0]);
|
||||
@@ -872,11 +963,64 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
|
||||
state.mkList(v, args[1]->list.length);
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
static void prim_length(EvalState & state, Value * * args, Value & v)
|
||||
{
|
||||
@@ -910,7 +1054,7 @@ static void prim_mul(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");
|
||||
mkInt(v, state.forceInt(*args[0]) / i2);
|
||||
}
|
||||
@@ -918,7 +1062,10 @@ static void prim_div(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 +1135,26 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args
|
||||
if (p.at(0) == '=') p = "~" + string(p, 1);
|
||||
context2.insert(p);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
*************************************************************/
|
||||
@@ -1035,21 +1197,32 @@ void EvalState::createBaseEnv()
|
||||
|
||||
mkBool(v, true);
|
||||
addConstant("true", v);
|
||||
|
||||
|
||||
mkBool(v, false);
|
||||
addConstant("false", v);
|
||||
|
||||
|
||||
v.type = tNull;
|
||||
addConstant("null", v);
|
||||
|
||||
mkInt(v, time(0));
|
||||
addConstant("__currentTime", v);
|
||||
|
||||
mkString(v, thisSystem.c_str());
|
||||
mkString(v, settings.thisSystem.c_str());
|
||||
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
|
||||
addPrimOp("import", 1, prim_import);
|
||||
addPrimOp("__typeOf", 1, prim_typeOf);
|
||||
addPrimOp("isNull", 1, prim_isNull);
|
||||
addPrimOp("__isFunction", 1, prim_isFunction);
|
||||
addPrimOp("__isString", 1, prim_isString);
|
||||
@@ -1076,7 +1249,7 @@ void EvalState::createBaseEnv()
|
||||
addPrimOp("__toFile", 2, prim_toFile);
|
||||
addPrimOp("__filterSource", 2, prim_filterSource);
|
||||
|
||||
// Attribute sets
|
||||
// Sets
|
||||
addPrimOp("__attrNames", 1, prim_attrNames);
|
||||
addPrimOp("__getAttr", 2, prim_getAttr);
|
||||
addPrimOp("__hasAttr", 2, prim_hasAttr);
|
||||
@@ -1088,11 +1261,15 @@ void EvalState::createBaseEnv()
|
||||
|
||||
// Lists
|
||||
addPrimOp("__isList", 1, prim_isList);
|
||||
addPrimOp("__elemAt", 2, prim_elemAt);
|
||||
addPrimOp("__head", 1, prim_head);
|
||||
addPrimOp("__tail", 1, prim_tail);
|
||||
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);
|
||||
|
||||
|
||||
// Integer arithmetic
|
||||
addPrimOp("__add", 2, prim_add);
|
||||
addPrimOp("__sub", 2, prim_sub);
|
||||
@@ -1106,6 +1283,7 @@ void EvalState::createBaseEnv()
|
||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||
addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
|
||||
addPrimOp("__hashString", 2, prim_hashString);
|
||||
|
||||
// Versions
|
||||
addPrimOp("__parseDrvName", 1, prim_parseDrvName);
|
||||
@@ -1116,11 +1294,13 @@ void EvalState::createBaseEnv()
|
||||
|
||||
/* Add a wrapper around the derivation primop that computes the
|
||||
`drvPath' and `outPath' attributes lazily. */
|
||||
mkThunk_(v, parseExprFromFile(findFile("nix/derivation.nix")));
|
||||
string path = findFile("nix/derivation.nix");
|
||||
sDerivationNix = symbols.create(path);
|
||||
evalFile(path, v);
|
||||
addConstant("derivation", v);
|
||||
|
||||
/* Now that we've added all primops, sort the `builtins' attribute
|
||||
set, because attribute lookups expect it to be sorted. */
|
||||
/* Now that we've added all primops, sort the `builtins' set,
|
||||
because attribute lookups expect it to be sorted. */
|
||||
baseEnv.values[0]->attrs->sort();
|
||||
}
|
||||
|
||||
|
||||
+16
-13
@@ -1,5 +1,4 @@
|
||||
#ifndef __SYMBOL_TABLE_H
|
||||
#define __SYMBOL_TABLE_H
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -14,11 +13,10 @@
|
||||
namespace nix {
|
||||
|
||||
/* Symbol table used by the parser and evaluator to represent and look
|
||||
up identifiers and attribute sets efficiently.
|
||||
SymbolTable::create() converts a string into a symbol. Symbols
|
||||
have the property that they can be compared efficiently (using a
|
||||
pointer equality test), because the symbol table stores only one
|
||||
copy of each string. */
|
||||
up identifiers and attributes efficiently. SymbolTable::create()
|
||||
converts a string into a symbol. Symbols have the property that
|
||||
they can be compared efficiently (using a pointer equality test),
|
||||
because the symbol table stores only one copy of each string. */
|
||||
|
||||
class Symbol
|
||||
{
|
||||
@@ -29,17 +27,17 @@ private:
|
||||
|
||||
public:
|
||||
Symbol() : s(0) { };
|
||||
|
||||
|
||||
bool operator == (const Symbol & s2) const
|
||||
{
|
||||
return s == s2.s;
|
||||
}
|
||||
|
||||
|
||||
bool operator != (const Symbol & s2) const
|
||||
{
|
||||
return s != s2.s;
|
||||
}
|
||||
|
||||
|
||||
bool operator < (const Symbol & s2) const
|
||||
{
|
||||
return s < s2.s;
|
||||
@@ -50,6 +48,11 @@ public:
|
||||
return *s;
|
||||
}
|
||||
|
||||
bool set() const
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return s->empty();
|
||||
@@ -67,7 +70,7 @@ inline std::ostream & operator << (std::ostream & str, const Symbol & sym)
|
||||
class SymbolTable
|
||||
{
|
||||
private:
|
||||
#if HAVE_TR1_UNORDERED_SET
|
||||
#if HAVE_TR1_UNORDERED_SET
|
||||
typedef std::tr1::unordered_set<string> Symbols;
|
||||
#else
|
||||
typedef std::set<string> Symbols;
|
||||
@@ -85,8 +88,8 @@ public:
|
||||
{
|
||||
return symbols.size();
|
||||
}
|
||||
|
||||
size_t totalSize() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__SYMBOL_TABLE_H */
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef __VALUE_TO_XML_H
|
||||
#define __VALUE_TO_XML_H
|
||||
#pragma once
|
||||
|
||||
#include "nixexpr.hh"
|
||||
#include "eval.hh"
|
||||
@@ -13,5 +12,3 @@ void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, std::ostream & out, PathSet & context);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__VALUE_TO_XML_H */
|
||||
|
||||
+13
-13
@@ -1,5 +1,4 @@
|
||||
#ifndef __VALUE_H
|
||||
#define __VALUE_H
|
||||
#pragma once
|
||||
|
||||
#include "symbol-table.hh"
|
||||
|
||||
@@ -32,17 +31,20 @@ struct PrimOp;
|
||||
struct Symbol;
|
||||
|
||||
|
||||
typedef long NixInt;
|
||||
|
||||
|
||||
struct Value
|
||||
{
|
||||
ValueType type;
|
||||
union
|
||||
union
|
||||
{
|
||||
int integer;
|
||||
NixInt integer;
|
||||
bool boolean;
|
||||
|
||||
/* Strings in the evaluator carry a so-called `context' (the
|
||||
ATermList) which is a list of strings representing store
|
||||
paths. This is to allow users to write things like
|
||||
|
||||
/* Strings in the evaluator carry a so-called `context' which
|
||||
is a list of strings representing store paths. This is to
|
||||
allow users to write things like
|
||||
|
||||
"--with-freetype2-library=" + freetype + "/lib"
|
||||
|
||||
@@ -64,7 +66,7 @@ struct Value
|
||||
const char * s;
|
||||
const char * * context; // must be in sorted order
|
||||
} string;
|
||||
|
||||
|
||||
const char * path;
|
||||
Bindings * attrs;
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
libmain_la_SOURCES = shared.cc
|
||||
libmain_la_SOURCES = shared.cc stack.cc
|
||||
|
||||
libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@
|
||||
|
||||
pkginclude_HEADERS = shared.hh
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
-DNIX_VERSION=\"$(VERSION)\" \
|
||||
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
||||
-I$(srcdir)/../libstore
|
||||
|
||||
+67
-95
@@ -10,8 +10,10 @@
|
||||
#include <cctype>
|
||||
#include <exception>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
#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()
|
||||
{
|
||||
static bool haveWarned = false;
|
||||
warnOnce(haveWarned,
|
||||
warnOnce(haveWarned,
|
||||
"you did not specify `--add-root'; "
|
||||
"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;
|
||||
PathSet willBuild, willSubstitute, unknown;
|
||||
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()) {
|
||||
printMsg(lvlInfo, format("these derivations will be built:"));
|
||||
foreach (PathSet::iterator, i, willBuild)
|
||||
@@ -74,7 +73,7 @@ void printMissing(StoreAPI & store, const PathSet & paths)
|
||||
|
||||
if (!unknown.empty()) {
|
||||
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)
|
||||
printMsg(lvlInfo, format(" %1%") % *i);
|
||||
}
|
||||
@@ -93,12 +92,25 @@ static void setLogType(string lt)
|
||||
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
|
||||
processor. */
|
||||
static void initAndRun(int argc, char * * argv)
|
||||
{
|
||||
setDefaultsFromEnvironment();
|
||||
|
||||
settings.processEnvironment();
|
||||
settings.loadConfFile();
|
||||
|
||||
/* Catch SIGINT. */
|
||||
struct sigaction act;
|
||||
act.sa_handler = sigintHandler;
|
||||
@@ -123,12 +135,19 @@ static void initAndRun(int argc, char * * argv)
|
||||
if (sigaction(SIGCHLD, &act, 0))
|
||||
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
|
||||
now. In particular, store objects should be readable by
|
||||
everybody. This prevents nasty surprises when using a shared
|
||||
store (with the setuid() hack). */
|
||||
everybody. */
|
||||
umask(0022);
|
||||
|
||||
/* Initialise the PRNG. */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
srandom(tv.tv_usec);
|
||||
|
||||
/* Process the NIX_LOG_TYPE environment variable. */
|
||||
string lt = getEnv("NIX_LOG_TYPE");
|
||||
if (lt != "") setLogType(lt);
|
||||
@@ -137,7 +156,7 @@ static void initAndRun(int argc, char * * argv)
|
||||
Strings args, remaining;
|
||||
while (argc--) args.push_back(*argv++);
|
||||
args.erase(args.begin());
|
||||
|
||||
|
||||
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
|
||||
ignore options for the ATerm library. */
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
@@ -156,46 +175,44 @@ static void initAndRun(int argc, char * * argv)
|
||||
remaining.clear();
|
||||
|
||||
/* Process default options. */
|
||||
int verbosityDelta = 0;
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
string arg = *i;
|
||||
if (arg == "--verbose" || arg == "-v") verbosityDelta++;
|
||||
else if (arg == "--quiet") verbosityDelta--;
|
||||
if (arg == "--verbose" || arg == "-v") verbosity = (Verbosity) (verbosity + 1);
|
||||
else if (arg == "--quiet") verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError;
|
||||
else if (arg == "--log-type") {
|
||||
++i;
|
||||
if (i == args.end()) throw UsageError("`--log-type' requires an argument");
|
||||
setLogType(*i);
|
||||
string s = getArg(arg, i, args.end());
|
||||
setLogType(s);
|
||||
}
|
||||
else if (arg == "--no-build-output" || arg == "-Q")
|
||||
buildVerbosity = lvlVomit;
|
||||
settings.buildVerbosity = lvlVomit;
|
||||
else if (arg == "--print-build-trace")
|
||||
printBuildTrace = true;
|
||||
settings.printBuildTrace = true;
|
||||
else if (arg == "--help") {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else if (arg == "--keep-failed" || arg == "-K")
|
||||
keepFailed = true;
|
||||
settings.keepFailed = true;
|
||||
else if (arg == "--keep-going" || arg == "-k")
|
||||
keepGoing = true;
|
||||
settings.keepGoing = true;
|
||||
else if (arg == "--fallback")
|
||||
tryFallback = true;
|
||||
settings.set("build-fallback", "true");
|
||||
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")
|
||||
buildCores = getIntArg<unsigned int>(arg, i, args.end());
|
||||
settings.set("build-cores", getArg(arg, i, args.end()));
|
||||
else if (arg == "--readonly-mode")
|
||||
readOnlyMode = true;
|
||||
settings.readOnlyMode = true;
|
||||
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")
|
||||
buildTimeout = getIntArg<unsigned int>(arg, i, args.end());
|
||||
settings.set("build-timeout", getArg(arg, i, args.end()));
|
||||
else if (arg == "--no-build-hook")
|
||||
useBuildHook = false;
|
||||
settings.useBuildHook = false;
|
||||
else if (arg == "--show-trace")
|
||||
showTrace = true;
|
||||
else if (arg == "--option") {
|
||||
@@ -203,14 +220,13 @@ static void initAndRun(int argc, char * * argv)
|
||||
string name = *i;
|
||||
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
||||
string value = *i;
|
||||
overrideSetting(name, tokenizeString(value));
|
||||
settings.set(name, value);
|
||||
}
|
||||
else remaining.push_back(arg);
|
||||
}
|
||||
|
||||
verbosityDelta += queryIntSetting("verbosity", lvlInfo);
|
||||
verbosity = (Verbosity) (verbosityDelta < 0 ? 0 : verbosityDelta);
|
||||
|
||||
settings.update();
|
||||
|
||||
run(remaining);
|
||||
|
||||
/* 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. */
|
||||
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;
|
||||
char * * argvSaved = 0;
|
||||
|
||||
@@ -290,11 +264,6 @@ int main(int argc, char * * 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. */
|
||||
#if HAVE_PUBSETBUF
|
||||
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
|
||||
@@ -323,7 +292,7 @@ int main(int argc, char * * argv)
|
||||
throw;
|
||||
}
|
||||
} catch (UsageError & e) {
|
||||
printMsg(lvlError,
|
||||
printMsg(lvlError,
|
||||
format(
|
||||
"error: %1%\n"
|
||||
"Try `%2% --help' for more information.")
|
||||
@@ -334,6 +303,9 @@ int main(int argc, char * * argv)
|
||||
if (e.prefix() != "" && !showTrace)
|
||||
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
|
||||
return e.status;
|
||||
} catch (std::bad_alloc & e) {
|
||||
printMsg(lvlError, "error: out of memory");
|
||||
return 1;
|
||||
} catch (std::exception & e) {
|
||||
printMsg(lvlError, format("error: %1%") % e.what());
|
||||
return 1;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef __SHARED_H
|
||||
#define __SHARED_H
|
||||
#pragma once
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
@@ -27,11 +26,14 @@ MakeError(UsageError, nix::Error);
|
||||
class StoreAPI;
|
||||
|
||||
/* Ugh. No better place to put this. */
|
||||
Path makeRootName(const Path & gcRoot, int & counter);
|
||||
void printGCWarning();
|
||||
|
||||
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,
|
||||
Strings::iterator & i, const Strings::iterator & end)
|
||||
{
|
||||
@@ -43,8 +45,8 @@ template<class N> N getIntArg(const string & opt,
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Whether we're running setuid. */
|
||||
extern bool setuidMode;
|
||||
/* Show the manual page for the specified program. */
|
||||
void showManPage(const string & name);
|
||||
|
||||
extern volatile ::sig_atomic_t blockInt;
|
||||
|
||||
@@ -54,6 +56,3 @@ extern int exitCode;
|
||||
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 \
|
||||
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
|
||||
|
||||
@@ -23,10 +23,11 @@ AM_CXXFLAGS = -Wall \
|
||||
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
|
||||
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
|
||||
-DNIX_BIN_DIR=\"$(bindir)\" \
|
||||
-DNIX_VERSION=\"$(VERSION)\" \
|
||||
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
||||
-I$(srcdir)/../libstore
|
||||
|
||||
local-store.lo: schema.sql.hh
|
||||
|
||||
%.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