Compare commits
543 Commits
sharing-ha
...
fast-eval
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd25ac2260 | ||
|
|
81a4b4e49b | ||
|
|
1a8eb6e3ec | ||
|
|
83dfa89870 | ||
|
|
01e58adce0 | ||
|
|
83d7b89660 | ||
|
|
e2d5e40f4f | ||
|
|
84ce7ac76f | ||
|
|
4750065ada | ||
|
|
4bab25a28d | ||
|
|
c82782f9a5 | ||
|
|
d77331d32f | ||
|
|
2be6118f4c | ||
|
|
0bc468f195 | ||
|
|
ee0384fb96 | ||
|
|
ebade9ff8b | ||
|
|
2d7636529f | ||
|
|
6bbfe95e30 | ||
|
|
7148df7971 | ||
|
|
6f0f16497a | ||
|
|
cae4efdca3 | ||
|
|
0777448ca6 | ||
|
|
fe2d869e04 | ||
|
|
f3b8833a48 | ||
|
|
efc7a579e8 | ||
|
|
55b5ddd3ca | ||
|
|
b7ff69eb7c | ||
|
|
5c31995bb8 | ||
|
|
8bb0210fea | ||
|
|
8ca4a001cb | ||
|
|
497e4ad126 | ||
|
|
02c1dac909 | ||
|
|
04c4bd3624 | ||
|
|
e41b5828db | ||
|
|
d39d3c6264 | ||
|
|
267dc693d2 | ||
|
|
81de12bc8f | ||
|
|
110d155778 | ||
|
|
9985230c00 | ||
|
|
816dd3f061 | ||
|
|
011b5da0f4 | ||
|
|
85d13c8f93 | ||
|
|
816f9c0f6f | ||
|
|
7d47498b5e | ||
|
|
ac1e8f40d4 | ||
|
|
10e8b1fd15 | ||
|
|
0d272fca79 | ||
|
|
d4f0b0fc6c | ||
|
|
a60317f20f | ||
|
|
4d6ad5be17 | ||
|
|
ed711f73bc | ||
|
|
db90b88e65 | ||
|
|
4e49002576 | ||
|
|
c3f228f296 | ||
|
|
aac5fcfbb5 | ||
|
|
f3dc7ab877 | ||
|
|
b7b3dd55f9 | ||
|
|
7e048eddf5 | ||
|
|
af2a372bb0 | ||
|
|
9a64454faa | ||
|
|
fc92244ba8 | ||
|
|
a353aef0b1 | ||
|
|
a5ece7d016 | ||
|
|
c172274e17 | ||
|
|
7b851915bf | ||
|
|
95cc417d76 | ||
|
|
71f026292b | ||
|
|
dc31305b38 | ||
|
|
979f163615 | ||
|
|
d8cd3115d8 | ||
|
|
55e207b2dc | ||
|
|
3d94be61ea | ||
|
|
5187678913 | ||
|
|
f061086a93 | ||
|
|
09381cccff | ||
|
|
13c2adc897 | ||
|
|
4c53ca2692 | ||
|
|
471419d1fa | ||
|
|
eb07a4f1ee | ||
|
|
7f19e03c65 | ||
|
|
47df476daa | ||
|
|
c9170be2bd | ||
|
|
c3aa615a5f | ||
|
|
5b72d8a749 | ||
|
|
d78a05ab40 | ||
|
|
31428c3a06 | ||
|
|
52090d2418 | ||
|
|
e3f32ac5af | ||
|
|
807a67bc74 | ||
|
|
392811eb8f | ||
|
|
d96cdcea6b | ||
|
|
3d2b835f30 | ||
|
|
45d822f29c | ||
|
|
cad8726b2c | ||
|
|
8da118e4d0 | ||
|
|
c2ba4313fb | ||
|
|
25eedf085d | ||
|
|
3c9f8fc9b6 | ||
|
|
f450384ded | ||
|
|
ef8bd919fc | ||
|
|
8a10360c91 | ||
|
|
7482349fe8 | ||
|
|
0fd3648d34 | ||
|
|
b70bd8fe56 | ||
|
|
d31c59eb17 | ||
|
|
e8f7978274 | ||
|
|
0910ae9568 | ||
|
|
90039e0863 | ||
|
|
71be50cc25 | ||
|
|
3bfd3a4e95 | ||
|
|
141294ff38 | ||
|
|
74299c1cfb | ||
|
|
c4cfb392d3 | ||
|
|
8e3d98eb41 | ||
|
|
f0c473c5f7 | ||
|
|
fe1b8781ae | ||
|
|
741b7577c1 | ||
|
|
2fb0df83e9 | ||
|
|
13cce8ec45 | ||
|
|
05e15049a5 | ||
|
|
c752c9f41a | ||
|
|
2e8eaca573 | ||
|
|
05fbf61f0e | ||
|
|
84a4dd5ff0 | ||
|
|
7db2831d3a | ||
|
|
5ccb6f64f4 | ||
|
|
68e55cd9da | ||
|
|
3b3e1025c3 | ||
|
|
20186a4079 | ||
|
|
d0bf4adb1f | ||
|
|
e08dbff9a8 | ||
|
|
e1e91a3731 | ||
|
|
817f4f7908 | ||
|
|
f36b7e7579 | ||
|
|
719cebcac2 | ||
|
|
443673620d | ||
|
|
7ec5a65925 | ||
|
|
c9b2d80bcd | ||
|
|
3cfe65e516 | ||
|
|
e51a276907 | ||
|
|
408913bbaf | ||
|
|
4e17be7981 | ||
|
|
f859a8d3c3 | ||
|
|
c45de33c67 | ||
|
|
d0c32dc135 | ||
|
|
f56a039775 | ||
|
|
bc1e478db1 | ||
|
|
4d8a85b8f5 | ||
|
|
3ce5f07793 | ||
|
|
e839802720 | ||
|
|
4bbbe25802 | ||
|
|
2723d9b56e | ||
|
|
07ffdc2862 | ||
|
|
ad529fb89f | ||
|
|
fdcaf37361 | ||
|
|
50e34891f0 | ||
|
|
5388944e8d | ||
|
|
f0c0277970 | ||
|
|
ef92a14bfe | ||
|
|
945d8218fb | ||
|
|
d8a5dc02fc | ||
|
|
3a78af1e24 | ||
|
|
7ca9972636 | ||
|
|
c4c84d1edb | ||
|
|
bcd6cdf0d8 | ||
|
|
13618b191e | ||
|
|
aa5a768720 | ||
|
|
9b8fda796b | ||
|
|
8022015552 | ||
|
|
f9e766db98 | ||
|
|
ca50c83fbb | ||
|
|
3d55f1eb57 | ||
|
|
ae6bf87273 | ||
|
|
c364d5d1e3 | ||
|
|
4f7e5f5810 | ||
|
|
8824d60fe5 | ||
|
|
997db91e07 | ||
|
|
3392d32e8b | ||
|
|
327a232c85 | ||
|
|
c60d796f04 | ||
|
|
e8bad77c7c | ||
|
|
7680904839 | ||
|
|
58f3338bfa | ||
|
|
268d90a03e | ||
|
|
1ff8758f76 | ||
|
|
8520542071 | ||
|
|
6b9f6b0222 | ||
|
|
deb342fb08 | ||
|
|
437077c39d | ||
|
|
6f7d7bc1de | ||
|
|
53a4981fa2 | ||
|
|
18f0ff003d | ||
|
|
96f1517831 | ||
|
|
1a8f8fd86f | ||
|
|
0f79ad47c5 | ||
|
|
c7057fc1f2 | ||
|
|
193f59e077 | ||
|
|
0ae2be5692 | ||
|
|
1332dd1ed3 | ||
|
|
63a17d4bd5 | ||
|
|
676e07902e | ||
|
|
64e89980e8 | ||
|
|
48b58617e9 | ||
|
|
51ad64cc07 | ||
|
|
df05a759e4 | ||
|
|
d3de71efc9 | ||
|
|
e1df4ef73c | ||
|
|
86408b3f47 | ||
|
|
57e0d73c77 | ||
|
|
0dbd4638e0 | ||
|
|
3bca8931e8 | ||
|
|
5e9a4e5101 | ||
|
|
9b46d1ae6f | ||
|
|
20b6f94b65 | ||
|
|
d413612029 | ||
|
|
1f169f43b3 | ||
|
|
5e2e2f10ef | ||
|
|
c6890d6b5c | ||
|
|
749dd97a54 | ||
|
|
f2c3fc5191 | ||
|
|
a2fc3a53ba | ||
|
|
d53603c928 | ||
|
|
14bc3ce3d6 | ||
|
|
f24cf5d303 | ||
|
|
c6cb792d48 | ||
|
|
a64bbe049e | ||
|
|
d407d572fd | ||
|
|
e42975490f | ||
|
|
50d11b90ca | ||
|
|
c34e6d71bc | ||
|
|
9536ba19d4 | ||
|
|
83bd320b39 | ||
|
|
f751c2966b | ||
|
|
404996ca1f | ||
|
|
7660e2a068 | ||
|
|
52a9ba96f5 | ||
|
|
6a5599fd01 | ||
|
|
098cb9d233 | ||
|
|
c710fe540e | ||
|
|
d5eab2fc82 | ||
|
|
8f1bf28505 | ||
|
|
4e646b0ddb | ||
|
|
0460ea4c39 | ||
|
|
dfb863f333 | ||
|
|
435a93b5d8 | ||
|
|
8b2a01a8c2 | ||
|
|
50cb6f9782 | ||
|
|
351bf658f9 | ||
|
|
cff2b2a13a | ||
|
|
160a60d663 | ||
|
|
805144b705 | ||
|
|
096affb55b | ||
|
|
cbc1f57b48 | ||
|
|
7377195297 | ||
|
|
737423a89c | ||
|
|
47706e3924 | ||
|
|
6e946c8e72 | ||
|
|
c7152c8f97 | ||
|
|
3a2bbe7f8a | ||
|
|
7fb548aa26 | ||
|
|
f54e800366 | ||
|
|
38f98b3282 | ||
|
|
e23a7a8b7b | ||
|
|
cb85bc396e | ||
|
|
61686926d1 | ||
|
|
9856efc7b0 | ||
|
|
5dd8fb2069 | ||
|
|
92f525ecf4 | ||
|
|
7024a1ef07 | ||
|
|
8146a0c731 | ||
|
|
a046858a22 | ||
|
|
12c8c64efa | ||
|
|
7aedcf9460 | ||
|
|
3a87163b24 | ||
|
|
cacff1be88 | ||
|
|
58969fa2bf | ||
|
|
d7b2d11255 | ||
|
|
7a57b2920b | ||
|
|
77d272623f | ||
|
|
7e05b8b75e | ||
|
|
b88460bcbc | ||
|
|
2897286487 | ||
|
|
e530e0a350 | ||
|
|
9485ec31ea | ||
|
|
13df3915ef | ||
|
|
c183ee5c79 | ||
|
|
1dcf208f56 | ||
|
|
93b6926054 | ||
|
|
51e7e32c3b | ||
|
|
2d5114452d | ||
|
|
33ecb42991 | ||
|
|
be88248add | ||
|
|
a96cac0d18 | ||
|
|
d4753c944f | ||
|
|
0e6f604178 | ||
|
|
7f254706b0 | ||
|
|
1273d355ac | ||
|
|
d4ca5c3952 | ||
|
|
fd2e14b3c8 | ||
|
|
60cb7de336 | ||
|
|
8ab6bc5a49 | ||
|
|
f052c10eed | ||
|
|
a7cee528c5 | ||
|
|
041717eda3 | ||
|
|
621093cb1c | ||
|
|
824b154ce8 | ||
|
|
2ef579d1aa | ||
|
|
1407a1ec99 | ||
|
|
1bb0f1e84b | ||
|
|
b682fae9d9 | ||
|
|
6f8c96d123 | ||
|
|
110606d470 | ||
|
|
061141e632 | ||
|
|
019176137f | ||
|
|
4ce692df88 | ||
|
|
c504d90c11 | ||
|
|
8e39d9bdb3 | ||
|
|
28355dafcf | ||
|
|
8fce03e0ad | ||
|
|
60ec75048a | ||
|
|
6f6bb1fdea | ||
|
|
92cb7c4dfe | ||
|
|
0008b0006d | ||
|
|
ac36c6cd44 | ||
|
|
2b70a8e7c9 | ||
|
|
9122dcecbb | ||
|
|
6776a52bb3 | ||
|
|
d86bd22d24 | ||
|
|
ac5478eb52 | ||
|
|
652817046b | ||
|
|
5a569509b4 | ||
|
|
7c54f1603f | ||
|
|
07cdfb09fb | ||
|
|
a0766eca27 | ||
|
|
cd16d5dc3d | ||
|
|
5b949241a5 | ||
|
|
67958f21df | ||
|
|
d91dc086bb | ||
|
|
9ac3f5df9c | ||
|
|
bcfe98acff | ||
|
|
9850262a72 | ||
|
|
909fbb9de1 | ||
|
|
5dfba0b4db | ||
|
|
9ccdb80de3 | ||
|
|
9fd9c4c635 | ||
|
|
63b8f09d8d | ||
|
|
f8713e1287 | ||
|
|
82ae85de27 | ||
|
|
5eaf644c99 | ||
|
|
cdee317419 | ||
|
|
d95b68fde3 | ||
|
|
ff762fb499 | ||
|
|
1307b22223 | ||
|
|
64519cfd65 | ||
|
|
09bc0c502c | ||
|
|
5d4eb9dd07 | ||
|
|
0c478d2f4d | ||
|
|
5024bde8f4 | ||
|
|
2ab09a55cf | ||
|
|
6bbff48079 | ||
|
|
b8eb32f4d2 | ||
|
|
bba87589cc | ||
|
|
f3e2e6076a | ||
|
|
53cca4a445 | ||
|
|
4213b8d8ec | ||
|
|
eb86b6f5a5 | ||
|
|
3d2035ea86 | ||
|
|
285d26374a | ||
|
|
a55113411f | ||
|
|
c202523e53 | ||
|
|
aab530e971 | ||
|
|
60564410ef | ||
|
|
2668a43388 | ||
|
|
63ccd72496 | ||
|
|
e13da525a7 | ||
|
|
5d250ad1ea | ||
|
|
7509d70f9d | ||
|
|
2369b122d1 | ||
|
|
6c2c771af7 | ||
|
|
07d3a38726 | ||
|
|
f5325d292d | ||
|
|
fa791116a3 | ||
|
|
3f4ed681c2 | ||
|
|
6fedb7aa0f | ||
|
|
a519bb0635 | ||
|
|
96598e7b06 | ||
|
|
4166b11a53 | ||
|
|
2b7c839b4e | ||
|
|
709b55ee02 | ||
|
|
c98ea254dc | ||
|
|
9d6d50269b | ||
|
|
fa61ee70ee | ||
|
|
f32fef1b07 | ||
|
|
4af2fdba6d | ||
|
|
c987061aa4 | ||
|
|
77afd97a99 | ||
|
|
7ab68961e4 | ||
|
|
2b2aa8a820 | ||
|
|
7933cdc6dc | ||
|
|
0f0dbe8c0c | ||
|
|
311c222f47 | ||
|
|
2a01d06da6 | ||
|
|
7718b19389 | ||
|
|
9cc0da8453 | ||
|
|
99dc3e613a | ||
|
|
d06be428f6 | ||
|
|
abec1c0004 | ||
|
|
c4f1c2114b | ||
|
|
49829da8b4 | ||
|
|
b428adc267 | ||
|
|
cc826dc03e | ||
|
|
51e2dda58c | ||
|
|
b7ff182b6e | ||
|
|
ca07f3e370 | ||
|
|
9279174dde | ||
|
|
db4f4a8425 | ||
|
|
1b962fc720 | ||
|
|
e818838412 | ||
|
|
efe4b690ae | ||
|
|
c03b729319 | ||
|
|
5664b6d7ba | ||
|
|
b455c4c45c | ||
|
|
72f3ea7358 | ||
|
|
98b07466fb | ||
|
|
339c142009 | ||
|
|
a87b5256e2 | ||
|
|
001b3f06ec | ||
|
|
7592f48c83 | ||
|
|
a1d310b6b5 | ||
|
|
42043953c3 | ||
|
|
5adbb0aabe | ||
|
|
5b1052663a | ||
|
|
c4f98941ed | ||
|
|
03427e76f1 | ||
|
|
b3c26180e3 | ||
|
|
3c92ea399d | ||
|
|
fc691e1cbd | ||
|
|
096198d11f | ||
|
|
660244f65f | ||
|
|
e139d7fc68 | ||
|
|
989176c56e | ||
|
|
8bc591a6f0 | ||
|
|
15f39aba8c | ||
|
|
7cd88b1dec | ||
|
|
d567baabbd | ||
|
|
b3b0b2a29e | ||
|
|
6c8641a542 | ||
|
|
5af84139a8 | ||
|
|
d3aa183beb | ||
|
|
a8f3b02092 | ||
|
|
a72709afd8 | ||
|
|
934c58aa38 | ||
|
|
ee8f15930d | ||
|
|
f351834f77 | ||
|
|
94fd46fa1c | ||
|
|
955b8841cd | ||
|
|
18e27629d3 | ||
|
|
826b271d9a | ||
|
|
30c9f909b2 | ||
|
|
194c66eeeb | ||
|
|
f903d86740 | ||
|
|
ce85b55cf0 | ||
|
|
4532e4b90d | ||
|
|
2818b7cee6 | ||
|
|
997b95a4af | ||
|
|
b0e92f6d47 | ||
|
|
4ed01ed791 | ||
|
|
c41a3ec3a9 | ||
|
|
bd955e15e1 | ||
|
|
9819bb20da | ||
|
|
b4bc8b7616 | ||
|
|
b1e321d6ce | ||
|
|
658816ddc9 | ||
|
|
72034ab35d | ||
|
|
f8985d195e | ||
|
|
329025253d | ||
|
|
5bb08db55b | ||
|
|
98968fbb63 | ||
|
|
2f1e2cf632 | ||
|
|
f106868110 | ||
|
|
f789ea1d09 | ||
|
|
d7caac3e81 | ||
|
|
11d512e7a8 | ||
|
|
0a84137c45 | ||
|
|
0ed89c569f | ||
|
|
4066f450c2 | ||
|
|
e7bdde981f | ||
|
|
66c51dc215 | ||
|
|
5b5a3af983 | ||
|
|
5eb5c23447 | ||
|
|
7d0f6aed59 | ||
|
|
895c953817 | ||
|
|
d4117859d6 | ||
|
|
e0ca671491 | ||
|
|
6bdecfacbb | ||
|
|
454f571f87 | ||
|
|
4c82983010 | ||
|
|
f60aa2aa21 | ||
|
|
dedd62dd0c | ||
|
|
b5ddcf58ad | ||
|
|
59707975a3 | ||
|
|
de012e76e2 | ||
|
|
2196cb67c5 | ||
|
|
df303666bc | ||
|
|
1e90b4189d | ||
|
|
485d71c54a | ||
|
|
30e4653783 | ||
|
|
4ff1335b2e | ||
|
|
3a2833daff | ||
|
|
764b0115d5 | ||
|
|
b42ef9c054 | ||
|
|
d4950f207f | ||
|
|
6d6c68c0d2 | ||
|
|
633518628f | ||
|
|
12d0a1eb75 | ||
|
|
06f95dd07c | ||
|
|
c370755583 | ||
|
|
c05783ad67 | ||
|
|
6784b14241 | ||
|
|
ca210d2a58 | ||
|
|
149e273023 | ||
|
|
bfec245efa | ||
|
|
6fc60e2060 | ||
|
|
5b74a59570 | ||
|
|
5f8a203b55 | ||
|
|
1511aa11ce | ||
|
|
fa44e401a8 | ||
|
|
e007b50eb7 | ||
|
|
bfea7b1f35 | ||
|
|
0b95603595 | ||
|
|
42d80d1170 | ||
|
|
d91cd30563 | ||
|
|
dc6f373842 | ||
|
|
9397cd30c8 | ||
|
|
0b4ed64d29 | ||
|
|
cd08fb3fde | ||
|
|
d423968ba1 | ||
|
|
612b3e8fa3 | ||
|
|
35ac16e75e | ||
|
|
1db187ff69 | ||
|
|
f90d85107e | ||
|
|
f8ed2e64a5 | ||
|
|
f529a3be8a |
262
.gitignore
vendored
Normal file
262
.gitignore
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
# START "git svn show-ignore"
|
||||
|
||||
# /
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/config.*
|
||||
/configure
|
||||
/nix.spec
|
||||
/stamp-h1
|
||||
/svn-revision
|
||||
/NEWS
|
||||
/libtool
|
||||
|
||||
# /config/
|
||||
/config/config.guess
|
||||
/config/config.sub
|
||||
/config/depcomp
|
||||
/config/install-sh
|
||||
/config/missing
|
||||
/config/mkinstalldirs
|
||||
/config/ltmain.sh
|
||||
|
||||
# /corepkgs/
|
||||
/corepkgs/Makefile
|
||||
/corepkgs/Makefile.in
|
||||
|
||||
# /corepkgs/buildenv/
|
||||
/corepkgs/buildenv/Makefile.in
|
||||
/corepkgs/buildenv/Makefile
|
||||
/corepkgs/buildenv/builder.pl
|
||||
|
||||
# /corepkgs/channels/
|
||||
/corepkgs/channels/Makefile.in
|
||||
/corepkgs/channels/Makefile
|
||||
/corepkgs/channels/unpack.sh
|
||||
|
||||
# /corepkgs/nar/
|
||||
/corepkgs/nar/Makefile
|
||||
/corepkgs/nar/Makefile.in
|
||||
/corepkgs/nar/nar.sh
|
||||
/corepkgs/nar/unnar.sh
|
||||
|
||||
# /doc/
|
||||
/doc/Makefile
|
||||
/doc/Makefile.in
|
||||
|
||||
# /doc/manual/
|
||||
/doc/manual/Makefile
|
||||
/doc/manual/Makefile.in
|
||||
/doc/manual/manual.html
|
||||
/doc/manual/manual.is-valid
|
||||
/doc/manual/*.1
|
||||
/doc/manual/*.8
|
||||
/doc/manual/images
|
||||
/doc/manual/version.txt
|
||||
/doc/manual/NEWS.html
|
||||
/doc/manual/NEWS.txt
|
||||
|
||||
# /externals/
|
||||
/externals/Makefile
|
||||
/externals/Makefile.in
|
||||
/externals/aterm-*
|
||||
/externals/have-aterm
|
||||
/externals/build-aterm
|
||||
/externals/inst-aterm
|
||||
/externals/bzip2-*
|
||||
/externals/have-bzip2
|
||||
/externals/build-bzip2
|
||||
/externals/inst-bzip2
|
||||
|
||||
# /make/examples/aterm/
|
||||
/make/examples/aterm/result*
|
||||
|
||||
# /make/examples/aterm/aterm/
|
||||
/make/examples/aterm/aterm/*
|
||||
|
||||
# /make/examples/aterm/test/
|
||||
/make/examples/aterm/test/*
|
||||
|
||||
# /misc/
|
||||
/misc/Makefile.in
|
||||
/misc/Makefile
|
||||
|
||||
# /misc/emacs/
|
||||
/misc/emacs/Makefile.in
|
||||
/misc/emacs/Makefile
|
||||
|
||||
# /scripts/
|
||||
/scripts/Makefile
|
||||
/scripts/Makefile.in
|
||||
/scripts/nix-profile.sh
|
||||
/scripts/nix-pull
|
||||
/scripts/nix-push
|
||||
/scripts/nix-switch
|
||||
/scripts/nix-collect-garbage
|
||||
/scripts/nix-prefetch-url
|
||||
/scripts/nix-install-package
|
||||
/scripts/nix-channel
|
||||
/scripts/nix-build
|
||||
/scripts/nix-copy-closure
|
||||
/scripts/readmanifest.pm
|
||||
/scripts/readconfig.pm
|
||||
/scripts/download-using-manifests.pl
|
||||
/scripts/copy-from-other-stores.pl
|
||||
/scripts/generate-patches.pl
|
||||
/scripts/find-runtime-roots.pl
|
||||
/scripts/build-remote.pl
|
||||
|
||||
# /src/
|
||||
/src/Makefile
|
||||
/src/Makefile.in
|
||||
|
||||
# /src/bin2c/
|
||||
/src/bin2c/Makefile.in
|
||||
/src/bin2c/Makefile
|
||||
/src/bin2c/bin2c
|
||||
/src/bin2c/.deps
|
||||
/src/bin2c/.libs
|
||||
|
||||
# /src/boost/
|
||||
/src/boost/Makefile
|
||||
/src/boost/Makefile.in
|
||||
|
||||
# /src/boost/format/
|
||||
/src/boost/format/Makefile
|
||||
/src/boost/format/Makefile.in
|
||||
/src/boost/format/.deps
|
||||
/src/boost/format/libformat.a
|
||||
/src/boost/format/.libs
|
||||
|
||||
# /src/bsdiff-4.3/
|
||||
/src/bsdiff-4.3/Makefile
|
||||
/src/bsdiff-4.3/Makefile.in
|
||||
/src/bsdiff-4.3/bsdiff
|
||||
/src/bsdiff-4.3/bspatch
|
||||
/src/bsdiff-4.3/.deps
|
||||
/src/bsdiff-4.3/.libs
|
||||
|
||||
# /src/libexpr/
|
||||
/src/libexpr/Makefile
|
||||
/src/libexpr/Makefile.in
|
||||
/src/libexpr/.deps
|
||||
/src/libexpr/libexpr.a
|
||||
/src/libexpr/lexer-tab.cc
|
||||
/src/libexpr/lexer-tab.hh
|
||||
/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/.libs
|
||||
/src/libexpr/nix.tbl
|
||||
|
||||
# /src/libmain/
|
||||
/src/libmain/Makefile
|
||||
/src/libmain/Makefile.in
|
||||
/src/libmain/.deps
|
||||
/src/libmain/libmain.a
|
||||
/src/libmain/.libs
|
||||
|
||||
# /src/libstore/
|
||||
/src/libstore/Makefile
|
||||
/src/libstore/Makefile.in
|
||||
/src/libstore/.deps
|
||||
/src/libstore/libstore.a
|
||||
/src/libstore/derivations-ast.cc
|
||||
/src/libstore/derivations-ast.hh
|
||||
/src/libstore/.libs
|
||||
|
||||
# /src/libutil/
|
||||
/src/libutil/Makefile
|
||||
/src/libutil/Makefile.in
|
||||
/src/libutil/.deps
|
||||
/src/libutil/libutil.a
|
||||
/src/libutil/.libs
|
||||
|
||||
# /src/nix-env/
|
||||
/src/nix-env/Makefile.in
|
||||
/src/nix-env/Makefile
|
||||
/src/nix-env/.deps
|
||||
/src/nix-env/nix-env
|
||||
/src/nix-env/help.txt.hh
|
||||
/src/nix-env/.libs
|
||||
|
||||
# /src/nix-hash/
|
||||
/src/nix-hash/Makefile
|
||||
/src/nix-hash/Makefile.in
|
||||
/src/nix-hash/.deps
|
||||
/src/nix-hash/.libs
|
||||
/src/nix-hash/nix-hash
|
||||
/src/nix-hash/help.txt.hh
|
||||
|
||||
# /src/nix-instantiate/
|
||||
/src/nix-instantiate/Makefile.in
|
||||
/src/nix-instantiate/Makefile
|
||||
/src/nix-instantiate/.deps
|
||||
/src/nix-instantiate/nix-instantiate
|
||||
/src/nix-instantiate/help.txt.hh
|
||||
/src/nix-instantiate/.libs
|
||||
|
||||
# /src/nix-log2xml/
|
||||
/src/nix-log2xml/Makefile.in
|
||||
/src/nix-log2xml/Makefile
|
||||
/src/nix-log2xml/.deps
|
||||
/src/nix-log2xml/nix-log2xml
|
||||
/src/nix-log2xml/test*.*
|
||||
/src/nix-log2xml/.libs
|
||||
/src/nix-log2xml/*.log
|
||||
/src/nix-log2xml/*.xml
|
||||
/src/nix-log2xml/*.html
|
||||
|
||||
# /src/nix-setuid-helper/
|
||||
/src/nix-setuid-helper/Makefile.in
|
||||
/src/nix-setuid-helper/Makefile
|
||||
/src/nix-setuid-helper/.deps
|
||||
/src/nix-setuid-helper/nix-setuid-helper
|
||||
/src/nix-setuid-helper/help.txt.hh
|
||||
/src/nix-setuid-helper/.libs
|
||||
|
||||
# /src/nix-store/
|
||||
/src/nix-store/Makefile
|
||||
/src/nix-store/Makefile.in
|
||||
/src/nix-store/.deps
|
||||
/src/nix-store/help.txt.hh
|
||||
/src/nix-store/nix-store
|
||||
/src/nix-store/.libs
|
||||
|
||||
# /src/nix-worker/
|
||||
/src/nix-worker/Makefile.in
|
||||
/src/nix-worker/Makefile
|
||||
/src/nix-worker/.deps
|
||||
/src/nix-worker/nix-worker
|
||||
/src/nix-worker/help.txt.hh
|
||||
/src/nix-worker/.libs
|
||||
|
||||
# /tests/
|
||||
/tests/Makefile
|
||||
/tests/Makefile.in
|
||||
/tests/test-tmp
|
||||
/tests/config.nix
|
||||
/tests/common.sh
|
||||
/tests/dummy
|
||||
|
||||
# /tests/lang/
|
||||
/tests/lang/*.out
|
||||
/tests/lang/*.out.xml
|
||||
/tests/lang/*.ast
|
||||
|
||||
# END "git svn show-ignore"
|
||||
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
*~
|
||||
|
||||
# GNU Global
|
||||
GPATH
|
||||
GRTAGS
|
||||
GSYMS
|
||||
GTAGS
|
||||
25
Makefile.am
25
Makefile.am
@@ -1,23 +1,19 @@
|
||||
SUBDIRS = externals src scripts corepkgs doc misc tests
|
||||
EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \
|
||||
svn-revision nix.conf.example NEWS
|
||||
nix.conf.example NEWS version
|
||||
|
||||
include ./substitute.mk
|
||||
|
||||
nix.spec: nix.spec.in
|
||||
|
||||
rpm: nix.spec dist
|
||||
rpm $(EXTRA_RPM_FLAGS) -ta $(distdir).tar.gz
|
||||
|
||||
relname:
|
||||
echo -n $(distdir) > relname
|
||||
|
||||
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)/
|
||||
|
||||
if INIT_STATE
|
||||
|
||||
@@ -33,23 +29,18 @@ 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
|
||||
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/gcroots/tmp
|
||||
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/gcroots/channels
|
||||
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
|
||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
|
||||
$(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(prefix)/store
|
||||
-$(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(storedir)
|
||||
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
|
||||
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
|
||||
# $(bindir)/nix-store --init
|
||||
|
||||
else
|
||||
|
||||
init-state:
|
||||
|
||||
endif
|
||||
|
||||
svn-revision:
|
||||
svnversion . > svn-revision
|
||||
|
||||
all-local: NEWS
|
||||
|
||||
NEWS: doc/manual/NEWS.txt
|
||||
NEWS:
|
||||
$(MAKE) -C doc/manual NEWS.txt
|
||||
cp $(srcdir)/doc/manual/NEWS.txt NEWS
|
||||
|
||||
9
README
9
README
@@ -1,9 +1,10 @@
|
||||
For installation and usage instructions, please read the manual, which
|
||||
can be found in `docs/manual/manual.html', and additionally at the Nix
|
||||
website at <http://www.cs.uu.nl/groups/ST/Trace/Nix>.
|
||||
Nix is a purely functional package manager. For installation and
|
||||
usage instructions, please read the manual, which can be found in
|
||||
`docs/manual/manual.html', and additionally at the Nix website at
|
||||
<http://nixos.org/>.
|
||||
|
||||
|
||||
Acknowledgments
|
||||
|
||||
This product includes software developed by the OpenSSL Project for
|
||||
use in the OpenSSL Toolkit (http://www.OpenSSL.org/)
|
||||
use in the OpenSSL Toolkit (http://www.OpenSSL.org/).
|
||||
|
||||
235
aterm-gc.supp
235
aterm-gc.supp
@@ -1,184 +1,117 @@
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_markTerm_young
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_markTerm_young
|
||||
fun:mark_memory_young
|
||||
fun:mark_phase_young
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_markTerm
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_markTerm
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_markTerm
|
||||
fun:mark_memory
|
||||
fun:mark_phase
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:mark_phase_young
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:mark_phase_young
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_phase_young
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value8
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:AT_isValidSymbol
|
||||
fun:mark_phase_young
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Value4
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_phase_young
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value8
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Addr4
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Addr8
|
||||
fun:*
|
||||
fun:AT_collect_minor
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:AT_isInsideValidTerm
|
||||
fun:mark_phase_young
|
||||
fun:AT_collect_minor
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value8
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Addr4
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Addr8
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value4
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Value8
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
{
|
||||
ATerm library conservatively scans for GC roots
|
||||
Memcheck:Cond
|
||||
fun:*
|
||||
fun:*
|
||||
fun:AT_collect
|
||||
}
|
||||
|
||||
152
configure.ac
152
configure.ac
@@ -1,24 +1,9 @@
|
||||
AC_INIT(nix, 0.11)
|
||||
AC_INIT(nix, m4_esyscmd([echo -n $(cat ./version)$VERSION_SUFFIX]))
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
|
||||
|
||||
# Change to `1' to produce a `stable' release (i.e., the `preREVISION'
|
||||
# suffix is not added).
|
||||
STABLE=0
|
||||
|
||||
# Put the revision number in the version.
|
||||
if test "$STABLE" != "1"; then
|
||||
if REVISION=`test -d $srcdir/.svn && svnversion -n $srcdir 2> /dev/null`; then
|
||||
VERSION=${VERSION}pre${REVISION}
|
||||
elif REVISION=`cat $srcdir/svn-revision 2> /dev/null`; then
|
||||
VERSION=${VERSION}pre${REVISION}
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [version])
|
||||
|
||||
AC_PREFIX_DEFAULT(/nix)
|
||||
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [Nix version.])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
@@ -54,27 +39,62 @@ case $sys_name in
|
||||
esac
|
||||
|
||||
AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
|
||||
[platform identifier (e.g., `i686-linux')]),
|
||||
[Platform identifier (e.g., `i686-linux').]),
|
||||
system=$withval, system="${machine_name}-${sys_name}")
|
||||
AC_MSG_RESULT($system)
|
||||
AC_SUBST(system)
|
||||
AC_DEFINE_UNQUOTED(SYSTEM, ["$system"], [platform identifier (`cpu-os')])
|
||||
|
||||
|
||||
# Windows-specific stuff.
|
||||
if test "$sys_name" = "cygwin"; then
|
||||
# We cannot delete open files.
|
||||
AC_DEFINE(CANNOT_DELETE_OPEN_FILES, 1, [Whether it is impossible to delete open files.])
|
||||
# State should be stored in /nix/var, unless the user overrides it explicitly.
|
||||
test "$localstatedir" = '${prefix}/var' && localstatedir=/nix/var
|
||||
|
||||
# Shared libraries don't work, currently.
|
||||
|
||||
# Whether to produce a statically linked binary. On Cygwin, this is
|
||||
# the default: dynamically linking against the ATerm DLL does work,
|
||||
# except that it requires the ATerm "lib" directory to be in $PATH, as
|
||||
# Windows doesn't have anything like an RPATH embedded in executable.
|
||||
# Since this is kind of annoying, we use static libraries for now.
|
||||
|
||||
AC_ARG_ENABLE(static-nix, AC_HELP_STRING([--enable-static-nix],
|
||||
[produce statically linked binaries]),
|
||||
static_nix=$enableval, static_nix=no)
|
||||
|
||||
if test "$sys_name" = cygwin; then
|
||||
static_nix=yes
|
||||
fi
|
||||
|
||||
if test "$static_nix" = yes; then
|
||||
AC_DISABLE_SHARED
|
||||
AC_ENABLE_STATIC
|
||||
fi
|
||||
|
||||
|
||||
# Windows-specific stuff.
|
||||
if test "$sys_name" = "cygwin"; then
|
||||
# We cannot delete open files.
|
||||
AC_DEFINE(CANNOT_DELETE_OPEN_FILES, 1, [Whether it is impossible to delete open files.])
|
||||
fi
|
||||
|
||||
# Solaris-specific stuff.
|
||||
if test "$sys_name" = "sunos"; then
|
||||
# Solaris requires -lsocket -lnsl for network functions
|
||||
ADDITIONAL_NETWORK_LIBS="-lsocket -lnsl"
|
||||
AC_SUBST(ADDITIONAL_NETWORK_LIBS)
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
# To build programs to be run in the build machine
|
||||
if test "$CC_FOR_BUILD" = ""; then
|
||||
if test "$cross_compiling" = "yes"; then
|
||||
AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc)
|
||||
else
|
||||
CC_FOR_BUILD="$CC"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CC_FOR_BUILD])
|
||||
|
||||
# We are going to use libtool.
|
||||
AC_DISABLE_STATIC
|
||||
@@ -83,8 +103,7 @@ AC_PROG_LIBTOOL
|
||||
|
||||
|
||||
# Use 64-bit file system calls so that we can support files > 2 GiB.
|
||||
CFLAGS="-D_FILE_OFFSET_BITS=64 $CFLAGS"
|
||||
CXXFLAGS="-D_FILE_OFFSET_BITS=64 $CXXFLAGS"
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
|
||||
# Check for pubsetbuf.
|
||||
@@ -94,17 +113,34 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <iostream>
|
||||
using namespace std;
|
||||
static char buf[1024];]],
|
||||
[[cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));]])],
|
||||
[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PUBSETBUF, 1, [whether pubsetbuf is available])],
|
||||
[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PUBSETBUF, 1, [Whether pubsetbuf is available.])],
|
||||
AC_MSG_RESULT(no))
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
|
||||
# Check for <locale>
|
||||
# Check for chroot support (requires chroot() and bind mounts).
|
||||
AC_CHECK_FUNCS([chroot])
|
||||
AC_CHECK_FUNCS([unshare])
|
||||
AC_CHECK_HEADERS([sched.h], [], [], [])
|
||||
AC_CHECK_HEADERS([sys/param.h], [], [], [])
|
||||
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
||||
[#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
# endif
|
||||
])
|
||||
|
||||
|
||||
# Check for <locale>.
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_CHECK_HEADERS([locale])
|
||||
AC_CHECK_HEADERS([locale], [], [], [])
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
|
||||
# Check whether we have the personality() syscall, which allows us to
|
||||
# do i686-linux builds on x86_64-linux machines.
|
||||
AC_CHECK_HEADERS([sys/personality.h])
|
||||
|
||||
|
||||
AC_DEFUN([NEED_PROG],
|
||||
[
|
||||
AC_PATH_PROG($1, $2)
|
||||
@@ -114,17 +150,19 @@ fi
|
||||
])
|
||||
|
||||
NEED_PROG(curl, curl)
|
||||
NEED_PROG(shell, sh)
|
||||
NEED_PROG(bash, bash)
|
||||
NEED_PROG(patch, patch)
|
||||
AC_PATH_PROG(xmllint, xmllint, false)
|
||||
AC_PATH_PROG(xsltproc, xsltproc, false)
|
||||
AC_PATH_PROG(jing, jing, false) # needed because xmllint --relaxng seems broken
|
||||
AC_PATH_PROG(w3m, w3m, false)
|
||||
AC_PATH_PROG(flex, flex, false)
|
||||
AC_PATH_PROG(bison, bison, false)
|
||||
NEED_PROG(perl, perl)
|
||||
NEED_PROG(sed, sed)
|
||||
NEED_PROG(tar, tar)
|
||||
AC_PATH_PROG(dot, dot)
|
||||
AC_PATH_PROG(dblatex, dblatex)
|
||||
AC_PATH_PROG(gzip, gzip)
|
||||
|
||||
AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PATH
|
||||
AC_SUBST(openssl_prog)
|
||||
@@ -162,40 +200,9 @@ AC_SUBST(xmlflags)
|
||||
|
||||
AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
|
||||
[path of the Nix store]),
|
||||
storedir=$withval, storedir='${prefix}/store')
|
||||
storedir=$withval, storedir='/nix/store')
|
||||
AC_SUBST(storedir)
|
||||
|
||||
AC_ARG_WITH(bdb, AC_HELP_STRING([--with-bdb=PATH],
|
||||
[prefix of Berkeley DB]),
|
||||
bdb=$withval, bdb=)
|
||||
AM_CONDITIONAL(HAVE_BDB, test -n "$bdb")
|
||||
if test -z "$bdb"; then
|
||||
bdb_lib='-L${top_builddir}/externals/inst-bdb/lib -ldb_cxx'
|
||||
bdb_include='-I${top_builddir}/externals/inst-bdb/include'
|
||||
else
|
||||
bdb_lib="-L$bdb/lib -ldb_cxx"
|
||||
bdb_include="-I$bdb/include"
|
||||
fi
|
||||
AC_SUBST(bdb_lib)
|
||||
AC_SUBST(bdb_include)
|
||||
|
||||
AC_ARG_WITH(aterm, AC_HELP_STRING([--with-aterm=PATH],
|
||||
[prefix of CWI ATerm library]),
|
||||
aterm=$withval, aterm=)
|
||||
AM_CONDITIONAL(HAVE_ATERM, test -n "$aterm")
|
||||
if test -z "$aterm"; then
|
||||
aterm_lib='-L${top_builddir}/externals/inst-aterm/lib -lATerm'
|
||||
aterm_include='-I${top_builddir}/externals/inst-aterm/include'
|
||||
aterm_bin='${top_builddir}/externals/inst-aterm/bin'
|
||||
else
|
||||
aterm_lib="-L$aterm/lib -lATerm"
|
||||
aterm_include="-I$aterm/include"
|
||||
aterm_bin="$aterm/bin"
|
||||
fi
|
||||
AC_SUBST(aterm_lib)
|
||||
AC_SUBST(aterm_include)
|
||||
AC_SUBST(aterm_bin)
|
||||
|
||||
AC_ARG_WITH(openssl, AC_HELP_STRING([--with-openssl=PATH],
|
||||
[prefix of the OpenSSL library]),
|
||||
openssl=$withval, openssl=)
|
||||
@@ -204,7 +211,7 @@ if test -n "$openssl"; then
|
||||
LDFLAGS="-L$openssl/lib -lcrypto $LDFLAGS"
|
||||
CFLAGS="-I$openssl/include $CFLAGS"
|
||||
CXXFLAGS="-I$openssl/include $CXXFLAGS"
|
||||
AC_DEFINE(HAVE_OPENSSL, 1, [whether to use OpenSSL])
|
||||
AC_DEFINE(HAVE_OPENSSL, 1, [Whether to use OpenSSL.])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(bzip2, AC_HELP_STRING([--with-bzip2=PATH],
|
||||
@@ -217,7 +224,7 @@ if test -z "$bzip2"; then
|
||||
bzip2_lib='-L${top_builddir}/externals/inst-bzip2/lib -lbz2'
|
||||
bzip2_include='-I${top_builddir}/externals/inst-bzip2/include'
|
||||
# The binary will be copied to $libexecdir.
|
||||
bzip2_bin='${libexecdir}'
|
||||
bzip2_bin='${libexecdir}/nix'
|
||||
# But for testing, we have to use the temporary copy :-(
|
||||
bzip2_bin_test='${top_builddir}/externals/inst-bzip2/bin'
|
||||
else
|
||||
@@ -225,7 +232,7 @@ else
|
||||
bzip2_include="-I$bzip2/include"
|
||||
bzip2_bin="$bzip2/bin"
|
||||
bzip2_bin_test="$bzip2/bin"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(bzip2_lib)
|
||||
AC_SUBST(bzip2_include)
|
||||
AC_SUBST(bzip2_bin)
|
||||
@@ -245,13 +252,26 @@ AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
|
||||
AC_CHECK_FUNCS([setresuid setreuid lchown])
|
||||
|
||||
|
||||
# This is needed if ATerm, Berkeley DB or bzip2 are static libraries,
|
||||
# Nice to have, but not essential.
|
||||
AC_CHECK_FUNCS([strsignal])
|
||||
AC_CHECK_FUNCS([posix_fallocate])
|
||||
|
||||
|
||||
# This is needed if ATerm or bzip2 are static libraries,
|
||||
# and the Nix libraries are dynamic.
|
||||
if test "$(uname)" = "Darwin"; then
|
||||
LDFLAGS="-all_load $LDFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
if test "$static_nix" = yes; then
|
||||
# `-all-static' has to be added at the end of configure, because
|
||||
# the C compiler doesn't know about -all-static (it's filtered out
|
||||
# by libtool, but configure doesn't use libtool).
|
||||
LDFLAGS="-all-static $LDFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
AM_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_FILES([Makefile
|
||||
externals/Makefile
|
||||
|
||||
@@ -29,10 +29,18 @@ sub createLinks {
|
||||
$baseName =~ s/^.*\///g; # strip directory
|
||||
my $dstFile = "$dstDir/$baseName";
|
||||
|
||||
# The files below are special-cased so that they don't show up
|
||||
# in user profiles, either because they are useless, or
|
||||
# because they would cause pointless collisions (e.g., each
|
||||
# Python package brings its own
|
||||
# `$out/lib/pythonX.Y/site-packages/easy-install.pth'.)
|
||||
# Urgh, hacky...
|
||||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
||||
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$/)
|
||||
{
|
||||
@@ -160,4 +168,4 @@ while (scalar(keys %postponed) > 0) {
|
||||
print STDERR "created $symlinks symlinks in user environment\n";
|
||||
|
||||
|
||||
symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";
|
||||
symlink($ENV{"manifest"}, "$out/manifest.nix") or die "cannot create manifest";
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#! @shell@ -e
|
||||
|
||||
# Cygwin compatibility hack: bunzip2 expects cygwin.dll in $PATH.
|
||||
export PATH=@coreutils@
|
||||
|
||||
@coreutils@/mkdir $out
|
||||
@coreutils@/mkdir $out/tmp
|
||||
cd $out/tmp
|
||||
@@ -8,9 +11,15 @@ inputs=($inputs)
|
||||
for ((n = 0; n < ${#inputs[*]}; n += 2)); do
|
||||
channelName=${inputs[n]}
|
||||
channelTarball=${inputs[n+1]}
|
||||
|
||||
echo "unpacking channel $channelName"
|
||||
|
||||
@bunzip2@ < $channelTarball | @tar@ xf -
|
||||
|
||||
if test -e */channel-name; then
|
||||
channelName="$(@coreutils@/cat */channel-name)"
|
||||
fi
|
||||
|
||||
nr=1
|
||||
attrName=$(echo $channelName | @tr@ -- '- ' '__')
|
||||
dirName=$attrName
|
||||
|
||||
@@ -6,7 +6,12 @@ XSLTPROC = $(xsltproc) $(xmlflags) \
|
||||
--param xref.with.number.and.title 1 \
|
||||
--param toc.section.depth 3 \
|
||||
--param admon.style \'\' \
|
||||
--param callout.graphics.extension \'.gif\'
|
||||
--param callout.graphics.extension \'.gif\' \
|
||||
--param contrib.inline.enabled 0
|
||||
|
||||
dblatex_opts = \
|
||||
-P doc.collab.show=0 \
|
||||
-P latex.output.revhistory=0
|
||||
|
||||
# Note: we use GIF for now, since the PNGs shipped with Docbook aren't
|
||||
# transparent.
|
||||
@@ -14,27 +19,24 @@ XSLTPROC = $(xsltproc) $(xmlflags) \
|
||||
man1_MANS = nix-env.1 nix-build.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-pack-closure.1 nix-unpack-closure.1 \
|
||||
nix-install-package.1 nix-hash.1 nix-copy-closure.1
|
||||
|
||||
man8_MANS = nix-worker.8
|
||||
|
||||
FIGURES = figures/user-environments.png
|
||||
|
||||
MANUAL_SRCS = manual.xml introduction.xml installation.xml \
|
||||
package-management.xml writing-nix-expressions.xml \
|
||||
package-management.xml writing-nix-expressions.xml builtins.xml \
|
||||
build-farm.xml \
|
||||
$(man1_MANS:.1=.xml) \
|
||||
$(man1_MANS:.1=.xml) $(man8_MANS:.8=.xml) \
|
||||
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
|
||||
env-common.xml quick-start.xml nix-lang-ref.xml glossary.xml \
|
||||
conf-file.xml release-notes.xml \
|
||||
style.css images
|
||||
|
||||
# Note: RelaxNG validation requires xmllint >= 2.7.4.
|
||||
manual.is-valid: $(MANUAL_SRCS) version.txt
|
||||
# $(XMLLINT) --xinclude $< | $(XMLLINT) --noout --nonet --relaxng $(docbookrng)/docbook.rng -
|
||||
if test "$(jing)" != "false"; then \
|
||||
$(XMLLINT) --xinclude $< | $(jing) $(docbookrng)/docbook.rng /dev/fd/0; \
|
||||
else \
|
||||
echo "Not validating."; \
|
||||
fi
|
||||
$(XMLLINT) --noout --nonet --xinclude --noxincludenode --relaxng $(docbookrng)/docbook.rng $<
|
||||
touch $@
|
||||
|
||||
version.txt:
|
||||
@@ -47,6 +49,14 @@ manual.html: $(MANUAL_SRCS) manual.is-valid images
|
||||
$(XSLTPROC) --nonet --xinclude --output manual.html \
|
||||
$(docbookxsl)/html/docbook.xsl manual.xml
|
||||
|
||||
manual.pdf: $(MANUAL_SRCS) manual.is-valid images
|
||||
if test "$(dblatex)" != ""; then \
|
||||
$(dblatex) $(dblatex_opts) manual.xml; \
|
||||
else \
|
||||
echo "Please install dblatex and rerun configure."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
NEWS_OPTS = \
|
||||
--stringparam generate.toc "article nop" \
|
||||
@@ -68,12 +78,16 @@ NEWS.txt: release-notes.xml
|
||||
all-local: manual.html NEWS.html NEWS.txt
|
||||
|
||||
install-data-local: manual.html
|
||||
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/manual
|
||||
$(INSTALL_DATA) manual.html $(DESTDIR)$(datadir)/nix/manual
|
||||
$(INSTALL_DATA) style.css $(DESTDIR)$(datadir)/nix/manual
|
||||
cp -r images $(DESTDIR)$(datadir)/nix/manual/images
|
||||
$(INSTALL) -d $(DESTDIR)$(datadir)/nix/manual/figures
|
||||
$(INSTALL_DATA) $(FIGURES) $(DESTDIR)$(datadir)/nix/manual/figures
|
||||
$(INSTALL) -d $(DESTDIR)$(docdir)/manual
|
||||
$(INSTALL_DATA) manual.html $(DESTDIR)$(docdir)/manual
|
||||
ln -sf manual.html $(DESTDIR)$(docdir)/manual/index.html
|
||||
$(INSTALL_DATA) style.css $(DESTDIR)$(docdir)/manual
|
||||
cp -r images $(DESTDIR)$(docdir)/manual/images
|
||||
$(INSTALL) -d $(DESTDIR)$(docdir)/manual/figures
|
||||
$(INSTALL_DATA) $(FIGURES) $(DESTDIR)$(docdir)/manual/figures
|
||||
$(INSTALL) -d $(DESTDIR)$(docdir)/release-notes
|
||||
$(INSTALL_DATA) NEWS.html $(DESTDIR)$(docdir)/release-notes/index.html
|
||||
$(INSTALL_DATA) style.css $(DESTDIR)$(docdir)/release-notes/
|
||||
|
||||
images:
|
||||
mkdir images
|
||||
|
||||
@@ -36,10 +36,10 @@ build farm, since:
|
||||
builds, and Nix expressions are self-contained.</para></listitem>
|
||||
|
||||
<listitem><para>Nix will only rebuild things that have actually
|
||||
changed. For instance, if the sources of a component haven't
|
||||
changed between runs of the build farm, the component won't be
|
||||
rebuild (unless it was garbage-collected). Also, dependencies
|
||||
typically don't change very often, so they only need to be built
|
||||
changed. For instance, if the sources of a package haven't changed
|
||||
between runs of the build farm, the package won't be rebuilt (unless
|
||||
it was garbage-collected). Also, dependencies typically don't
|
||||
change very often, so they only need to be built
|
||||
once.</para></listitem>
|
||||
|
||||
<listitem><para>The results of a Nix build farm can be made
|
||||
@@ -56,7 +56,7 @@ build farm, since:
|
||||
<para>TODO</para>
|
||||
|
||||
<para>The sources of the Nix build farm are at <link
|
||||
xlink:href='https://svn.cs.uu.nl:12443/repos/trace/release/trunk'/>.</para>
|
||||
xlink:href='https://svn.nixos.org/repos/nix/release/trunk'/>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -85,7 +85,7 @@ nix@scratchy.labs.cs.uu.nl i686-linux /home/nix/.ssh/id_scratchy_auto
|
||||
|
||||
<para>An example build hook can be found in the Nix build farm
|
||||
sources: <link
|
||||
xlink:href='https://svn.cs.uu.nl:12443/repos/trace/release/trunk/common/distributed/build-remote.pl'
|
||||
xlink:href='https://svn.nixos.org/repos/nix/release/trunk/common/distributed/build-remote.pl'
|
||||
/>. It should be suitable for most purposes, with maybe some minor
|
||||
adjustments. It uses <command>ssh</command> and
|
||||
<command>rsync</command> to copy the build inputs and outputs and
|
||||
|
||||
851
doc/manual/builtins.xml
Normal file
851
doc/manual/builtins.xml
Normal file
@@ -0,0 +1,851 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id='ssec-builtins'>
|
||||
|
||||
<title>Built-in functions</title>
|
||||
|
||||
|
||||
<para>This section lists the functions and constants built into the
|
||||
Nix expression evaluator. (The built-in function
|
||||
<function>derivation</function> is discussed above.) Some built-ins,
|
||||
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>
|
||||
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Abort Nix expression evaluation, print error
|
||||
message <replaceable>s</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.add</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Return the sum of the integers
|
||||
<replaceable>e1</replaceable> and
|
||||
<replaceable>e2</replaceable>.</para></listitem>
|
||||
|
||||
</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:
|
||||
|
||||
<programlisting>
|
||||
attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames attrs);</programlisting>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Return the <emphasis>base name</emphasis> of the
|
||||
string <replaceable>s</replaceable>, that is, everything following
|
||||
the final slash in the string. This is similar to the GNU
|
||||
<command>basename</command> command.</para></listitem>
|
||||
|
||||
</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
|
||||
<varname>builtins</varname> to test for the availability of
|
||||
features in the Nix installation, e.g.,
|
||||
|
||||
<programlisting>
|
||||
if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
|
||||
|
||||
This allows a Nix expression to fall back gracefully on older Nix
|
||||
installations that don’t have the desired built-in
|
||||
function.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.compareVersions</function>
|
||||
<replaceable>s1</replaceable> <replaceable>s2</replaceable></term>
|
||||
|
||||
<listitem><para>Compare two strings representing versions and
|
||||
return <literal>-1</literal> if version
|
||||
<replaceable>s1</replaceable> is older than version
|
||||
<replaceable>s2</replaceable>, <literal>0</literal> if they are
|
||||
the same, and <literal>1</literal> if
|
||||
<replaceable>s1</replaceable> is newer than
|
||||
<replaceable>s2</replaceable>. The version comparison algorithm
|
||||
is the same as the one used by <link
|
||||
linkend="ssec-version-comparisons"><command>nix-env
|
||||
-u</command></link>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry
|
||||
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
|
||||
|
||||
<listitem><para>The built-in value <varname>currentSystem</varname>
|
||||
evaluates to the Nix platform identifier for the Nix installation
|
||||
on which the expression is being evaluated, such as
|
||||
<literal>"i686-linux"</literal> or
|
||||
<literal>"powerpc-darwin"</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<!--
|
||||
<varlistentry><term><function>currentTime</function></term>
|
||||
|
||||
<listitem><para>The built-in value <varname>currentTime</varname>
|
||||
returns the current system time in seconds since 00:00:00 1/1/1970
|
||||
UTC. Due to the evaluation model of Nix expressions
|
||||
(<emphasis>maximal laziness</emphasis>), it always yields the same
|
||||
value within an execution of Nix.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
<varlistentry><term><function>dependencyClosure</function></term>
|
||||
|
||||
<listitem><para>TODO</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
-->
|
||||
|
||||
|
||||
<varlistentry><term><function>derivation</function>
|
||||
<replaceable>attrs</replaceable></term>
|
||||
|
||||
<listitem><para><function>derivation</function> is described in
|
||||
<xref linkend='ssec-derivation' />.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>dirOf</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Return the directory part of the string
|
||||
<replaceable>s</replaceable>, that is, everything before the final
|
||||
slash in the string. This is similar to the GNU
|
||||
<command>dirname</command> command.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.div</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Return the quotient of the integers
|
||||
<replaceable>e1</replaceable> and
|
||||
<replaceable>e2</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.filterSource</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<para>This function allows you to copy sources into the Nix
|
||||
store while filtering certain files. For instance, suppose that
|
||||
you want to use the directory <filename>source-dir</filename> as
|
||||
an input to a Nix expression, e.g.
|
||||
|
||||
<programlisting>
|
||||
stdenv.mkDerivation {
|
||||
...
|
||||
src = ./source-dir;
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
However, if <filename>source-dir</filename> is a Subversion
|
||||
working copy, then all those annoying <filename>.svn</filename>
|
||||
subdirectories will also be copied to the store. Worse, the
|
||||
contents of those directories may change a lot, causing lots of
|
||||
spurious rebuilds. With <function>filterSource</function> you
|
||||
can filter out the <filename>.svn</filename> directories:
|
||||
|
||||
<programlisting>
|
||||
src = builtins.filterSource
|
||||
(path: type: type != "directory" || baseNameOf path != ".svn")
|
||||
./source-dir;
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Thus, the first argument <replaceable>e1</replaceable>
|
||||
must be a predicate function that is called for each regular
|
||||
file, directory or symlink in the source tree
|
||||
<replaceable>e2</replaceable>. If the function returns
|
||||
<literal>true</literal>, the file is copied to the Nix store,
|
||||
otherwise it is omitted. The function is called with two
|
||||
arguments. The first is the full path of the file. The second
|
||||
is a string that identifies the type of the file, which is
|
||||
either <literal>"regular"</literal>,
|
||||
<literal>"directory"</literal>, <literal>"symlink"</literal> or
|
||||
<literal>"unknown"</literal> (for other kinds of files such as
|
||||
device nodes or fifos — but note that those cannot be copied to
|
||||
the Nix store, so if the predicate returns
|
||||
<literal>true</literal> for them, the copy will fail).</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.getAttr</function>
|
||||
<replaceable>s</replaceable> <replaceable>attrs</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
|
||||
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>
|
||||
|
||||
<listitem><para><function>getEnv</function> returns the value of
|
||||
the environment variable <replaceable>s</replaceable>, or an empty
|
||||
string if the variable doesn’t exist. This function should be
|
||||
used with care, as it can introduce all sorts of nasty environment
|
||||
dependencies in your Nix expression.</para>
|
||||
|
||||
<para><function>getEnv</function> is used in Nix Packages to
|
||||
locate the file <filename>~/.nixpkgs/config.nix</filename>, which
|
||||
contains user-local settings for Nix Packages. (That is, it does
|
||||
a <literal>getEnv "HOME"</literal> to locate the user’s home
|
||||
directory.)</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.hasAttr</function>
|
||||
<replaceable>s</replaceable> <replaceable>attrs</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>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.head</function>
|
||||
<replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Return the first element of a list; abort
|
||||
evaluation if the argument isn’t a list or is an empty list. You
|
||||
can test whether a list is empty by comparing it with
|
||||
<literal>[]</literal>.</para></listitem>
|
||||
|
||||
</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>
|
||||
|
||||
<para>A Nix expression loaded by <function>import</function> must
|
||||
not contain any <emphasis>free variables</emphasis> (identifiers
|
||||
that are not defined in the Nix expression itself and are not
|
||||
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;
|
||||
y = import ./foo.nix;
|
||||
}</programlisting>
|
||||
|
||||
then the following <filename>foo.nix</filename> will give an
|
||||
error:
|
||||
|
||||
<programlisting>
|
||||
x + 456</programlisting>
|
||||
|
||||
since <varname>x</varname> is not in scope in
|
||||
<filename>foo.nix</filename>. If you want <varname>x</varname>
|
||||
to be available in <filename>foo.nix</filename>, you should pass
|
||||
it as a function argument:
|
||||
|
||||
<programlisting>
|
||||
rec {
|
||||
x = 123;
|
||||
y = import ./foo.nix x;
|
||||
}</programlisting>
|
||||
|
||||
and
|
||||
|
||||
<programlisting>
|
||||
x: x + 456</programlisting>
|
||||
|
||||
(The function argument doesn’t have to be called
|
||||
<varname>x</varname> in <filename>foo.nix</filename>; any name
|
||||
would work.)</para></listitem>
|
||||
|
||||
</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>
|
||||
|
||||
</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
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isList</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to a list, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isFunction</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to a function, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isString</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to a string, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</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
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.isBool</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to a bool, and
|
||||
<literal>false</literal> otherwise.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>isNull</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if
|
||||
<replaceable>e</replaceable> evaluates to <literal>null</literal>,
|
||||
and <literal>false</literal> otherwise.</para>
|
||||
|
||||
<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>
|
||||
|
||||
<listitem><para>Return the length of the list
|
||||
<replaceable>e</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.lessThan</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if the integer
|
||||
<replaceable>e1</replaceable> is less than the integer
|
||||
<replaceable>e2</replaceable>, and <literal>false</literal>
|
||||
otherwise. Evaluation aborts if either
|
||||
<replaceable>e1</replaceable> or <replaceable>e2</replaceable>
|
||||
does not evaluate to an integer.</para></listitem>
|
||||
|
||||
</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
|
||||
<varname>name</varname> specifying the name of the attribute, and
|
||||
an attribute <varname>value</varname> specifying its value.
|
||||
Example:
|
||||
|
||||
<programlisting>
|
||||
builtins.listToAttrs [
|
||||
{name = "foo"; value = 123;}
|
||||
{name = "bar"; value = 456;}
|
||||
]
|
||||
</programlisting>
|
||||
|
||||
evaluates to
|
||||
|
||||
<programlisting>
|
||||
{ foo = 123; bar = 456; }
|
||||
</programlisting>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><function>map</function>
|
||||
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Apply the function <replaceable>f</replaceable> to
|
||||
each element in the list <replaceable>list</replaceable>. For
|
||||
example,
|
||||
|
||||
<programlisting>
|
||||
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>
|
||||
|
||||
<listitem><para>Return the product of the integers
|
||||
<replaceable>e1</replaceable> and
|
||||
<replaceable>e2</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.parseDrvName</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Split the string <replaceable>s</replaceable> into
|
||||
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,
|
||||
<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>
|
||||
|
||||
<listitem><para>Return <literal>true</literal> if the path
|
||||
<replaceable>path</replaceable> exists, and
|
||||
<literal>false</literal> otherwise. One application of this
|
||||
function is to conditionally include a Nix expression containing
|
||||
user configuration:
|
||||
|
||||
<programlisting>
|
||||
let
|
||||
fileName = builtins.getEnv "CONFIG_FILE";
|
||||
config =
|
||||
if fileName != "" && builtins.pathExists (builtins.toPath fileName)
|
||||
then import (builtins.toPath fileName)
|
||||
else { someSetting = false; }; <lineannotation># default configuration</lineannotation>
|
||||
in config.someSetting</programlisting>
|
||||
|
||||
(Note that <envar>CONFIG_FILE</envar> must be an absolute path for
|
||||
this to work.)</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<!--
|
||||
<varlistentry><term><function>relativise</function></term>
|
||||
|
||||
<listitem><para>TODO</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
-->
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.readFile</function>
|
||||
<replaceable>path</replaceable></term>
|
||||
|
||||
<listitem><para>Return the contents of the file
|
||||
<replaceable>path</replaceable> as a string.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>removeAttrs</function>
|
||||
<replaceable>attrs</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,
|
||||
|
||||
<screen>
|
||||
removeAttrs { x = 1; y = 2; z = 3; } ["a" "x" "z"]</screen>
|
||||
|
||||
evaluates to <literal>{y = 2;}</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.stringLength</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return the length of the string
|
||||
<replaceable>e</replaceable>. If <replaceable>e</replaceable> is
|
||||
not a string, evaluation is aborted.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.sub</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Return the difference between the integers
|
||||
<replaceable>e1</replaceable> and
|
||||
<replaceable>e2</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.substring</function>
|
||||
<replaceable>start</replaceable> <replaceable>len</replaceable>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Return the substring of
|
||||
<replaceable>s</replaceable> from character position
|
||||
<replaceable>start</replaceable> (zero-based) up to but not
|
||||
including <replaceable>start + len</replaceable>. If
|
||||
<replaceable>start</replaceable> is greater than the length of the
|
||||
string, an empty string is returned, and if <replaceable>start +
|
||||
len</replaceable> lies beyond the end of the string, only the
|
||||
substring up to the end of the string is returned.
|
||||
<replaceable>start</replaceable> must be
|
||||
non-negative.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.tail</function>
|
||||
<replaceable>list</replaceable></term>
|
||||
|
||||
<listitem><para>Return the second to last elements of a list;
|
||||
abort evaluation if the argument isn’t a list or is an empty
|
||||
list.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>throw</function>
|
||||
<replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Throw an error message
|
||||
<replaceable>s</replaceable>. This usually aborts Nix expression
|
||||
evaluation, but in <command>nix-env -qa</command> and other
|
||||
commands that try to evaluate a set of derivations to get
|
||||
information about those derivations, a derivation that throws an
|
||||
error is silently skipped (which is not the case for
|
||||
<function>abort</function>).</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry
|
||||
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
|
||||
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Store the string <replaceable>s</replaceable> in a
|
||||
file in the Nix store and return its path. The file has suffix
|
||||
<replaceable>name</replaceable>. This file can be used as an
|
||||
input to derivations. One application is to write builders
|
||||
“inline”. For instance, the following Nix expression combines
|
||||
<xref linkend='ex-hello-nix' /> and <xref
|
||||
linkend='ex-hello-builder' /> into one file:
|
||||
|
||||
<programlisting>
|
||||
{stdenv, fetchurl, perl}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "hello-2.1.1";
|
||||
|
||||
builder = builtins.toFile "builder.sh" "
|
||||
source $stdenv/setup
|
||||
|
||||
PATH=$perl/bin:$PATH
|
||||
|
||||
tar xvfz $src
|
||||
cd hello-*
|
||||
./configure --prefix=$out
|
||||
make
|
||||
make install
|
||||
";
|
||||
|
||||
src = fetchurl {
|
||||
url = http://nix.cs.uu.nl/dist/tarballs/hello-2.1.1.tar.gz;
|
||||
md5 = "70c9ccf9fac07f762c24f2df2290784d";
|
||||
};
|
||||
inherit perl;
|
||||
}</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>It is even possible for one file to refer to another, e.g.,
|
||||
|
||||
<programlisting>
|
||||
builder = let
|
||||
configFile = builtins.toFile "foo.conf" "
|
||||
# This is some dummy configuration file.
|
||||
<replaceable>...</replaceable>
|
||||
";
|
||||
in builtins.toFile "builder.sh" "
|
||||
source $stdenv/setup
|
||||
<replaceable>...</replaceable>
|
||||
cp ${configFile} $out/etc/foo.conf
|
||||
";</programlisting>
|
||||
|
||||
Note that <literal>${configFile}</literal> is an antiquotation
|
||||
(see <xref linkend='ssec-values' />), so the result of the
|
||||
expression <literal>configFile</literal> (i.e., a path like
|
||||
<filename>/nix/store/m7p7jfny445k...-foo.conf</filename>) will be
|
||||
spliced into the resulting string.</para>
|
||||
|
||||
<para>It is however <emphasis>not</emphasis> allowed to have files
|
||||
mutually referring to each other, like so:
|
||||
|
||||
<programlisting>
|
||||
let
|
||||
foo = builtins.toFile "foo" "...${bar}...";
|
||||
bar = builtins.toFile "bar" "...${foo}...";
|
||||
in foo</programlisting>
|
||||
|
||||
This is not allowed because it would cause a cyclic dependency in
|
||||
the computation of the cryptographic hashes for
|
||||
<varname>foo</varname> and <varname>bar</varname>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
|
||||
|
||||
<listitem><para>Convert the string value
|
||||
<replaceable>s</replaceable> into a path value. The string
|
||||
<replaceable>s</replaceable> must represent an absolute path
|
||||
(i.e., must start with <literal>/</literal>). The path need not
|
||||
exist. The resulting path is canonicalised, e.g.,
|
||||
<literal>builtins.toPath "//foo/xyzzy/../bar/"</literal> returns
|
||||
<literal>/foo/bar</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Convert the expression
|
||||
<replaceable>e</replaceable> to a string.
|
||||
<replaceable>e</replaceable> can be a string (in which case
|
||||
<function>toString</function> is a no-op) or a path (e.g.,
|
||||
<literal>toString /foo/bar</literal> yields
|
||||
<literal>"/foo/bar"</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
|
||||
|
||||
<listitem><para>Return a string containing an XML representation
|
||||
of <replaceable>e</replaceable>. The main application for
|
||||
<function>toXML</function> is to communicate information with the
|
||||
builder in a more structured format than plain environment
|
||||
variables.</para>
|
||||
|
||||
<!-- TODO: more formally describe the schema of the XML
|
||||
representation -->
|
||||
|
||||
<para><xref linkend='ex-toxml' /> shows an example where this is
|
||||
the case. The builder is supposed to generate the configuration
|
||||
file for a <link xlink:href='http://jetty.mortbay.org/'>Jetty
|
||||
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
|
||||
<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
|
||||
information through an environment variable, which just
|
||||
concatenates everything together into a string (which might just
|
||||
work in this case, but wouldn’t work if fields are optional or
|
||||
contain lists themselves). Instead the Nix expression is
|
||||
converted to an XML representation with
|
||||
<function>toXML</function>, which is unambiguous and can easily be
|
||||
processed with the appropriate tools. For instance, in the
|
||||
example an XSLT stylesheet (<xref linkend='ex-toxml-co-stylesheet'
|
||||
/>) is applied to it (<xref linkend='ex-toxml-co-apply' />) to
|
||||
generate the XML configuration file for the Jetty server. The XML
|
||||
representation produced from <xref linkend='ex-toxml-co-servlets'
|
||||
/> by <function>toXML</function> is shown in <xref
|
||||
linkend='ex-toxml-result' />.</para>
|
||||
|
||||
<para>Note that <xref linkend='ex-toxml' /> uses the <function
|
||||
linkend='builtin-toFile'>toFile</function> built-in to write the
|
||||
builder and the stylesheet “inline” in the Nix expression. The
|
||||
path of the stylesheet is spliced into the builder at
|
||||
<literal>xsltproc ${stylesheet}
|
||||
<replaceable>...</replaceable></literal>.</para>
|
||||
|
||||
<example xml:id='ex-toxml'><title>Passing information to a builder
|
||||
using <function>toXML</function></title>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
{stdenv, fetchurl, libxslt, jira, uberwiki}:
|
||||
|
||||
stdenv.mkDerivation (rec {
|
||||
name = "web-server";
|
||||
|
||||
buildInputs = [libxslt];
|
||||
|
||||
builder = builtins.toFile "builder.sh" "
|
||||
source $stdenv/setup
|
||||
mkdir $out
|
||||
echo $servlets | xsltproc ${stylesheet} - > $out/server-conf.xml]]> <co xml:id='ex-toxml-co-apply' /> <![CDATA[
|
||||
";
|
||||
|
||||
stylesheet = builtins.toFile "stylesheet.xsl"]]> <co xml:id='ex-toxml-co-stylesheet' /> <![CDATA[
|
||||
"<?xml version='1.0' encoding='UTF-8'?>
|
||||
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
|
||||
<xsl:template match='/'>
|
||||
<Configure>
|
||||
<xsl:for-each select='/expr/list/attrs'>
|
||||
<Call name='addWebApplication'>
|
||||
<Arg><xsl:value-of select=\"attr[@name = 'path']/string/@value\" /></Arg>
|
||||
<Arg><xsl:value-of select=\"attr[@name = 'war']/path/@value\" /></Arg>
|
||||
</Call>
|
||||
</xsl:for-each>
|
||||
</Configure>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
";
|
||||
|
||||
servlets = builtins.toXML []]> <co xml:id='ex-toxml-co-servlets' /> <![CDATA[
|
||||
{ path = "/bugtracker"; war = jira + "/lib/atlassian-jira.war"; }
|
||||
{ path = "/wiki"; war = uberwiki + "/uberwiki.war"; }
|
||||
];
|
||||
})]]></programlisting>
|
||||
|
||||
</example>
|
||||
|
||||
<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>
|
||||
<attrs>
|
||||
<attr name="path">
|
||||
<string value="/bugtracker" />
|
||||
</attr>
|
||||
<attr name="war">
|
||||
<path value="/nix/store/d1jh9pasa7k2...-jira/lib/atlassian-jira.war" />
|
||||
</attr>
|
||||
</attrs>
|
||||
<attrs>
|
||||
<attr name="path">
|
||||
<string value="/wiki" />
|
||||
</attr>
|
||||
<attr name="war">
|
||||
<path value="/nix/store/y6423b1yi4sx...-uberwiki/uberwiki.war" />
|
||||
</attr>
|
||||
</attrs>
|
||||
</list>
|
||||
</expr>]]></programlisting>
|
||||
|
||||
</example>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><function>builtins.trace</function>
|
||||
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
|
||||
|
||||
<listitem><para>Evaluate <replaceable>e1</replaceable> and print its
|
||||
abstract syntax representation on standard error. Then return
|
||||
<replaceable>e2</replaceable>. This function is useful for
|
||||
debugging.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -60,27 +60,6 @@ env-keep-derivations = false
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-gc-reserved-space"><term><literal>gc-reserved-space</literal></term>
|
||||
|
||||
<listitem><para>This option specifies how much space should be
|
||||
reserved in normal use so that the garbage collector can run
|
||||
succesfully. Since the garbage collector must perform Berkeley DB
|
||||
transactions, it needs some disk space for itself. However, when
|
||||
the disk is full, this space is not available, so the collector
|
||||
would not be able to run precisely when it is most needed.</para>
|
||||
|
||||
<para>For this reason, when Nix is run, it allocates a file
|
||||
<filename>/nix/var/nix/db/reserved</filename> of the size
|
||||
specified by this option. When the garbage collector is run, this
|
||||
file is deleted before the Berkeley DB environment is opened.
|
||||
This should give it enough room to proceed.</para>
|
||||
|
||||
<para>The default is <literal>1048576</literal> (1
|
||||
MiB).</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>env-keep-derivations</literal></term>
|
||||
|
||||
<listitem><para>If <literal>false</literal> (default), derivations
|
||||
@@ -118,6 +97,123 @@ env-keep-derivations = false
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="conf-build-max-silent-time"><term><literal>build-max-silent-time</literal></term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<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
|
||||
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
|
||||
linkend="opt-max-silent-time">--max-silent-time</option> command
|
||||
line switch.</para>
|
||||
|
||||
<para>The value <literal>0</literal> means that there is no
|
||||
timeout. This is also the default.</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
|
||||
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.</para>
|
||||
|
||||
<para>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
|
||||
<filename>/etc/group</filename>). Those user accounts should not
|
||||
be used for any other purpose!</para>
|
||||
|
||||
<para>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.)</para>
|
||||
|
||||
<para>The build users should have permission to create files in
|
||||
the Nix store, but not delete them. Therefore,
|
||||
<filename>/nix/store</filename> should be owned by the Nix
|
||||
account, its group should be the group specified here, and its
|
||||
mode should be <literal>1775</literal>.</para>
|
||||
|
||||
<para>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 <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>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>build-use-chroot</literal></term>
|
||||
|
||||
<listitem><para>If set to <literal>true</literal>, builds will be
|
||||
performed in a <emphasis>chroot environment</emphasis>, 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 <link
|
||||
linkend='conf-build-chroot-dirs'><literal>build-chroot-dirs</literal>
|
||||
option</link> (such as <filename>/proc</filename> and
|
||||
<filename>/dev</filename>). This is useful to prevent undeclared
|
||||
dependencies on files in directories such as
|
||||
<filename>/usr/bin</filename>.</para>
|
||||
|
||||
<para>The use of a chroot requires that Nix is run as root (but
|
||||
you can still use the <link
|
||||
linkend='conf-build-users-group'>“build users” feature</link> 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.</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><literal>system</literal></term>
|
||||
|
||||
<listitem><para>This option specifies the canonical Nix system
|
||||
@@ -137,7 +233,17 @@ env-keep-derivations = false
|
||||
<filename>configure</filename> at build time.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry><term><literal>fsync-metadata</literal></term>
|
||||
|
||||
<listitem><para>If set to <literal>true</literal>, changes to the
|
||||
Nix store metadata (in <filename>/nix/var/nix/db</filename>) are
|
||||
synchronously flushed to disk. This improves robustness in case
|
||||
of system crashes, but reduces performance. The default is
|
||||
<literal>false</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
@@ -151,12 +151,12 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
<para>On the basis of this information, and whatever persistent
|
||||
state the build hook keeps about other machines and their current
|
||||
load, it has to decide what to do with the build. It should print
|
||||
out on file descriptor 3 one of the following responses (terminated
|
||||
by a newline, <literal>"\n"</literal>):
|
||||
out on standard error one of the following responses (terminated by
|
||||
a newline, <literal>"\n"</literal>):
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><literal>decline</literal></term>
|
||||
<varlistentry><term><literal># decline</literal></term>
|
||||
|
||||
<listitem><para>The build hook is not willing or able to perform
|
||||
the build; the calling Nix process should do the build itself,
|
||||
@@ -164,7 +164,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>postpone</literal></term>
|
||||
<varlistentry><term><literal># postpone</literal></term>
|
||||
|
||||
<listitem><para>The build hook cannot perform the build now, but
|
||||
can do so in the future (e.g., because all available build slots
|
||||
@@ -174,7 +174,7 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>accept</literal></term>
|
||||
<varlistentry><term><literal># accept</literal></term>
|
||||
|
||||
<listitem><para>The build hook has accepted the
|
||||
build.</para></listitem>
|
||||
@@ -185,37 +185,12 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>If the build hook accepts the build, it is possible that it is
|
||||
no longer necessary to do the build because some other process has
|
||||
performed the build in the meantime. To prevent races, the hook
|
||||
must read from file descriptor 4 a single line that tells it whether
|
||||
to continue:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><literal>cancel</literal></term>
|
||||
|
||||
<listitem><para>The build has already been done, so the hook
|
||||
should exit.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>okay</literal></term>
|
||||
|
||||
<listitem><para>The hook should proceed with the build. At this
|
||||
point, the calling Nix process has acquired locks on the output
|
||||
path, so no other Nix process will perform the
|
||||
build.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
||||
<para>If the hook has been told to proceed, Nix will store in the
|
||||
hook’s current directory a number of text files that contain
|
||||
information about the derivation:
|
||||
<para>After sending <literal># accept</literal>, the hook should
|
||||
read one line from standard input, which will be the string
|
||||
<literal>okay</literal>. It can then proceed with the build.
|
||||
Before sending <literal>okay</literal>, Nix will store in the hook’s
|
||||
current directory a number of text files that contain information
|
||||
about the derivation:
|
||||
|
||||
<variablelist>
|
||||
|
||||
@@ -255,7 +230,9 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
<para>The hook should copy the inputs to the remote machine,
|
||||
register the validity of the inputs, perform the remote build, and
|
||||
copy the outputs back to the local machine. An exit code other than
|
||||
<literal>0</literal> indicates that the hook has failed.</para>
|
||||
<literal>0</literal> indicates that the hook has failed. An exit
|
||||
code equal to 100 means that the remote build failed (as opposed to,
|
||||
e.g., a network error).</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
@@ -263,6 +240,38 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="envar-remote"><term><envar>NIX_REMOTE</envar></term>
|
||||
|
||||
<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
|
||||
linkend="ssec-multi-user">multi-user Nix installations</link>.
|
||||
Otherwise, it should be left unset.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<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.
|
||||
See <xref linkend="sec-sharing-packages" /> for details. Each path
|
||||
should be the <filename>/nix</filename> directory of a remote Nix
|
||||
installation (i.e., not the <filename>/nix/store</filename>
|
||||
directory). The paths are subject to globbing, so you can set it so
|
||||
something like <literal>/var/run/nix/remote-stores/*/nix</literal>
|
||||
and mount multiple remote filesystems in
|
||||
<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
|
||||
this variable that matters is the one that the
|
||||
<command>nix-worker</command> process uses. So if you want to
|
||||
change it, you have to restart the daemon.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
@@ -74,9 +74,9 @@
|
||||
|
||||
<glossentry><glossterm>Nix expression</glossterm>
|
||||
|
||||
<glossdef><para>A high-level description of software components and
|
||||
<glossdef><para>A high-level description of software packages and
|
||||
compositions thereof. Deploying software using Nix entails writing
|
||||
Nix expressions for your components. Nix expressions are translated
|
||||
Nix expressions for your packages. Nix expressions are translated
|
||||
to derivations that are stored in the Nix store. These derivations
|
||||
can then be built.</para></glossdef>
|
||||
|
||||
|
||||
@@ -42,26 +42,22 @@ platforms as well.</para>
|
||||
<section><title>Obtaining Nix</title>
|
||||
|
||||
<para>The easiest way to obtain Nix is to download a <link
|
||||
xlink:href="http://www.cs.uu.nl/groups/ST/Trace/Nix">source
|
||||
distribution</link>. RPMs for Red Hat, SuSE, and Fedora Core are also
|
||||
available.</para>
|
||||
xlink:href="http://nixos.org/">source distribution</link>. RPMs
|
||||
for Red Hat, SuSE, and Fedora Core are also available.</para>
|
||||
|
||||
<para>Alternatively, the most recent sources of Nix can be obtained
|
||||
from its <link
|
||||
xlink:href="https://svn.cs.uu.nl:12443/repos/trace/nix/trunk">Subversion
|
||||
xlink:href="https://svn.nixos.org/repos/nix/nix/trunk">Subversion
|
||||
repository</link>. For example, the following command will check out
|
||||
the latest revision into a directory called
|
||||
<filename>nix</filename>:</para>
|
||||
|
||||
<screen>
|
||||
$ svn checkout https://svn.cs.uu.nl:12443/repos/trace/nix/trunk nix</screen>
|
||||
$ svn checkout https://svn.nixos.org/repos/nix/nix/trunk nix</screen>
|
||||
|
||||
<para>Likewise, specific releases can be obtained from the <link
|
||||
xlink:href="https://svn.cs.uu.nl:12443/repos/trace/nix/tags">tags
|
||||
directory</link> of the repository. If you don't have Subversion, you
|
||||
can also download an automatically generated <link
|
||||
xlink:href="https://svn.cs.uu.nl:12443/dist/trace/">compressed
|
||||
tar-file</link> of the head revision of the trunk.</para>
|
||||
xlink:href="https://svn.nixos.org/repos/nix/nix/tags">tags
|
||||
directory</link> of the repository.</para>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -100,16 +96,14 @@ ubiquitous 2.5.4a won't. Note that these are only required if you
|
||||
modify the parser or when you are building from the Subversion
|
||||
repository.</para>
|
||||
|
||||
<para>Nix uses Sleepycat's Berkeley DB and CWI's ATerm library. These
|
||||
are included in the Nix source distribution. If you build from the
|
||||
Subversion repository, you must download them yourself and place them
|
||||
in the <filename>externals/</filename> directory. See
|
||||
<para>Nix uses the bzip2 compressor (including the bzip2 library). It
|
||||
is included in the Nix source distribution. If you build from the
|
||||
Subversion repository, you must download it yourself and place it in
|
||||
the <filename>externals/</filename> directory. See
|
||||
<filename>externals/Makefile.am</filename> for the precise URLs of
|
||||
these packages. Alternatively, if you already have them installed,
|
||||
you can use <command>configure</command>'s <option>--with-bdb</option>
|
||||
and <option>--with-aterm</option> options to point to their respective
|
||||
locations. Note that Berkeley DB <emphasis>must</emphasis> be version
|
||||
4.5; other versions may not have compatible database formats.</para>
|
||||
this packages. Alternatively, if you already have it installed, you
|
||||
can use <command>configure</command>'s <option>--with-bzip2</option>
|
||||
options to point to their respective locations.</para>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -118,33 +112,44 @@ locations. Note that Berkeley DB <emphasis>must</emphasis> be version
|
||||
|
||||
<para>After unpacking or checking out the Nix sources, issue the
|
||||
following commands:
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
$ ./configure <replaceable>options...</replaceable>
|
||||
$ make
|
||||
$ make install</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>When building from the Subversion repository, these should be
|
||||
preceded by the command:
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
$ ./boostrap</screen>
|
||||
$ ./bootstrap.sh</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>The installation path can be specified by passing the
|
||||
<option>--prefix=<replaceable>prefix</replaceable></option> to
|
||||
<command>configure</command>. The default installation directory is
|
||||
<filename>/nix</filename>. You can change this to any location you
|
||||
like. You must have write permission to the
|
||||
<filename>/usr/local</filename>. You can change this to any location
|
||||
you like. You must have write permission to the
|
||||
<replaceable>prefix</replaceable> path.</para>
|
||||
|
||||
<warning><para>It is best <emphasis>not</emphasis> to change the
|
||||
installation prefix from its default, since doing so makes it
|
||||
impossible to use pre-built binaries from the standard Nixpkgs
|
||||
channels.</para></warning>
|
||||
<para>Nix keeps its <emphasis>store</emphasis> (the place where
|
||||
packages are stored) in <filename>/nix/store</filename> by default.
|
||||
This can be changed using
|
||||
<option>--with-store-dir=<replaceable>path</replaceable></option>.</para>
|
||||
|
||||
<para>If you want to rebuilt the documentation, pass the full path to
|
||||
<warning><para>It is best <emphasis>not</emphasis> to change the Nix
|
||||
store from its default, since doing so makes it impossible to use
|
||||
pre-built binaries from the standard Nixpkgs channels — that is, all
|
||||
packages will need to be built from source.</para></warning>
|
||||
|
||||
<para>Nix keeps state (such as its database and log files) in
|
||||
<filename>/nix/var</filename> by default. This can be changed using
|
||||
<option>--localstatedir=<replaceable>path</replaceable></option>.</para>
|
||||
|
||||
<para>If you want to rebuild the documentation, pass the full path to
|
||||
the DocBook RELAX NG schemas and to the DocBook XSL stylesheets using
|
||||
the
|
||||
<option>--with-docbook-rng=<replaceable>path</replaceable></option>
|
||||
@@ -155,45 +160,50 @@ options.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Installing from RPMs</title>
|
||||
<section><title>Installing a binary distribution</title>
|
||||
|
||||
<para>RPM packages of Nix can be downloaded from <uri
|
||||
xlink:href="http://www.cs.uu.nl/groups/ST/Trace/Nix">http://www.cs.uu.nl/groups/ST/Trace/Nix</uri>.
|
||||
These RPMs should work for most fairly recent releases of SuSE and Red
|
||||
Hat Linux. They have been known to work work on SuSE Linux 8.1 and
|
||||
9.0, and Red Hat 9.0. In fact, it should work on any RPM-based Linux
|
||||
distribution based on <literal>glibc</literal> 2.3 or later.</para>
|
||||
|
||||
<para>Once downloaded, the RPMs can be installed or upgraded using
|
||||
<command>rpm -U</command>. For example,</para>
|
||||
<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.5pre664-1.i386.rpm</screen>
|
||||
$ rpm -U nix-0.13pre18104-1.i386.rpm</screen>
|
||||
|
||||
<para>The RPMs install into the directory <filename>/nix</filename>.
|
||||
Nix can be uninstalled using <command>rpm -e nix</command>. After
|
||||
this it will be necessary to manually remove the Nix store and other
|
||||
auxiliary data:</para>
|
||||
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>
|
||||
|
||||
|
||||
<!-- TODO: should be updated
|
||||
<section><title>Upgrading Nix through Nix</title>
|
||||
|
||||
<para>You can install the latest stable version of Nix through Nix
|
||||
itself by subscribing to the channel <link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/channels-v3/nix-stable" />,
|
||||
or the latest unstable version by subscribing to the channel<link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/channels-v3/nix-unstable" />.
|
||||
xlink:href="http://nixos.org/releases/nix/channels/nix-stable" />,
|
||||
or the latest unstable version by subscribing to the channel <link
|
||||
xlink:href="http://nixos.org/releases/nix/channels/nix-unstable" />.
|
||||
You can also do a <link linkend="sec-one-click">one-click
|
||||
installation</link> by clicking on the package links at <link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/" />.</para>
|
||||
xlink:href="http://nixos.org/releases/full-index-nix.html" />.</para>
|
||||
|
||||
</section>
|
||||
-->
|
||||
|
||||
|
||||
<section><title>Security</title>
|
||||
@@ -231,33 +241,215 @@ class="username">root</systemitem> all the time.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Multi-user mode</title>
|
||||
<section xml:id="ssec-multi-user"><title>Multi-user mode</title>
|
||||
|
||||
<para></para>
|
||||
<para>To allow a Nix store to be shared safely among multiple users,
|
||||
it is important that users are not able to run builders that modify
|
||||
the Nix store or database in arbitrary ways, or that interfere with
|
||||
builds started by other users. If they could do so, they could
|
||||
install a Trojan horse in some package and compromise the accounts of
|
||||
other users.</para>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
warning: the nix-builders group should contain *only* the Nix
|
||||
builders, and nothing else. If the Nix account is compromised, you
|
||||
can execute programs under the accounts in the nix-builders group, so
|
||||
it obviously shouldn’t contain any “real” user accounts. So don’t use
|
||||
an existing group like <literal>users</literal> — just create a new
|
||||
one.
|
||||
|
||||
-->
|
||||
<para>To prevent this, the Nix store and database are owned by some
|
||||
privileged user (usually <literal>root</literal>) and builders are
|
||||
executed under special user accounts (usually named
|
||||
<literal>nixbld1</literal>, <literal>nixbld2</literal>, etc.). When a
|
||||
unprivileged user runs a Nix command, actions that operate on the Nix
|
||||
store (such as builds) are forwarded to a <emphasis>Nix
|
||||
daemon</emphasis> running under the owner of the Nix store/database
|
||||
that performs the operation.</para>
|
||||
|
||||
<note><para>Multi-user mode has one important limitation: only
|
||||
<systemitem class="username">root</systemitem> can run <command
|
||||
linkend="sec-nix-pull">nix-pull</command> to register the availability
|
||||
of pre-built binaries. However, those registrations
|
||||
<emphasis>are</emphasis> used by all users to speed up
|
||||
builds.</para></note>
|
||||
of pre-built binaries. However, those registrations are shared by all
|
||||
users, so they still get the benefit from <command>nix-pull</command>s
|
||||
done by <systemitem class="username">root</systemitem>.</para></note>
|
||||
|
||||
|
||||
<section><title>Setting up the build users</title>
|
||||
|
||||
<para>The <emphasis>build users</emphasis> are the special UIDs under
|
||||
which builds are performed. They should all be members of the
|
||||
<emphasis>build users group</emphasis> (usually called
|
||||
<literal>nixbld</literal>). This group should have no other members.
|
||||
The build users should not be members of any other group.</para>
|
||||
|
||||
<para>Here is a typical <filename>/etc/group</filename> definition of
|
||||
the build users group with 10 build users:
|
||||
|
||||
<programlisting>
|
||||
nixbld:!:30000:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10
|
||||
</programlisting>
|
||||
|
||||
In this example the <literal>nixbld</literal> group has UID 30000, but
|
||||
of course it can be anything that doesn’t collide with an existing
|
||||
group.</para>
|
||||
|
||||
<para>Here is the corresponding part of
|
||||
<filename>/etc/passwd</filename>:
|
||||
|
||||
<programlisting>
|
||||
nixbld1:x:30001:65534:Nix build user 1:/var/empty:/noshell
|
||||
nixbld2:x:30002:65534:Nix build user 2:/var/empty:/noshell
|
||||
nixbld3:x:30003:65534:Nix build user 3:/var/empty:/noshell
|
||||
...
|
||||
nixbld10:x:30010:65534:Nix build user 10:/var/empty:/noshell
|
||||
</programlisting>
|
||||
|
||||
The home directory of the build users should not exist or should be an
|
||||
empty directory to which they do not have write access.</para>
|
||||
|
||||
<para>The build users should have write access to the Nix store, but
|
||||
they should not have the right to delete files. Thus the Nix store’s
|
||||
group should be the build users group, and it should have the sticky
|
||||
bit turned on (like <filename>/tmp</filename>):
|
||||
|
||||
<screen>
|
||||
$ chgrp nixbld /nix/store
|
||||
$ chmod 1777 /nix/store
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Finally, you should tell Nix to use the build users by
|
||||
specifying the build users group in the <link
|
||||
linkend="conf-build-users-group"><literal>build-users-group</literal>
|
||||
option</link> in the <link linkend="sec-conf-file">Nix configuration
|
||||
file</link> (<literal>/nix/etc/nix/nix.conf</literal>):
|
||||
|
||||
<programlisting>
|
||||
build-users-group = nixbld
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section> <!-- end of permissions section -->
|
||||
<section><title>Nix store/database owned by root</title>
|
||||
|
||||
<para>The simplest setup is to let <literal>root</literal> own the Nix
|
||||
store and database. I.e.,
|
||||
|
||||
<screen>
|
||||
$ chown -R root /nix/store /nix/var/nix</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>The <link linkend="sec-nix-worker">Nix daemon</link> should be
|
||||
started as follows (as <literal>root</literal>):
|
||||
|
||||
<screen>
|
||||
$ nix-worker --daemon</screen>
|
||||
|
||||
You’ll want to put that line somewhere in your system’s boot
|
||||
scripts.</para>
|
||||
|
||||
<para>To let unprivileged users use the daemon, they should set the
|
||||
<link linkend="envar-remote"><envar>NIX_REMOTE</envar> environment
|
||||
variable</link> to <literal>daemon</literal>. So you should put a
|
||||
line like
|
||||
|
||||
<programlisting>
|
||||
export NIX_REMOTE=daemon</programlisting>
|
||||
|
||||
into the users’ login scripts.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Nix store/database not owned by root</title>
|
||||
|
||||
<para>It is also possible to let the Nix store and database be owned
|
||||
by a non-root user, which should be more secure<footnote><para>Note
|
||||
however that even when the Nix daemon runs as root, not
|
||||
<emphasis>that</emphasis> much code is executed as root: Nix
|
||||
expression evaluation is performed by the calling (unprivileged) user,
|
||||
and builds are performed under the special build user accounts. So
|
||||
only the code that accesses the database and starts builds is executed
|
||||
as <literal>root</literal>.</para></footnote>. Typically, this user
|
||||
is a special account called <literal>nix</literal>, but it can be
|
||||
named anything. It should own the Nix store and database:
|
||||
|
||||
<screen>
|
||||
$ chown -R root /nix/store /nix/var/nix</screen>
|
||||
|
||||
and of course <command>nix-worker --daemon</command> should be started
|
||||
under that user, e.g.,
|
||||
|
||||
<screen>
|
||||
$ su - nix -c "exec /nix/bin/nix-worker --daemon"</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>There is a catch, though: non-<literal>root</literal> users
|
||||
cannot start builds under the build user accounts, since the
|
||||
<function>setuid</function> system call is obviously privileged. To
|
||||
allow a non-<literal>root</literal> Nix daemon to use the build user
|
||||
feature, it calls a setuid-root helper program,
|
||||
<command>nix-setuid-helper</command>. This program is installed in
|
||||
<filename><replaceable>prefix</replaceable>/libexec/nix-setuid-helper</filename>.
|
||||
To set the permissions properly (Nix’s <command>make install</command>
|
||||
doesn’t do this, since we don’t want to ship setuid-root programs
|
||||
out-of-the-box):
|
||||
|
||||
<screen>
|
||||
$ chown root.root /nix/libexec/nix-setuid-helper
|
||||
$ chmod 4755 /nix/libexec/nix-setuid-helper
|
||||
</screen>
|
||||
|
||||
(This example assumes that the Nix binaries are installed in
|
||||
<filename>/nix</filename>.)</para>
|
||||
|
||||
<para>Of course, the <command>nix-setuid-helper</command> command
|
||||
should not be usable by just anybody, since then anybody could run
|
||||
commands under the Nix build user accounts. For that reason there is
|
||||
a configuration file <filename>/etc/nix-setuid.conf</filename> that
|
||||
restricts the use of the helper. This file should be a text file
|
||||
containing precisely two lines, the first being the Nix daemon user
|
||||
and the second being the build users group, e.g.,
|
||||
|
||||
<programlisting>
|
||||
nix
|
||||
nixbld
|
||||
</programlisting>
|
||||
|
||||
The setuid-helper barfs if it is called by a user other than the one
|
||||
specified on the first line, or if it is asked to execute a build
|
||||
under a user who is not a member of the group specified on the second
|
||||
line. The file <filename>/etc/nix-setuid.conf</filename> must be
|
||||
owned by root, and must not be group- or world-writable. The
|
||||
setuid-helper barfs if this is not the case.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Restricting access</title>
|
||||
|
||||
<para>To limit which users can perform Nix operations, you can use the
|
||||
permissions on the directory
|
||||
<filename>/nix/var/nix/daemon-socket</filename>. For instance, if you
|
||||
want to restrict the use of Nix to the members of a group called
|
||||
<literal>nix-users</literal>, do
|
||||
|
||||
<screen>
|
||||
$ chgrp nix-users /nix/var/nix/daemon-socket
|
||||
$ chmod ug=rwx,o= /nix/var/nix/daemon-socket
|
||||
</screen>
|
||||
|
||||
This way, users who are not in the <literal>nix-users</literal> group
|
||||
cannot connect to the Unix domain socket
|
||||
<filename>/nix/var/nix/daemon-socket/socket</filename>, so they cannot
|
||||
perform Nix operations.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section> <!-- end of multi-user -->
|
||||
|
||||
|
||||
</section> <!-- end of security -->
|
||||
|
||||
|
||||
<section><title>Using Nix</title>
|
||||
|
||||
@@ -1,150 +1,337 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="chap-introduction">
|
||||
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Nix is a system for the deployment of software. Software
|
||||
deployment is concerned with the creation, distribution, and
|
||||
management of software components (<quote>packages</quote>). Its main
|
||||
features are:
|
||||
|
||||
<itemizedlist>
|
||||
<section><title>About Nix</title>
|
||||
|
||||
<listitem><para>It helps you make sure that dependency specifications
|
||||
are complete. In general in a deployment system you have to specify
|
||||
for each component what its dependencies are, but there are no
|
||||
guarantees that this specification is complete. If you forget a
|
||||
dependency, then the component will build and work correctly on
|
||||
<emphasis>your</emphasis> machine if you have the dependency
|
||||
installed, but not on the end user's machine if it's not
|
||||
there.</para></listitem>
|
||||
<para>Nix is a <emphasis>purely functional package manager</emphasis>.
|
||||
This means that it treats packages like values in purely functional
|
||||
programming languages such as Haskell — they are built by functions
|
||||
that don’t have side-effects, and they never change after they have
|
||||
been built. Nix stores packages in the <emphasis>Nix
|
||||
store</emphasis>, usually the directory
|
||||
<filename>/nix/store</filename>, where each package has its own unique
|
||||
subdirectory such as
|
||||
|
||||
<listitem><para>It is possible to have <emphasis>multiple versions or
|
||||
variants</emphasis> of a component installed at the same time. In
|
||||
contrast, in systems such as RPM different versions of the same
|
||||
package tend to install to the same location in the file system, so
|
||||
installing one version will remove the other. This is especially
|
||||
important if you want to use applications that have conflicting
|
||||
requirements on different versions of a component (e.g., application A
|
||||
requires version 1.0 of library X, while application B requires a
|
||||
non-backwards compatible version 1.1).</para></listitem>
|
||||
<programlisting>
|
||||
/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-2.0.0.1/
|
||||
</programlisting>
|
||||
|
||||
<listitem><para>Users can have different <quote>views</quote>
|
||||
(<quote>profiles</quote> in Nix parlance) on the set of installed
|
||||
applications in a system. For instance, one user can have version 1.0
|
||||
of some package visible, while another is using version 1.1, and a
|
||||
third doesn't use it at all.</para></listitem>
|
||||
where <literal>r8vvq9kq…</literal> is a unique identifier for the
|
||||
package that captures all its dependencies (it’s a cryptographic hash
|
||||
of the package’s build dependency graph). This enables many powerful
|
||||
features.</para>
|
||||
|
||||
<listitem><para>It is possible to atomically
|
||||
<emphasis>upgrade</emphasis> software. I.e., there is no time window
|
||||
during an upgrade in which part of the old version and part of the new
|
||||
version are simultaneously visible (which might well cause the
|
||||
component to fail).</para></listitem>
|
||||
|
||||
<listitem><para>Likewise, it is possible to atomically roll back after
|
||||
an install, upgrade, or uninstall action. That is, in a fast (O(1))
|
||||
operation the previous configuration of the system can be restored.
|
||||
This is because upgrade or uninstall actions don't actually remove
|
||||
components from the system.</para></listitem>
|
||||
<simplesect><title>Multiple versions</title>
|
||||
|
||||
<listitem><para>Unused components can be
|
||||
<emphasis>garbage-collected</emphasis> automatically and safely: when
|
||||
you remove an application from a profile, its dependencies will be
|
||||
deleted by the garbage collector only if there are no other active
|
||||
applications using them.</para></listitem>
|
||||
<para>You can have multiple versions or variants of a package
|
||||
installed at the same time. This is especially important when
|
||||
different applications have dependencies on different versions of the
|
||||
same package — it prevents the “DLL hell”. Because of the hashing
|
||||
scheme, different versions of a package end up in different paths in
|
||||
the Nix store, so they don’t interfere with each other.</para>
|
||||
|
||||
<listitem><para>Nix supports both source-based deployment models
|
||||
(where you distribute <emphasis>Nix expressions</emphasis> that tell
|
||||
Nix how to build software from source) and binary-based deployment
|
||||
models. The latter is more-or-less transparent: installation of
|
||||
components is always based on Nix expressions, but if the expressions
|
||||
have been built before and Nix knows that the resulting binaries are
|
||||
available somewhere, it will use those instead.</para></listitem>
|
||||
<para>An important consequence is that operations like upgrading or
|
||||
uninstalling an application cannot break other applications, since
|
||||
these operations never “destructively” update or delete files that are
|
||||
used by other packages.</para>
|
||||
|
||||
<listitem><para>Nix is flexible in the deployment policies that it
|
||||
supports. There is a clear separation between the tools that
|
||||
implement basic Nix <emphasis>mechanisms</emphasis> (e.g., building
|
||||
Nix expressions), and the tools that implement various deployment
|
||||
<emphasis>policies</emphasis>. For instance, there is a concept of
|
||||
<quote>Nix channels</quote> that can be used to keep software
|
||||
installations up-to-date automatically from a network source. This is
|
||||
a policy that is implemented by a fairly short Perl script, which can
|
||||
be adapted easily to achieve similar policies.</para></listitem>
|
||||
</simplesect>
|
||||
|
||||
<listitem><para>Nix component builds aim to be <quote>pure</quote>;
|
||||
that is, unaffected by anything other than the declared dependencies.
|
||||
This means that if a component was built successfully once, it can be
|
||||
rebuilt again on another machine and the result will be the same. We
|
||||
cannot <emphasis>guarantee</emphasis> this (e.g., if the build depends
|
||||
on the time-of-day), but Nix (and the tools in the Nix Packages
|
||||
collection) takes special care to help achieve this.</para></listitem>
|
||||
|
||||
<listitem><para>Nix expressions (the things that tell Nix how to build
|
||||
components) are self-contained: they describe not just components but
|
||||
complete compositions. In other words, Nix expressions also describe
|
||||
how to build all the dependencies. This is in contrast to component
|
||||
specification languages like RPM spec files, which might say that a
|
||||
component X depends on some other component Y, but since it does not
|
||||
describe <emphasis>exactly</emphasis> what Y is, the result of
|
||||
building or running X might be different on different machines.
|
||||
Combined with purity, self-containedness ensures that a component that
|
||||
<quote>works</quote> on one machine also works on another, when
|
||||
deployed using Nix.</para></listitem>
|
||||
<simplesect><title>Complete dependencies</title>
|
||||
|
||||
<listitem><para>The Nix expression language makes it easy to describe
|
||||
variability in components (e.g., optional features or
|
||||
dependencies).</para></listitem>
|
||||
<para>Nix helps you make sure that package dependency specifications
|
||||
are complete. In general, when you’re making a package for a package
|
||||
management system like RPM, you have to specify for each package what
|
||||
its dependencies are, but there are no guarantees that this
|
||||
specification is complete. If you forget a dependency, then the
|
||||
package will build and work correctly on <emphasis>your</emphasis>
|
||||
machine if you have the dependency installed, but not on the end
|
||||
user's machine if it's not there.</para>
|
||||
|
||||
<listitem><para>Nix is ideal for building build farms that do
|
||||
continuous builds of software from a version management system, since
|
||||
it can take care of building all the dependencies as well. Also, Nix
|
||||
only rebuilds components that have changed, so there are no
|
||||
unnecessary builds. In addition, Nix can transparently distribute
|
||||
build jobs over different machines, including different
|
||||
platforms.</para></listitem>
|
||||
<para>Since Nix on the other hand doesn’t install packages in “global”
|
||||
locations like <filename>/usr/bin</filename> but in package-specific
|
||||
directories, the risk of incomplete dependencies is greatly reduced.
|
||||
This is because tools such as compilers don’t search in per-packages
|
||||
directories such as
|
||||
<filename>/nix/store/5lbfaxb722zp…-openssl-0.9.8d/include</filename>,
|
||||
so if a package builds correctly on your system, this is because you
|
||||
specified the dependency explicitly.</para>
|
||||
|
||||
<listitem><para>Nix can be used not only for software deployment, but
|
||||
also for <emphasis>service deployment</emphasis>, such as the
|
||||
deployment of a complete web server with all its configuration files,
|
||||
static pages, software dependencies, and so on. Nix's advantages for
|
||||
software deployment also apply here: for instance, the ability
|
||||
trivially to have multiple configurations at the same time, or the
|
||||
ability to do rollbacks.</para></listitem>
|
||||
<para>Runtime dependencies are found by scanning binaries for the hash
|
||||
parts of Nix store paths (such as <literal>r8vvq9kq…</literal>). This
|
||||
sounds risky, but it works extremely well.</para>
|
||||
|
||||
<listitem><para>Nix can efficiently upgrade between different versions
|
||||
of a component through <emphasis>binary patching</emphasis>. If
|
||||
patches are available on a server, and you try to install a new
|
||||
version of some component, Nix will automatically apply a patch (or
|
||||
sequence of patches), if available, to transform the installed
|
||||
component into the new version.</para></listitem>
|
||||
</simplesect>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
<simplesect><title>Multi-user support</title>
|
||||
|
||||
<para>Starting at version 0.11, Nix has multi-user support. This
|
||||
means that non-privileged users can securely install software. Each
|
||||
user can have a different <emphasis>profile</emphasis>, a set of
|
||||
packages in the Nix store that appear in the user’s
|
||||
<envar>PATH</envar>. If a user installs a package that another user
|
||||
has already installed previously, the package won’t be built or
|
||||
downloaded a second time. At the same time, it is not possible for
|
||||
one user to inject a Trojan horse into a package that might be used by
|
||||
another user.</para>
|
||||
|
||||
<!--
|
||||
<para>More details can be found in Section 3 of our <a
|
||||
href="docs/papers.html#securesharing">ASE 2005 paper</a>.</para>
|
||||
-->
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Atomic upgrades and rollbacks</title>
|
||||
|
||||
<para>Since package management operations never overwrite packages in
|
||||
the Nix store but just add new versions in different paths, they are
|
||||
<emphasis>atomic</emphasis>. So during a package upgrade, there is no
|
||||
time window in which the package has some files from the old version
|
||||
and some files from the new version — which would be bad because a
|
||||
program might well crash if it’s started during that period.</para>
|
||||
|
||||
<para>And since package aren’t overwritten, the old versions are still
|
||||
there after an upgrade. This means that you can <emphasis>roll
|
||||
back</emphasis> to the old version:</para>
|
||||
|
||||
<screen>
|
||||
$ nix-env --upgrade <replaceable>some-packages</replaceable>
|
||||
$ nix-env --rollback
|
||||
</screen>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Garbage collection</title>
|
||||
|
||||
<para>When you install a package like this…
|
||||
|
||||
<screen>
|
||||
$ nix-env --uninstall firefox
|
||||
</screen>
|
||||
|
||||
the package isn’t deleted from the system right away (after all, you
|
||||
might want to do a rollback, or it might be in the profiles of other
|
||||
users). Instead, unused packages can be deleted safely by running the
|
||||
<emphasis>garbage collector</emphasis>:
|
||||
|
||||
<screen>
|
||||
$ nix-collect-garbage
|
||||
</screen>
|
||||
|
||||
This deletes all packages that aren’t in use by any user profile or by
|
||||
a currently running program.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Functional package language</title>
|
||||
|
||||
<para>Packages are built from <emphasis>Nix expressions</emphasis>,
|
||||
which is a simple functional language. A Nix expression describes
|
||||
everything that goes into a package build action (a “derivation”):
|
||||
other packages, sources, the build script, environment variables for
|
||||
the build script, etc. Nix tries very hard to ensure that Nix
|
||||
expressions are <emphasis>deterministic</emphasis>: building a Nix
|
||||
expression twice should yield the same result.</para>
|
||||
|
||||
<para>Because it’s a functional language, it’s easy to support
|
||||
building variants of a package: turn the Nix expression into a
|
||||
function and call it any number of times with the appropriate
|
||||
arguments. Due to the hashing scheme, variants don’t conflict with
|
||||
each other in the Nix store.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Transparent source/binary deployment</title>
|
||||
|
||||
<para>Nix expressions generally describe how to build a package from
|
||||
source, so an installation action like
|
||||
|
||||
<screen>
|
||||
$ nix-env --install firefox
|
||||
</screen>
|
||||
|
||||
<emphasis>could</emphasis> cause quite a bit of build activity, as not
|
||||
only Firefox but also all its dependencies (all the way up to the C
|
||||
library and the compiler) would have to built, at least if they are
|
||||
not already in the Nix store. This is a <emphasis>source deployment
|
||||
model</emphasis>. For most users, building from source is not very
|
||||
pleasant as it takes far too long. However, Nix can automatically
|
||||
skip building from source and download a pre-built binary instead if
|
||||
it knows about it. <emphasis>Nix channels</emphasis> provide Nix
|
||||
expressions along with pre-built binaries.</para>
|
||||
|
||||
<!--
|
||||
<para>source deployment model (like <a
|
||||
href="http://www.gentoo.org/">Gentoo</a>) and a binary model (like
|
||||
RPM)</para>
|
||||
-->
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Binary patching</title>
|
||||
|
||||
<para>In addition to downloading binaries automatically if they’re
|
||||
available, Nix can download binary deltas that patch an existing
|
||||
package in the Nix store into a new version. This speeds up
|
||||
upgrades.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Nix Packages collection</title>
|
||||
|
||||
<para>We provide a large set of Nix expressions containing hundreds of
|
||||
existing Unix packages, the <emphasis>Nix Packages
|
||||
collection</emphasis> (Nixpkgs).</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>Service deployment</title>
|
||||
|
||||
<para>Nix can be used not only for rolling out packages, but also
|
||||
complete <emphasis>configurations</emphasis> of services. This is
|
||||
done by treating all the static bits of a service (such as software
|
||||
packages, configuration files, control scripts, static web pages,
|
||||
etc.) as “packages” that can be built by Nix expressions. As a
|
||||
result, all the features above apply to services as well: for
|
||||
instance, you can roll back a web server configuration if a
|
||||
configuration change turns out to be undesirable, you can easily have
|
||||
multiple instances of a service (e.g., a test and production server),
|
||||
and because the whole service is built in a purely functional way from
|
||||
a Nix expression, it is repeatable so you can easily reproduce the
|
||||
service on another machine.</para>
|
||||
|
||||
<!--
|
||||
<para>You can read more about this in our <a
|
||||
href="docs/papers.html#servicecm">SCM-12 paper</a>.</para>
|
||||
-->
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<simplesect><title>NixOS</title>
|
||||
|
||||
<para>NixOS is a Linux distribution based on Nix. It uses Nix not
|
||||
just for package management but also to manage the system
|
||||
configuration (e.g., to build configuration files in
|
||||
<filename>/etc</filename>). This means, among other things, that it’s
|
||||
possible to easily roll back the entire configuration of the system to
|
||||
an earlier state. Also, users can install software without root
|
||||
privileges. For more information and downloads, see the <link
|
||||
xlink:href="http://nixos.org/">NixOS homepage</link>.</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
|
||||
<!-- other features:
|
||||
|
||||
- build farms
|
||||
- reproducibility (Nix expressions allows whole configuration to be rebuilt)
|
||||
|
||||
-->
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>About us</title>
|
||||
|
||||
<para>Nix was originally developed at the <link
|
||||
xlink:href="http://www.cs.uu.nl/">Department of Information and
|
||||
Computing Sciences</link>, Utrecht University by the <link
|
||||
xlink:href="http://www.cs.uu.nl/wiki/Trace/WebHome">TraCE
|
||||
project</link> (2003-2008). The project was funded by the Software
|
||||
Engineering Research Program <link
|
||||
xlink:href="http://www.jacquard.nl/">Jacquard</link> to improve the
|
||||
support for variability in software systems. Further funding is now
|
||||
provided by the NIRICT LaQuSo Build Farm project.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>About this manual</title>
|
||||
|
||||
<para>This manual tells you how to install and use Nix and how to
|
||||
write Nix expressions for software not already in the Nix Packages
|
||||
collection. It also discusses some advanced topics, such as setting
|
||||
up a Nix-based build farm, and doing service deployment using
|
||||
Nix.</para>
|
||||
up a Nix-based build farm.</para>
|
||||
|
||||
<note><para>Some background information on Nix can be found in a
|
||||
number of papers. The ICSE 2004 paper <citetitle
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/pubs/immdsd-icse2004-final.pdf'>Imposing
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>License</title>
|
||||
|
||||
<para>Nix is free software; you can redistribute it and/or modify it
|
||||
under the terms of the <link
|
||||
xlink:href="http://www.gnu.org/licenses/lgpl.html">GNU Lesser General
|
||||
Public License</link> as published by the <link
|
||||
xlink:href="http://www.fsf.org/">Free Software Foundation</link>;
|
||||
either version 2.1 of the License, or (at your option) any later
|
||||
version. Nix is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>More information</title>
|
||||
|
||||
<para>Some background information on Nix can be found in a number of
|
||||
papers. The ICSE 2004 paper <citetitle
|
||||
xlink:href='http://www.st.ewi.tudelft.nl/~dolstra/pubs/immdsd-icse2004-final.pdf'>Imposing
|
||||
a Memory Management Discipline on Software Deployment</citetitle>
|
||||
discusses the hashing mechanism used to ensure reliable dependency
|
||||
identification and non-interference between different versions and
|
||||
variants of packages. The LISA 2004 paper <citetitle
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/pubs/nspfssd-lisa2004-final.pdf'>Nix:
|
||||
xlink:href='http://www.st.ewi.tudelft.nl/~dolstra/pubs/nspfssd-lisa2004-final.pdf'>Nix:
|
||||
A Safe and Policy-Free System for Software Deployment</citetitle>
|
||||
gives a more general discussion of Nix from a system-administration
|
||||
perspective. The CBSE 2005 paper <citetitle
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/pubs/eupfcdm-cbse2005-final.pdf'>Efficient
|
||||
xlink:href='http://www.st.ewi.tudelft.nl/~dolstra/pubs/eupfcdm-cbse2005-final.pdf'>Efficient
|
||||
Upgrading in a Purely Functional Component Deployment Model
|
||||
</citetitle> is about transparent patch deployment in Nix. Finally,
|
||||
the SCM-12 paper <citetitle
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/pubs/servicecm-scm12-final.pdf'>
|
||||
</citetitle> is about transparent patch deployment in Nix. The SCM-12
|
||||
paper <citetitle
|
||||
xlink:href='http://www.st.ewi.tudelft.nl/~dolstra/pubs/servicecm-scm12-final.pdf'>
|
||||
Service Configuration Management</citetitle> shows how services (e.g.,
|
||||
web servers) can be deployed and managed through Nix.</para></note>
|
||||
web servers) can be deployed and managed through Nix. A short
|
||||
overview of NixOS is given in the HotOS XI paper <citetitle
|
||||
xlink:href="http://www.st.ewi.tudelft.nl/~dolstra/pubs/hotos-final.pdf">Purely
|
||||
Functional System Configuration Management</citetitle>. The Nix
|
||||
homepage has <link
|
||||
xlink:href="http://nixos.org/docs/papers.html">an up-to-date list
|
||||
of Nix-related papers</link>.</para>
|
||||
|
||||
<para>Nix is the subject of Eelco Dolstra’s PhD thesis <citetitle
|
||||
xlink:href="http://igitur-archive.library.uu.nl/dissertations/2006-0118-200031/index.htm">The
|
||||
Purely Functional Software Deployment Model</citetitle>, which
|
||||
contains most of the papers listed above.</para>
|
||||
|
||||
<para>Nix has a homepage at <link
|
||||
xlink:href="http://nixos.org/"/>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
<surname>Dolstra</surname>
|
||||
</personname>
|
||||
<affiliation>
|
||||
<orgname>Utrecht University</orgname>
|
||||
<orgdiv>Faculty of Science, Department of Information and Computing Sciences</orgdiv>
|
||||
<orgname>Delft University of Technology</orgname>
|
||||
<orgdiv>Department of Software Technology</orgdiv>
|
||||
</affiliation>
|
||||
<contrib>Author</contrib>
|
||||
</author>
|
||||
|
||||
<copyright>
|
||||
@@ -24,10 +25,12 @@
|
||||
<year>2005</year>
|
||||
<year>2006</year>
|
||||
<year>2007</year>
|
||||
<year>2008</year>
|
||||
<year>2009</year>
|
||||
<holder>Eelco Dolstra</holder>
|
||||
</copyright>
|
||||
|
||||
<date>September 2007</date>
|
||||
<date>September 2009</date>
|
||||
|
||||
</info>
|
||||
|
||||
@@ -48,72 +51,29 @@
|
||||
|
||||
<section>
|
||||
<title>Main commands</title>
|
||||
<section xml:id="sec-nix-env">
|
||||
<title>nix-env</title>
|
||||
<xi:include href="nix-env.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-instantiate">
|
||||
<title>nix-instantiate</title>
|
||||
<xi:include href="nix-instantiate.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-store">
|
||||
<title>nix-store</title>
|
||||
<xi:include href="nix-store.xml" />
|
||||
</section>
|
||||
<xi:include href="nix-env.xml" />
|
||||
<xi:include href="nix-instantiate.xml" />
|
||||
<xi:include href="nix-store.xml" />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Utilities</title>
|
||||
<section xml:id="sec-nix-build">
|
||||
<title>nix-build</title>
|
||||
<xi:include href="nix-build.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-channel">
|
||||
<title>nix-channel</title>
|
||||
<xi:include href="nix-channel.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-collect-garbage">
|
||||
<title>nix-collect-garbage</title>
|
||||
<xi:include href="nix-collect-garbage.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-copy-closure">
|
||||
<title>nix-copy-closure</title>
|
||||
<xi:include href="nix-copy-closure.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-hash">
|
||||
<title>nix-hash</title>
|
||||
<xi:include href="nix-hash.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-install-package">
|
||||
<title>nix-install-package</title>
|
||||
<xi:include href="nix-install-package.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-pack-closure">
|
||||
<title>nix-pack-closure</title>
|
||||
<xi:include href="nix-pack-closure.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-prefetch-url">
|
||||
<title>nix-prefetch-url</title>
|
||||
<xi:include href="nix-prefetch-url.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-pull">
|
||||
<title>nix-pull</title>
|
||||
<xi:include href="nix-pull.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-push">
|
||||
<title>nix-push</title>
|
||||
<xi:include href="nix-push.xml" />
|
||||
</section>
|
||||
<section xml:id="sec-nix-unpack-closure">
|
||||
<title>nix-unpack-closure</title>
|
||||
<xi:include href="nix-unpack-closure.xml" />
|
||||
</section>
|
||||
<xi:include href="nix-build.xml" />
|
||||
<xi:include href="nix-channel.xml" />
|
||||
<xi:include href="nix-collect-garbage.xml" />
|
||||
<xi:include href="nix-copy-closure.xml" />
|
||||
<xi:include href="nix-hash.xml" />
|
||||
<xi:include href="nix-install-package.xml" />
|
||||
<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" />
|
||||
</section>
|
||||
|
||||
|
||||
</appendix>
|
||||
|
||||
<xi:include href="troubleshooting.xml" />
|
||||
<xi:include href="bugs.xml" />
|
||||
<!-- <xi:include href="bugs.xml" /> -->
|
||||
<xi:include href="glossary.xml" />
|
||||
|
||||
<appendix>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-build">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-build</refentrytitle>
|
||||
@@ -19,6 +20,7 @@
|
||||
<command>nix-build</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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-channel">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-channel</refentrytitle>
|
||||
@@ -62,11 +63,11 @@ also <xref linkend="sec-channels" />.</para>
|
||||
<varlistentry><term><option>--update</option></term>
|
||||
|
||||
<listitem><para>Downloads the Nix expressions of all subscribed
|
||||
channels, makes the conjunction of these the default for
|
||||
<command>nix-env</command> operations (by calling <command>nix-env
|
||||
-I</command>), and performs a <command>nix-pull</command> on the
|
||||
manifests of all channels to make pre-built binaries
|
||||
available.</para></listitem>
|
||||
channels, makes them the default for <command>nix-env</command>
|
||||
operations (by symlinking them in the directory
|
||||
<filename>~/.nix-defexpr</filename>), and performs a
|
||||
<command>nix-pull</command> on the manifests of all channels to
|
||||
make pre-built binaries available.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-collect-garbage">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-collect-garbage</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-copy-closure">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-copy-closure</refentrytitle>
|
||||
@@ -128,7 +129,7 @@ those paths. If this bothers you, use
|
||||
<para>Copy Firefox with all its dependencies to a remote machine:
|
||||
|
||||
<screen>
|
||||
$ nix-copy-closure alice@itchy.labs $(type -tP firefox)</screen>
|
||||
$ nix-copy-closure --to alice@itchy.labs $(type -tP firefox)</screen>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-env">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-env</refentrytitle>
|
||||
@@ -19,13 +20,7 @@
|
||||
<command>nix-env</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>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
<arg choice='plain'><option>-A</option></arg>
|
||||
</group>
|
||||
<replaceable>attrPath</replaceable>
|
||||
</arg>
|
||||
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--file</option></arg>
|
||||
@@ -45,9 +40,6 @@
|
||||
<replaceable>system</replaceable>
|
||||
</arg>
|
||||
<arg><option>--dry-run</option></arg>
|
||||
<arg><option>--from-expression</option></arg>
|
||||
<arg><option>-E</option></arg>
|
||||
<arg><option>--from-profile</option> <replaceable>path</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>operation</replaceable></arg>
|
||||
<arg rep='repeat'><replaceable>options</replaceable></arg>
|
||||
<arg rep='repeat'><replaceable>arguments</replaceable></arg>
|
||||
@@ -58,7 +50,7 @@
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The command <command>nix-env</command> is used to manipulate Nix
|
||||
user environments. User environments are sets of software components
|
||||
user environments. User environments are sets of software packages
|
||||
available to a user at some point in time. In other words, they are a
|
||||
synthesised view of the programs available in the Nix store. There
|
||||
may be many user environments: different users can have different
|
||||
@@ -151,13 +143,33 @@ linkend="sec-common-options" />.</para>
|
||||
|
||||
<varlistentry><term><filename>~/.nix-defexpr</filename></term>
|
||||
|
||||
<!-- !!! .nix-defexpr can be a directory now -->
|
||||
|
||||
<listitem><para>The default Nix expression used by the
|
||||
<option>--install</option>, <option>--upgrade</option>, and
|
||||
<option>--query --available</option> operations to obtain
|
||||
derivations. The <option>--file</option> option may be used to
|
||||
override this default.</para></listitem>
|
||||
<listitem><para>A directory that contains the default Nix
|
||||
expressions used by the <option>--install</option>,
|
||||
<option>--upgrade</option>, and <option>--query
|
||||
--available</option> operations to obtain derivations. The
|
||||
<option>--file</option> option may be used to override this
|
||||
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
|
||||
|
||||
<programlisting>
|
||||
{
|
||||
foo = import ~/.nix-defexpr/foo;
|
||||
bar = import ~/.nix-defexpr/bar;
|
||||
}</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>The command <command>nix-channel</command> places symlinks
|
||||
to the downloaded Nix expressions from each subscribed channel in
|
||||
this directory.</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
@@ -190,6 +202,7 @@ linkend="sec-common-options" />.</para>
|
||||
<arg choice='plain'><option>--install</option></arg>
|
||||
<arg choice='plain'><option>-i</option></arg>
|
||||
</group>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-inst-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
|
||||
<group choice='opt'>
|
||||
<arg choice='plain'><option>--preserve-installed</option></arg>
|
||||
<arg choice='plain'><option>-P</option></arg>
|
||||
@@ -221,11 +234,21 @@ number of possible ways:
|
||||
<para>If there are multiple derivations matching a name in
|
||||
<replaceable>args</replaceable> that have the same name (e.g.,
|
||||
<literal>gcc-3.3.6</literal> and <literal>gcc-4.1.1</literal>), then
|
||||
only the highest version will be installed. You can force the
|
||||
installation of multiple derivations with the same name by being
|
||||
specific about the versions. For instance, <literal>nix-env -i
|
||||
gcc-3.3.6 gcc-4.1.1</literal> will install both version of GCC (and
|
||||
will probably cause a user environment conflict!).</para></listitem>
|
||||
the derivation with the highest <emphasis>priority</emphasis> is
|
||||
used. A derivation can define a priority by declaring the
|
||||
<varname>meta.priority</varname> attribute. This attribute should
|
||||
be a number, with a higher value denoting a lower priority. The
|
||||
default priority is <literal>0</literal>.</para>
|
||||
|
||||
<para>If there are multiple matching derivations with the same
|
||||
priority, then the derivation with the highest version will be
|
||||
installed.</para>
|
||||
|
||||
<para>You can force the installation of multiple derivations with
|
||||
the same name by being specific about the versions. For instance,
|
||||
<literal>nix-env -i gcc-3.3.6 gcc-4.1.1</literal> will install both
|
||||
version of GCC (and will probably cause a user environment
|
||||
conflict!).</para></listitem>
|
||||
|
||||
<listitem><para>If <link
|
||||
linkend='opt-attr'><option>--attr</option></link>
|
||||
@@ -272,6 +295,15 @@ number of possible ways:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><option>--prebuild-only</option> / <option>-b</option></term>
|
||||
|
||||
<listitem><para>Use only derivations for which a substitute is
|
||||
registered, i.e., there is a pre-built binary available that can
|
||||
be downloaded in lieu of building the derivation. Thus, no
|
||||
packages will be built from source.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--preserve-installed</option></term>
|
||||
<term><option>-P</option></term>
|
||||
|
||||
@@ -387,7 +419,7 @@ the following paths will be substituted:
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--upgrade</option></title>
|
||||
<refsection xml:id="rsec-nix-env-upgrade"><title>Operation <option>--upgrade</option></title>
|
||||
|
||||
<refsection><title>Synopsis</title>
|
||||
|
||||
@@ -397,6 +429,7 @@ the following paths will be substituted:
|
||||
<arg choice='plain'><option>--upgrade</option></arg>
|
||||
<arg choice='plain'><option>-u</option></arg>
|
||||
</group>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-inst-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
|
||||
<group choice='opt'>
|
||||
<arg choice='plain'><option>--lt</option></arg>
|
||||
<arg choice='plain'><option>--leq</option></arg>
|
||||
@@ -471,6 +504,9 @@ installed.</para>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>For the other flags, see <option
|
||||
linkend="rsec-nix-env-install">--install</option>.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
@@ -491,7 +527,7 @@ upgrading `mozilla-1.2' to `mozilla-1.4'</screen>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Versions</title>
|
||||
<refsection xml:id="ssec-version-comparisons"><title>Versions</title>
|
||||
|
||||
<para>The upgrade operation determines whether a derivation
|
||||
<varname>y</varname> is an upgrade of a derivation
|
||||
@@ -580,6 +616,111 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
|
||||
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection xml:id="rsec-nix-env-set-flag"><title>Operation <option>--set-flag</option></title>
|
||||
|
||||
<refsection><title>Synopsis</title>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>nix-env</command>
|
||||
<arg choice='plain'><option>--set-flag</option></arg>
|
||||
<arg choice='plain'><replaceable>name</replaceable></arg>
|
||||
<arg choice='plain'><replaceable>value</replaceable></arg>
|
||||
<arg choice='plain' rep='repeat'><replaceable>drvnames</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The <option>--set-flag</option> operation allows meta attributes
|
||||
of installed packages to be modified. There are several attributes
|
||||
that can be usefully modified, because they affect the behaviour of
|
||||
<command>nix-env</command> or the user environment build
|
||||
script:
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para><varname>priority</varname> can be changed to
|
||||
resolve filename clashes. The user environment build script uses
|
||||
the <varname>meta.priority</varname> attribute of derivations to
|
||||
resolve filename collisions between packages. Lower priority values
|
||||
denote a higher priority. For instance, the GCC wrapper package and
|
||||
the Binutils package in Nixpkgs both have a file
|
||||
<filename>bin/ld</filename>, so previously if you tried to install
|
||||
both you would get a collision. Now, on the other hand, the GCC
|
||||
wrapper declares a higher priority than Binutils, so the former’s
|
||||
<filename>bin/ld</filename> is symlinked in the user
|
||||
environment.</para></listitem>
|
||||
|
||||
<listitem><para><varname>keep</varname> can be set to
|
||||
<literal>true</literal> to prevent the package from being upgraded
|
||||
or replaced. This is useful if you want to hang on to an older
|
||||
version of a package.</para></listitem>
|
||||
|
||||
<listitem><para><varname>active</varname> can be set to
|
||||
<literal>false</literal> to “disable” the package. That is, no
|
||||
symlinks will be generated to the files of the package, but it
|
||||
remains part of the profile (so it won’t be garbage-collected). It
|
||||
can be set back to <literal>true</literal> to re-enable the
|
||||
package.</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
|
||||
<para>To prevent the currently installed Firefox from being upgraded:
|
||||
|
||||
<screen>
|
||||
$ nix-env --set-flag keep true firefox</screen>
|
||||
|
||||
After this, <command>nix-env -u</command> will ignore Firefox.</para>
|
||||
|
||||
<para>To disable the currently installed Firefox, then install a new
|
||||
Firefox while the old remains part of the profile:
|
||||
|
||||
<screen>
|
||||
$ nix-env -q \*
|
||||
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'
|
||||
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>
|
||||
|
||||
$ nix-env --set-flag active false firefox
|
||||
setting flag on `firefox-2.0.0.9'
|
||||
|
||||
$ nix-env --preserve-installed -i firefox-2.0.0.11
|
||||
installing `firefox-2.0.0.11'
|
||||
|
||||
$ nix-env -q \*
|
||||
firefox-2.0.0.11 <lineannotation>(the enabled one)</lineannotation>
|
||||
firefox-2.0.0.9 <lineannotation>(the disabled one)</lineannotation></screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>To make files from <literal>binutils</literal> take precedence
|
||||
over files from <literal>gcc</literal>:
|
||||
|
||||
<screen>
|
||||
$ nix-env --set-flag priority 5 binutils
|
||||
$ nix-env --set-flag priority 10 gcc</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--query</option></title>
|
||||
@@ -592,13 +733,14 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
|
||||
<arg choice='plain'><option>--query</option></arg>
|
||||
<arg choice='plain'><option>-q</option></arg>
|
||||
</group>
|
||||
<arg><option>--xml</option></arg>
|
||||
<group choice='opt'>
|
||||
<arg choice='plain'><option>--installed</option></arg>
|
||||
<arg choice='plain'><option>--available</option></arg>
|
||||
<arg choice='plain'><option>-a</option></arg>
|
||||
</group>
|
||||
|
||||
<sbr />
|
||||
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--status</option></arg>
|
||||
@@ -607,8 +749,8 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
|
||||
</arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
<arg choice='plain'><option>-A</option></arg>
|
||||
<arg choice='plain'><option>--attr-path</option></arg>
|
||||
<arg choice='plain'><option>-P</option></arg>
|
||||
</group>
|
||||
</arg>
|
||||
<arg><option>--no-name</option></arg>
|
||||
@@ -622,6 +764,28 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
|
||||
<arg><option>--drv-path</option></arg>
|
||||
<arg><option>--out-path</option></arg>
|
||||
<arg><option>--description</option></arg>
|
||||
<arg><option>--meta</option></arg>
|
||||
|
||||
<sbr />
|
||||
|
||||
<arg><option>--xml</option></arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--prebuilt-only</option></arg>
|
||||
<arg choice='plain'><option>-b</option></arg>
|
||||
</group>
|
||||
</arg>
|
||||
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
<arg choice='plain'><option>-A</option></arg>
|
||||
</group>
|
||||
<replaceable>attribute-path</replaceable>
|
||||
</arg>
|
||||
|
||||
<sbr />
|
||||
|
||||
<arg choice='plain' rep='repeat'><replaceable>names</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
@@ -698,6 +862,16 @@ user environment elements, etc. -->
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--prebuild-only</option> / <option>-b</option></term>
|
||||
|
||||
<listitem><para>Show only derivations for which a substitute is
|
||||
registered, i.e., there is a pre-built binary available that can
|
||||
be downloaded in lieu of building the derivation. Thus, this
|
||||
shows all packages that probably can be installed
|
||||
quickly.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--status</option></term>
|
||||
<term><option>-s</option></term>
|
||||
|
||||
@@ -717,8 +891,8 @@ user environment elements, etc. -->
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--attr</option></term>
|
||||
<term><option>-a</option></term>
|
||||
<varlistentry><term><option>--attr-path</option></term>
|
||||
<term><option>-P</option></term>
|
||||
|
||||
<listitem><para>Print the <emphasis>attribute path</emphasis> of
|
||||
the derivation, which can be used to unambiguously select it using
|
||||
@@ -741,35 +915,35 @@ user environment elements, etc. -->
|
||||
<listitem><para>Compare installed versions to available versions,
|
||||
or vice versa (if <option>--available</option> is given). This is
|
||||
useful for quickly seeing whether upgrades for installed
|
||||
components are available in a Nix expression. A column is added
|
||||
packages are available in a Nix expression. A column is added
|
||||
with the following meaning:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><literal><</literal> <replaceable>version</replaceable></term>
|
||||
|
||||
<listitem><para>A newer version of the component is available
|
||||
<listitem><para>A newer version of the package is available
|
||||
or installed.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>=</literal> <replaceable>version</replaceable></term>
|
||||
|
||||
<listitem><para>At most the same version of the component is
|
||||
<listitem><para>At most the same version of the package is
|
||||
available or installed.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>></literal> <replaceable>version</replaceable></term>
|
||||
|
||||
<listitem><para>Only older versions of the component are
|
||||
<listitem><para>Only older versions of the package are
|
||||
available or installed.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>- ?</literal></term>
|
||||
|
||||
<listitem><para>No version of the component is available or
|
||||
<listitem><para>No version of the package is available or
|
||||
installed.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
@@ -810,6 +984,14 @@ user environment elements, etc. -->
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--meta</option></term>
|
||||
|
||||
<listitem><para>Print all of the meta-attributes of the
|
||||
derivation. This option is only available with
|
||||
<option>--xml</option>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-hash">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-hash</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-install-package">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-install-package</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-instantiate">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-instantiate</refentrytitle>
|
||||
|
||||
@@ -178,100 +178,5 @@
|
||||
</productionset>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
<sect1>
|
||||
<title>Semantics</title>
|
||||
|
||||
|
||||
|
||||
<sect2>
|
||||
<title>Built-in functions</title>
|
||||
|
||||
<para>
|
||||
The Nix language provides the following built-in function
|
||||
(<quote>primops</quote>):
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><function>import</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Evaluates the expression <replaceable>e</replaceable>,
|
||||
which must yield a path value. The Nix expression
|
||||
stored at this path in the file system is then read,
|
||||
parsed, and evaluated. Returns the result of the
|
||||
evaluation of the Nix expression just read.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Example: <literal>import ./foo.nix</literal> evaluates
|
||||
the expression stored in <filename>foo.nix</filename>
|
||||
(in the directory containing the expression in which the
|
||||
<function>import</function> occurs).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><function>derivation</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Evaluates the expression <replaceable>e</replaceable>,
|
||||
which must yield an attribute set. [...]
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><function>baseNameOf</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Evaluates the expression <replaceable>e</replaceable>,
|
||||
which must yield a string value, and returns a string
|
||||
representing its <emphasis>base name</emphasis>. This
|
||||
is the substring following the last path separator
|
||||
(<literal>/</literal>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Example: <literal>baseNameOf "/foo/bar"</literal>
|
||||
returns <literal>"bar"</literal>, and
|
||||
<literal>baseNameOf "/foo/bar/"</literal> returns
|
||||
<literal>""</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><function>toString</function>
|
||||
<replaceable>e</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Evaluates the expression <replaceable>e</replaceable>
|
||||
and coerces it into a string, if possible. Only
|
||||
strings, paths, and URIs can be so coerced.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Example: <literal>toString
|
||||
http://www.cs.uu.nl/</literal> returns
|
||||
<literal>"http://www.cs.uu.nl/"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
</appendix>
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-pack-closure</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-pack-closure</refname>
|
||||
<refpurpose>pack the closure of a store path into a single file that
|
||||
can be unpacked with
|
||||
<command>nix-unpack-closure</command></refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-pack-closure</command>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The command <command>nix-pack-closure</command> packs the
|
||||
contents of the store paths <replaceable>paths</replaceable> and
|
||||
<emphasis>all their dependencies</emphasis> into a single file, which
|
||||
is written to standard output. (That is, it
|
||||
<emphasis>serialises</emphasis> <replaceable>paths</replaceable>.)
|
||||
The output can then be unpacked into the Nix store of another machine
|
||||
using <command>nix-unpack-closure</command>.</para>
|
||||
|
||||
<para>Together, <command>nix-pack-closure</command> and
|
||||
<command>nix-unpack-closure</command> provide a quick and easy way to
|
||||
deploy a package to a different machine. However, as the output of
|
||||
<command>nix-pack-closure</command> tends to be rather large (since it
|
||||
contains all dependencies), it’s not very efficient.
|
||||
<command>nix-push</command> and <command>nix-pull</command> are more
|
||||
efficient, but are also a bit more cumbersome to use.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
|
||||
<para>To copy some instance of Subversion with all its dependencies to
|
||||
another machine:
|
||||
|
||||
<screen>
|
||||
$ nix-pack-closure /nix/store/hj232g1r...-subversion-1.3.0 > svn.closure
|
||||
|
||||
<lineannotation>Copy <!-- !!! <filename> -->svn.closure to the remote machine, then on the remote machine do:</lineannotation>
|
||||
$ nix-unpack-closure < svn.closure</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Copy the program <command>azureus</command> with all its
|
||||
dependencies to the machine <literal>scratchy</literal>:
|
||||
|
||||
<screen>
|
||||
$ nix-pack-closure $(which azureus) | ssh scratchy nix-unpack-closure</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>As a variation on the previous example, copy
|
||||
<command>azureus</command>, and also install it in the user’s profile
|
||||
on the target machine:
|
||||
|
||||
<screen>
|
||||
$ nix-pack-closure $(which azureus) | ssh scratchy 'nix-env -i $(nix-unpack-closure)'</screen>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refentry>
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-prefetch-url">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-prefetch-url</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-pull">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-pull</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-push">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-push</refentrytitle>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xml:id="sec-nix-store">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-store</refentrytitle>
|
||||
@@ -128,6 +129,7 @@ lrwxrwxrwx 1 ... 2005-03-13 21:10 /home/eelco/bla/result -> /nix/store/1r1134
|
||||
<arg choice='plain'><option>-r</option></arg>
|
||||
</group>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
<arg><option>--dry-run</option></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
</refsection>
|
||||
@@ -166,6 +168,11 @@ 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>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
@@ -204,6 +211,8 @@ linkend="sec-nix-build"><command>nix-build</command></link> does.</para>
|
||||
<arg choice='plain'><option>--print-dead</option></arg>
|
||||
<arg choice='plain'><option>--delete</option></arg>
|
||||
</group>
|
||||
<arg><option>--max-freed</option> <replaceable>bytes</replaceable></arg>
|
||||
<arg><option>--max-links</option> <replaceable>nrlinks</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
</refsection>
|
||||
@@ -258,7 +267,34 @@ the Nix store not reachable via file system references from a set of
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>The behaviour of the collector is influenced by the <link
|
||||
<para>By default, all unreachable paths are deleted. The following
|
||||
options control what gets deleted and in what order:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><option>--max-freed</option> <replaceable>bytes</replaceable></term>
|
||||
|
||||
<listitem><para>Keep deleting paths until at least
|
||||
<replaceable>bytes</replaceable> bytes have been
|
||||
deleted, then stop.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--max-links</option> <replaceable>nrlinks</replaceable></term>
|
||||
|
||||
<listitem><para>Keep deleting paths until the hard link count on
|
||||
<filename>/nix/store</filename> is less than
|
||||
<replaceable>nrlinks</replaceable>, then stop. This is useful for
|
||||
very large Nix stores on filesystems with a 32000 subdirectories
|
||||
limit (like <literal>ext3</literal>).</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
||||
<para>The behaviour of the collector is also influenced by the <link
|
||||
linkend="conf-gc-keep-outputs"><literal>gc-keep-outputs</literal></link>
|
||||
and <link
|
||||
linkend="conf-gc-keep-derivations"><literal>gc-keep-derivations</literal></link>
|
||||
@@ -284,6 +320,13 @@ deleting `/nix/store/kq82idx6g0nyzsp2s14gfsc38npai7lf-cairo-1.0.4.tar.gz.drv'
|
||||
|
||||
</para>
|
||||
|
||||
<para>To delete at least 100 MiBs of unreachable paths:
|
||||
|
||||
<screen>
|
||||
$ nix-store --gc --max-freed $((100 * 1024 * 1024))</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
@@ -299,7 +342,7 @@ deleting `/nix/store/kq82idx6g0nyzsp2s14gfsc38npai7lf-cairo-1.0.4.tar.gz.drv'
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--gc</option></arg>
|
||||
<arg choice='plain'><option>--delete</option></arg>
|
||||
<arg><option>--ignore-liveness</option></arg>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
@@ -361,6 +404,7 @@ error: cannot delete path `/nix/store/zq0h41l75vlb4z45kzgjjmsjxvcv1qk7-mesa-6.4'
|
||||
<arg choice='plain'><option>--tree</option></arg>
|
||||
<arg choice='plain'><option>--binding</option> <replaceable>name</replaceable></arg>
|
||||
<arg choice='plain'><option>--hash</option></arg>
|
||||
<arg choice='plain'><option>--roots</option></arg>
|
||||
</group>
|
||||
<arg><option>--use-output</option></arg>
|
||||
<arg><option>-u</option></arg>
|
||||
@@ -543,12 +587,20 @@ query is applied to the target of the symlink.</para>
|
||||
<varlistentry><term><option>--hash</option></term>
|
||||
|
||||
<listitem><para>Prints the SHA-256 hash of the contents of the
|
||||
store path <replaceable>paths</replaceable>. Since the hash is
|
||||
store paths <replaceable>paths</replaceable>. Since the hash is
|
||||
stored in the Nix database, this is a fast
|
||||
operation.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--roots</option></term>
|
||||
|
||||
<listitem><para>Prints the garbage collector roots that point,
|
||||
directly or indirectly, at the store paths
|
||||
<replaceable>paths</replaceable>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
@@ -626,6 +678,18 @@ $ gv graph.ps</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Show every garbage collector root that points to a store path
|
||||
that depends on <command>svn</command>:
|
||||
|
||||
<screen>
|
||||
$ nix-store -q --roots $(which svn)
|
||||
/nix/var/nix/profiles/default-81-link
|
||||
/nix/var/nix/profiles/default-82-link
|
||||
/nix/var/nix/profiles/per-user/eelco/profile-97-link
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
@@ -779,4 +843,222 @@ archive is read from standard input.</para>
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection xml:id='refsec-nix-store-export'><title>Operation <option>--export</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--export</option></arg>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--export</option> writes a serialisation
|
||||
of the specified store paths to standard output in a format that can
|
||||
be imported into another Nix store with <command
|
||||
linkend="refsec-nix-store-import">nix-store --import</command>. This
|
||||
is like <command linkend="refsec-nix-store-dump">nix-store
|
||||
--dump</command>, except that the NAR archive produced by that command
|
||||
doesn’t contain the necessary meta-information to allow it to be
|
||||
imported into another Nix store (namely, the set of references of the
|
||||
path).</para>
|
||||
|
||||
<para>This command does not produce a <emphasis>closure</emphasis> of
|
||||
the specified paths, so if a store path references other store paths
|
||||
that are missing in the target Nix store, the import will fail. To
|
||||
copy a whole closure, do something like
|
||||
|
||||
<screen>
|
||||
$ nix-store --export $(nix-store -qR <replaceable>paths</replaceable>) > out</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>For an example of how <option>--export</option> and
|
||||
<option>--import</option> can be used, see the source of the <command
|
||||
linkend="sec-nix-copy-closure">nix-copy-closure</command>
|
||||
command.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection xml:id='refsec-nix-store-import'><title>Operation <option>--import</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--import</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--export</option> reads a serialisation of
|
||||
a set of store paths produced by <command
|
||||
linkend="refsec-nix-store-export">nix-store --import</command> from
|
||||
standard input and adds those store paths to the Nix store. Paths
|
||||
that already exist in the Nix store are ignored. If a path refers to
|
||||
another path that doesn’t exist in the Nix store, the import
|
||||
fails.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--optimise</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--optimise</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--optimise</option> reduces Nix store disk
|
||||
space usage by finding identical files in the store and hard-linking
|
||||
them to each other. It typically reduces the size of the store by
|
||||
something like 25-35%. Only regular files and symlinks are
|
||||
hard-linked in this manner. Files are considered identical when they
|
||||
have the same NAR archive serialisation: that is, regular files must
|
||||
have the same contents and permission (executable or non-executable),
|
||||
and symlinks must have the same contents.</para>
|
||||
|
||||
<para>After completion, or when the command is interrupted, a report
|
||||
on the achieved savings is printed on standard error.</para>
|
||||
|
||||
<para>Use <option>-vv</option> or <option>-vvv</option> to get some
|
||||
progress indication.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Example</title>
|
||||
|
||||
<screen>
|
||||
$ nix-store --optimise
|
||||
hashing files in `/nix/store/qhqx7l2f1kmwihc9bnxs7rc159hsxnf3-gcc-4.1.1'
|
||||
<replaceable>...</replaceable>
|
||||
541838819 bytes (516.74 MiB) freed by hard-linking 54143 files;
|
||||
there are 114486 files with equal contents out of 215894 files in total
|
||||
</screen>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--read-log</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--read-log</option></arg>
|
||||
<arg choice='plain'><option>-l</option></arg>
|
||||
</group>
|
||||
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--read-log</option> prints the build log
|
||||
of the specified store paths on standard output. The build log is
|
||||
whatever the builder of a derivation wrote to standard output and
|
||||
standard error. If a store path is not a derivation, the deriver of
|
||||
the store path is used.</para>
|
||||
|
||||
<para>Build logs are kept in
|
||||
<filename>/nix/var/log/nix/drvs</filename>. However, there is no
|
||||
guarantee that a build log is available for any particular store
|
||||
path. For instance, if the path was downloaded as a pre-built binary
|
||||
through a substitute, then the log is unavailable.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Example</title>
|
||||
|
||||
<screen>
|
||||
$ nix-store -l $(which ktorrent)
|
||||
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
|
||||
unpacking sources
|
||||
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
|
||||
ktorrent-2.2.1/
|
||||
ktorrent-2.2.1/NEWS
|
||||
<replaceable>...</replaceable>
|
||||
</screen>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--dump-db</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--dump-db</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--dump-db</option> writes a dump of the
|
||||
Nix database to standard output. It can be loaded into an empty Nix
|
||||
store using <option>--load-db</option>. This is useful for making
|
||||
backups and when migrating to different database schemas.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--dump-db</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>--load-db</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>--load-db</option> reads a dump of the Nix
|
||||
database created by <option>--dump-db</option> from standard input and
|
||||
loads it into the Nix database.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-unpack-closure</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-unpack-closure</refname>
|
||||
<refpurpose>unpack the closure of a store path created by <command>nix-pack-closure</command> into the Nix store</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-unpack-closure</command>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The command <command>nix-unpack-closure</command> unpacks the
|
||||
closure of a set of store paths created by
|
||||
<command>nix-pack-closure</command> into the local Nix store. The
|
||||
closure is a single file read from standard input. See the
|
||||
description of <command>nix-pack-closure</command> for details and
|
||||
examples.</para>
|
||||
|
||||
<para>The top-level paths in the closure (i.e., the paths passed to
|
||||
the original <command>nix-pack-closure</command> call that created the
|
||||
closure) are printed on standard output. These paths can be passed,
|
||||
for instance, to <literal>nix-env -i</literal> to install them into a
|
||||
user environment on the target machine.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refentry>
|
||||
35
doc/manual/nix-worker.xml
Normal file
35
doc/manual/nix-worker.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<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">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-worker</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>
|
||||
<refpurpose>Nix multi-user support daemon</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-worker</command>
|
||||
<arg choice="plain"><option>--daemon</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The Nix daemon is necessary in multi-user Nix installations. It
|
||||
performs build actions and other operations on the Nix store on behalf
|
||||
of unprivileged users.</para>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
</refentry>
|
||||
@@ -13,6 +13,10 @@
|
||||
</group>
|
||||
<replaceable>number</replaceable>
|
||||
</arg>
|
||||
<arg>
|
||||
<arg><option>--max-silent-time</option></arg>
|
||||
<replaceable>number</replaceable>
|
||||
</arg>
|
||||
<arg><option>--keep-going</option></arg>
|
||||
<arg><option>-k</option></arg>
|
||||
<arg><option>--keep-failed</option></arg>
|
||||
@@ -20,6 +24,7 @@
|
||||
<arg><option>--fallback</option></arg>
|
||||
<arg><option>--readonly-mode</option></arg>
|
||||
<arg><option>--log-type</option> <replaceable>type</replaceable></arg>
|
||||
<arg><option>--show-trace</option></arg>
|
||||
<sbr />
|
||||
|
||||
</nop>
|
||||
|
||||
@@ -103,6 +103,17 @@
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="opt-max-silent-time"><term><option>--max-silent-time</option></term>
|
||||
|
||||
<listitem><para>Sets the maximum number of seconds that a builder
|
||||
can go without producing any data on standard output or standard
|
||||
error. The default is specified by the <link
|
||||
linkend='conf-build-max-silent-time'><literal>build-max-silent-time</literal></link>
|
||||
configuration setting. <literal>0</literal> means no
|
||||
time-out.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--keep-going</option></term>
|
||||
<term><option>-k</option></term>
|
||||
|
||||
@@ -240,14 +251,14 @@
|
||||
|
||||
<programlisting>
|
||||
{ # The system (e.g., `i686-linux') for which to build the packages.
|
||||
system ? __currentSystem
|
||||
system ? builtins.currentSystem
|
||||
<replaceable>...</replaceable>
|
||||
}: <replaceable>...</replaceable></programlisting>
|
||||
|
||||
So if you call this Nix expression (e.g., when you do
|
||||
<literal>nix-env -i <replaceable>pkgname</replaceable></literal>),
|
||||
the function will be called automatically using the value <link
|
||||
linkend='builtin-currentSystem'><literal>__currentSystem</literal></link>
|
||||
linkend='builtin-currentSystem'><literal>builtins.currentSystem</literal></link>
|
||||
for the <literal>system</literal> argument. You can override this
|
||||
using <option>--arg</option>, e.g., <literal>nix-env -i
|
||||
<replaceable>pkgname</replaceable> --arg system
|
||||
@@ -257,6 +268,17 @@
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></term>
|
||||
|
||||
<listitem><para>This option is like <option>--arg</option>, only the
|
||||
value is not a Nix expression but a string. So instead of
|
||||
<literal>--arg system \"i686-linux\"</literal> (the outer quotes are
|
||||
to keep the shell happy) you can say <literal>--argstr system
|
||||
i686-linux</literal>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry xml:id="opt-attr"><term><option>--attr</option> / <option>-A</option>
|
||||
<replaceable>attrPath</replaceable></term>
|
||||
|
||||
@@ -283,6 +305,14 @@
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><option>--show-trace</option></term>
|
||||
|
||||
<listitem><para>Causes Nix to print out a stack trace in case of Nix
|
||||
expression evaluation errors.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
22
doc/manual/opt-inst-syn.xml
Normal file
22
doc/manual/opt-inst-syn.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<nop xmlns="http://docbook.org/ns/docbook">
|
||||
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--prebuilt-only</option></arg>
|
||||
<arg choice='plain'><option>-b</option></arg>
|
||||
</group>
|
||||
</arg>
|
||||
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
<arg choice='plain'><option>-A</option></arg>
|
||||
</group>
|
||||
</arg>
|
||||
|
||||
<arg><option>--from-expression</option></arg>
|
||||
<arg><option>-E</option></arg>
|
||||
|
||||
<arg><option>--from-profile</option> <replaceable>path</replaceable></arg>
|
||||
|
||||
</nop>
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
|
||||
<para>This chapter discusses how to do package management with Nix,
|
||||
i.e., how to obtain, install, upgrade, and erase components. This is
|
||||
i.e., how to obtain, install, upgrade, and erase packages. This is
|
||||
the “user’s” perspective of the Nix system — people
|
||||
who want to <emphasis>create</emphasis> components should consult
|
||||
who want to <emphasis>create</emphasis> packages should consult
|
||||
<xref linkend='chap-writing-nix-expressions' />.</para>
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ who want to <emphasis>create</emphasis> components should consult
|
||||
|
||||
<para>The main command for package management is <link
|
||||
linkend="sec-nix-env"><command>nix-env</command></link>. You can use
|
||||
it to install, upgrade, and erase components, and to query what
|
||||
components are installed or are available for installation.</para>
|
||||
it to install, upgrade, and erase packages, and to query what
|
||||
packages are installed or are available for installation.</para>
|
||||
|
||||
<para>In Nix, different users can have different “views”
|
||||
on the set of installed applications. That is, there might be lots of
|
||||
@@ -30,18 +30,18 @@ environment</emphasis>, which is just a directory tree consisting of
|
||||
symlinks to the files of the active applications. </para>
|
||||
|
||||
<para>Components are installed from a set of <emphasis>Nix
|
||||
expressions</emphasis> that tell Nix how to build those components,
|
||||
expressions</emphasis> that tell Nix how to build those packages,
|
||||
including, if necessary, their dependencies. There is a collection of
|
||||
Nix expressions called the Nix Package collection that contains
|
||||
components ranging from basic development stuff such as GCC and Glibc,
|
||||
packages ranging from basic development stuff such as GCC and Glibc,
|
||||
to end-user applications like Mozilla Firefox. (Nix is however not
|
||||
tied to the Nix Package collection; you could write your own Nix
|
||||
expressions based on it, or completely new ones.) You can download
|
||||
the latest version from <link
|
||||
xlink:href='http://nix.cs.uu.nl/dist/nix' />.</para>
|
||||
xlink:href='http://nixos.org/nixpkgs/download.html' />.</para>
|
||||
|
||||
<para>Assuming that you have downloaded and unpacked a release of Nix
|
||||
Packages, you can view the set of available components in the release:
|
||||
Packages, you can view the set of available packages in the release:
|
||||
|
||||
<screen>
|
||||
$ nix-env -qaf nixpkgs-<replaceable>version</replaceable> '*'
|
||||
@@ -74,7 +74,7 @@ gcc-4.1.1</screen>
|
||||
</para>
|
||||
|
||||
<para>It is also possible to see the <emphasis>status</emphasis> of
|
||||
available components, i.e., whether they are installed into the user
|
||||
available packages, i.e., whether they are installed into the user
|
||||
environment and/or present in the system:
|
||||
|
||||
<screen>
|
||||
@@ -86,24 +86,24 @@ IPS bison-1.875d
|
||||
...</screen>
|
||||
|
||||
The first character (<literal>I</literal>) indicates whether the
|
||||
component is installed in your current user environment. The second
|
||||
package is installed in your current user environment. The second
|
||||
(<literal>P</literal>) indicates whether it is present on your system
|
||||
(in which case installing it into your user environment would be a
|
||||
very quick operation). The last one (<literal>S</literal>) indicates
|
||||
whether there is a so-called <emphasis>substitute</emphasis> for the
|
||||
component, which is Nix’s mechanism for doing binary deployment. It
|
||||
just means that Nix knows that it can fetch a pre-built component from
|
||||
package, which is Nix’s mechanism for doing binary deployment. It
|
||||
just means that Nix knows that it can fetch a pre-built package from
|
||||
somewhere (typically a network server) instead of building it
|
||||
locally.</para>
|
||||
|
||||
<para>So now that we have a set of Nix expressions we can build the
|
||||
components contained in them. This is done using <literal>nix-env
|
||||
packages contained in them. This is done using <literal>nix-env
|
||||
-i</literal>. For instance,
|
||||
|
||||
<screen>
|
||||
$ nix-env -f nixpkgs-<replaceable>version</replaceable> -i subversion</screen>
|
||||
|
||||
will install the component called <literal>subversion</literal> (which
|
||||
will install the package called <literal>subversion</literal> (which
|
||||
is, of course, the <link
|
||||
xlink:href='http://subversion.tigris.org/'>Subversion version
|
||||
management system</link>).</para>
|
||||
@@ -112,21 +112,21 @@ management system</link>).</para>
|
||||
Subversion and all its dependencies. This will take quite a while —
|
||||
typically an hour or two on modern machines. Fortunately, there is a
|
||||
faster way (so do a Ctrl-C on that install operation!): you just need
|
||||
to tell Nix that pre-built binaries of all those components are
|
||||
to tell Nix that pre-built binaries of all those packages are
|
||||
available somewhere. This is done using the
|
||||
<command>nix-pull</command> command, which must be supplied with a URL
|
||||
containing a <emphasis>manifest</emphasis> describing what binaries
|
||||
are available. This URL should correspond to the Nix Packages release
|
||||
that you’re using. For instance, if you obtained a release from <link
|
||||
xlink:href='http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/' />, then
|
||||
you should do:
|
||||
xlink:href='http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x'
|
||||
/>, then you should do:
|
||||
|
||||
<screen>
|
||||
$ nix-pull http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/MANIFEST</screen>
|
||||
$ nix-pull http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x/MANIFEST</screen>
|
||||
|
||||
If you then issue the installation command, it should start
|
||||
downloading binaries from <systemitem
|
||||
class='fqdomainname'>nix.cs.uu.nl</systemitem>, instead of building
|
||||
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>
|
||||
@@ -153,7 +153,7 @@ expressions, use <parameter>-i</parameter> instead of
|
||||
<parameter>-u</parameter>; <parameter>-i</parameter> will remove
|
||||
whatever version is already installed.</para>
|
||||
|
||||
<para>You can also upgrade all components for which there are newer
|
||||
<para>You can also upgrade all packages for which there are newer
|
||||
versions:
|
||||
|
||||
<screen>
|
||||
@@ -199,19 +199,19 @@ set.</para></footnote></para>
|
||||
implementing the ability to allow different users to have different
|
||||
configurations, and to do atomic upgrades and rollbacks. To
|
||||
understand how they work, it’s useful to know a bit about how Nix
|
||||
works. In Nix, components are stored in unique locations in the
|
||||
works. In Nix, packages are stored in unique locations in the
|
||||
<emphasis>Nix store</emphasis> (typically,
|
||||
<filename>/nix/store</filename>). For instance, a particular version
|
||||
of the Subversion component might be stored in a directory
|
||||
of the Subversion package might be stored in a directory
|
||||
<filename>/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3/</filename>,
|
||||
while another version might be stored in
|
||||
<filename>/nix/store/5mq2jcn36ldlmh93yj1n8s9c95pj7c5s-subversion-1.1.2</filename>.
|
||||
The long strings prefixed to the directory names are cryptographic
|
||||
hashes<footnote><para>160-bit truncations of SHA-256 hashes encoded in
|
||||
a base-32 notation, to be precise.</para></footnote> of
|
||||
<emphasis>all</emphasis> inputs involved in building the component —
|
||||
<emphasis>all</emphasis> inputs involved in building the package —
|
||||
sources, dependencies, compiler flags, and so on. So if two
|
||||
components differ in any way, they end up in different locations in
|
||||
packages differ in any way, they end up in different locations in
|
||||
the file system, so they don’t interfere with each other. <xref
|
||||
linkend='fig-user-environments' /> shows a part of a typical Nix
|
||||
store.</para>
|
||||
@@ -231,12 +231,12 @@ $ /nix/store/dpmvp969yhdq...-subversion-1.1.3/bin/svn</screen>
|
||||
|
||||
every time you want to run Subversion. Of course we could set up the
|
||||
<envar>PATH</envar> environment variable to include the
|
||||
<filename>bin</filename> directory of every component we want to use,
|
||||
<filename>bin</filename> directory of every package we want to use,
|
||||
but this is not very convenient since changing <envar>PATH</envar>
|
||||
doesn’t take effect for already existing processes. The solution Nix
|
||||
uses is to create directory trees of symlinks to
|
||||
<emphasis>activated</emphasis> components. These are called
|
||||
<emphasis>user environments</emphasis> and they are components
|
||||
<emphasis>activated</emphasis> packages. These are called
|
||||
<emphasis>user environments</emphasis> and they are packages
|
||||
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
|
||||
@@ -285,8 +285,8 @@ operation, a new user environment and generation link are created
|
||||
based on the current one, and finally the <filename>default</filename>
|
||||
symlink is made to point at the new generation. This last step is
|
||||
atomic on Unix, which explains how we can do atomic upgrades. (Note
|
||||
that the building/installing of new components doesn’t interfere in
|
||||
any way with old components, since they are stored in different
|
||||
that the building/installing of new packages doesn’t interfere in
|
||||
any way with old packages, since they are stored in different
|
||||
locations in the Nix store.)</para>
|
||||
|
||||
<para>If you find that you want to undo a <command>nix-env</command>
|
||||
@@ -331,7 +331,7 @@ default profile, respectively. If the profile doesn’t exist, it will
|
||||
be created automatically. You should be careful about storing a
|
||||
profile in another location than the <filename>profiles</filename>
|
||||
directory, since otherwise it might not be used as a root of the
|
||||
garbage collector (see section <xref linkend='sec-garbage-collection'
|
||||
garbage collector (see <xref linkend='sec-garbage-collection'
|
||||
/>).</para>
|
||||
|
||||
<para>All <command>nix-env</command> operations work on the profile
|
||||
@@ -352,18 +352,18 @@ This will <emphasis>not</emphasis> change the
|
||||
|
||||
<para><command>nix-env</command> operations such as upgrades
|
||||
(<option>-u</option>) and uninstall (<option>-e</option>) never
|
||||
actually delete components from the system. All they do (as shown
|
||||
actually delete packages from the system. All they do (as shown
|
||||
above) is to create a new user environment that no longer contains
|
||||
symlinks to the “deleted” components.</para>
|
||||
symlinks to the “deleted” packages.</para>
|
||||
|
||||
<para>Of course, since disk space is not infinite, unused components
|
||||
<para>Of course, since disk space is not infinite, unused packages
|
||||
should be removed at some point. You can do this by running the Nix
|
||||
garbage collector. It will remove from the Nix store any component
|
||||
garbage collector. It will remove from the Nix store any package
|
||||
not used (directly or indirectly) by any generation of any
|
||||
profile.</para>
|
||||
|
||||
<para>Note however that as long as old generations reference a
|
||||
component, it will not be deleted. After all, we wouldn’t be able to
|
||||
package, it will not be deleted. After all, we wouldn’t be able to
|
||||
do a rollback otherwise. So in order for garbage collection to be
|
||||
effective, you should also delete (some) old generations. Of course,
|
||||
this should only be done if you are certain that you will not need to
|
||||
@@ -458,7 +458,7 @@ URL.</para>
|
||||
<command>nix-channel --add</command>, e.g.,
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable</screen>
|
||||
$ nix-channel --add http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
|
||||
|
||||
subscribes you to a channel that always contains that latest version
|
||||
of the Nix Packages collection. (Instead of
|
||||
@@ -486,7 +486,7 @@ makes the union of each channel’s Nix expressions the default for
|
||||
<screen>
|
||||
$ nix-env -u '*'</screen>
|
||||
|
||||
to upgrade all components in your profile to the latest versions
|
||||
to upgrade all packages in your profile to the latest versions
|
||||
available in the subscribed channels.</para>
|
||||
|
||||
</section>
|
||||
@@ -496,31 +496,27 @@ available in the subscribed channels.</para>
|
||||
|
||||
<para>Often, when you want to install a specific package (e.g., from
|
||||
the <link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/nixpkgs-unstable-latest/">Nix
|
||||
Packages collection</link> or from our <link
|
||||
xlink:href='http://nix.cs.uu.nl/dist/'>release server</link>),
|
||||
subscribing to a channel is a bit cumbersome. And channels don’t help
|
||||
you at all if you want to install an older version of a package than
|
||||
the one provided by the current contents of the channel, or a package
|
||||
that has been removed from the channel. That’s when
|
||||
<emphasis>one-click installs</emphasis> come in handy: you can just go
|
||||
to the web page that contains the package, click on it, and it will be
|
||||
installed with all the necessary dependencies.</para>
|
||||
xlink:href="http://nixos.org/nixpkgs/">Nix
|
||||
Packages collection</link>), subscribing to a channel is a bit
|
||||
cumbersome. And channels don’t help you at all if you want to install
|
||||
an older version of a package than the one provided by the current
|
||||
contents of the channel, or a package that has been removed from the
|
||||
channel. That’s when <emphasis>one-click installs</emphasis> come in
|
||||
handy: you can just go to the web page that contains the package,
|
||||
click on it, and it will be installed with all the necessary
|
||||
dependencies.</para>
|
||||
|
||||
<para>For instance, you can go to <link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/nixpkgs-unstable-latest/" />
|
||||
— or to any older release of Nix Packages — and click on any link for
|
||||
the individual packages for your platform (say, <link
|
||||
xlink:href='http://nix.cs.uu.nl/dist/nix/nixpkgs-0.10pre6622/pkgs/subversion-1.4.0-i686-linux.nixpkg'><literal>subversion-1.4.0</literal>
|
||||
for <literal>i686-linux</literal></link>). The first time you do
|
||||
this, your browser will ask what to do with
|
||||
<literal>application/nix-package</literal> files. You should open
|
||||
them with <filename>/nix/bin/nix-install-package</filename>. This
|
||||
will open a window that asks you to confirm that you want to install
|
||||
the package. When you answer <literal>Y</literal>, the package and
|
||||
all its dependencies will be installed. This is a binary deployment
|
||||
mechanism — you get packages pre-compiled for the selected platform
|
||||
type.</para>
|
||||
xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest"
|
||||
/> and click on any link for the individual packages for your
|
||||
platform. The first time you do this, your browser will ask what to
|
||||
do with <literal>application/nix-package</literal> files. You should
|
||||
open them with <filename>/nix/bin/nix-install-package</filename>.
|
||||
This will open a window that asks you to confirm that you want to
|
||||
install the package. When you answer <literal>Y</literal>, the
|
||||
package and all its dependencies will be installed. This is a binary
|
||||
deployment mechanism — you get packages pre-compiled for the selected
|
||||
platform type.</para>
|
||||
|
||||
<para>You can also install <literal>application/nix-package</literal>
|
||||
files from the command line directly. See <xref
|
||||
@@ -529,4 +525,82 @@ linkend='sec-nix-install-package' /> for details.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section xml:id="sec-sharing-packages"><title>Sharing packages between machines</title>
|
||||
|
||||
<para>Sometimes you want to copy a package from one machine to
|
||||
another. Or, you want to install some packages and you know that
|
||||
another machine already has some or all of those packages or their
|
||||
dependencies. In that case there are mechanisms to quickly copy
|
||||
packages between machines.</para>
|
||||
|
||||
<para>The command <command
|
||||
linkend="sec-nix-copy-closure">nix-copy-closure</command> copies a Nix
|
||||
store path along with all its dependencies to or from another machine
|
||||
via the SSH protocol. It doesn’t copy store paths that are already
|
||||
present on the target machine. For example, the following command
|
||||
copies Firefox with all its dependencies:
|
||||
|
||||
<screen>
|
||||
$ nix-copy-closure --to alice@itchy.example.org $(type -p firefox)</screen>
|
||||
|
||||
See <xref linkend='sec-nix-copy-closure' /> for details.</para>
|
||||
|
||||
<para>With <command linkend='refsec-nix-store-export'>nix-store
|
||||
--export</command> and <command
|
||||
linkend='refsec-nix-store-import'>nix-store --import</command> you can
|
||||
write the closure of a store path (that is, the path and all its
|
||||
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>
|
||||
|
||||
writes the closure of Firefox to a file. You can then copy this file
|
||||
to another machine and install the closure:
|
||||
|
||||
<screen>
|
||||
$ nix-store --import < firefox.closure</screen>
|
||||
|
||||
Any store paths in the closure that are already present in the target
|
||||
store are ignored. It is also possible to pipe the export into
|
||||
another command, e.g. to copy and install a closure directly to/on
|
||||
another machine:
|
||||
|
||||
<screen>
|
||||
$ nix-store --export $(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
|
||||
efficient in this example because it only copies paths that are not
|
||||
already present in the target Nix store.</para>
|
||||
|
||||
<para>Finally, if you can mount the Nix store of a remote machine in
|
||||
your local filesystem, Nix can copy paths from the remote Nix store to
|
||||
the local Nix store <emphasis>on demand</emphasis>. For instance,
|
||||
suppose that you mount a remote machine containing a Nix store via
|
||||
<command
|
||||
xlink:href="http://fuse.sourceforge.net/sshfs.html">sshfs</command>:
|
||||
|
||||
<screen>
|
||||
$ sshfs alice@itchy.example.org:/ /mnt</screen>
|
||||
|
||||
You should then set the <envar>NIX_OTHER_STORES</envar> environment
|
||||
variable to tell Nix about this remote Nix store:
|
||||
|
||||
<screen>
|
||||
$ export NIX_OTHER_STORES=/mnt/nix</screen>
|
||||
|
||||
Then if you do any Nix operation, e.g.
|
||||
|
||||
<screen>
|
||||
$ 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>
|
||||
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="chap-quick-start">
|
||||
|
||||
<title>Quick Start</title>
|
||||
|
||||
@@ -10,9 +11,9 @@ to the following chapters.</para>
|
||||
|
||||
<orderedlist>
|
||||
|
||||
<listitem><para>Download a source tarball or RPM from <link
|
||||
xlink:href='http://www.cs.uu.nl/groups/ST/Trace/Nix'/>. Build source
|
||||
distributions using the regular sequence:
|
||||
<listitem><para>Download a source tarball, RPM or Deb from <link
|
||||
xlink:href='http://nixos.org/'/>. Build source distributions using
|
||||
the regular sequence:
|
||||
|
||||
<screen>
|
||||
$ tar xvfj nix-<replaceable>version</replaceable>.tar.bz2
|
||||
@@ -20,19 +21,28 @@ $ ./configure
|
||||
$ make
|
||||
$ make install <lineannotation>(as root)</lineannotation></screen>
|
||||
|
||||
This will install Nix in <filename>/nix</filename>. You shouldn't
|
||||
change the prefix if at all possible since that will make it
|
||||
impossible to use our pre-built components. Alternatively, you could
|
||||
grab an RPM if you're on an RPM-based system. You should also add
|
||||
<filename>/nix/etc/profile.d/nix.sh</filename> to your
|
||||
<filename>~/.bashrc</filename> (or some other login
|
||||
This will install the Nix binaries in <filename>/usr/local</filename>
|
||||
and keep the Nix store and other state in <filename>/nix</filename>.
|
||||
You can change the former by specifying
|
||||
<option>--prefix=<replaceable>path</replaceable></option>. The
|
||||
location of the store can be changed using
|
||||
<option>--with-store-dir=<replaceable>path</replaceable></option>.
|
||||
However, you shouldn't change the store location, if at all possible,
|
||||
since that will make it impossible to use pre-built binaries from the
|
||||
Nixpkgs channel and other channels. The location of the state can be
|
||||
changed using
|
||||
<option>--localstatedir=<replaceable>path</replaceable>.</option></para></listitem>
|
||||
|
||||
<listitem><para>You should add
|
||||
<filename><replaceable>prefix</replaceable>/etc/profile.d/nix.sh</filename>
|
||||
to your <filename>~/.bashrc</filename> (or some other login
|
||||
file).</para></listitem>
|
||||
|
||||
<listitem><para>Subscribe to the Nix Packages channel.
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add \
|
||||
http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable</screen>
|
||||
http://nixos.org/releases/nixpkgs/channels/nixpkgs-unstable</screen>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
@@ -40,14 +50,14 @@ $ nix-channel --add \
|
||||
<screen>
|
||||
$ nix-channel --update</screen>
|
||||
|
||||
Note that this in itself doesn't download any components, it just
|
||||
Note that this in itself doesn't download any packages, it just
|
||||
downloads the Nix expressions that build them and stores them
|
||||
somewhere (under <filename>~/.nix-defexpr</filename>, in case you're
|
||||
curious). Also, it registers the fact that pre-built binaries are
|
||||
available remotely.</para></listitem>
|
||||
|
||||
<listitem><para>See what installable components are currently
|
||||
available in the channel:
|
||||
<listitem><para>See what installable packages are currently available
|
||||
in the channel:
|
||||
|
||||
<screen>
|
||||
$ nix-env -qa ’*’ <lineannotation>(mind the quotes!)</lineannotation>
|
||||
@@ -59,13 +69,13 @@ libxslt-1.1.0
|
||||
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>Install some components from the channel:
|
||||
<listitem><para>Install some packages from the channel:
|
||||
|
||||
<screen>
|
||||
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
|
||||
|
||||
This should download the pre-built components; it should not build
|
||||
them locally (if it does, something went wrong).</para></listitem>
|
||||
This should download pre-built packages; it should not build them
|
||||
locally (if it does, something went wrong).</para></listitem>
|
||||
|
||||
<listitem><para>Test that they work:
|
||||
|
||||
@@ -92,13 +102,13 @@ $ nix-env -e hello</screen>
|
||||
$ nix-channel --update
|
||||
$ nix-env -u '*'</screen>
|
||||
|
||||
The latter command will upgrade each installed component for which
|
||||
there is a “newer” version (as determined by comparing the version
|
||||
The latter command will upgrade each installed package for which there
|
||||
is a “newer” version (as determined by comparing the version
|
||||
numbers).</para></listitem>
|
||||
|
||||
<listitem><para>You can also install specific packages directly from
|
||||
your web browser. For instance, you can go to <link
|
||||
xlink:href="http://nix.cs.uu.nl/dist/nix/nixpkgs-unstable-latest/" />
|
||||
xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest" />
|
||||
and click on any link for the individual packages for your platform.
|
||||
Associate <literal>application/nix-package</literal> with the program
|
||||
<filename>/nix/bin/nix-install-package</filename>. A window should
|
||||
@@ -107,7 +117,7 @@ appear asking you whether it’s okay to install the package. Say
|
||||
installed.</para></listitem>
|
||||
|
||||
<listitem><para>If you're unhappy with the result of a
|
||||
<command>nix-env</command> action (e.g., an upgraded component turned
|
||||
<command>nix-env</command> action (e.g., an upgraded package turned
|
||||
out not to work properly), you can go back:
|
||||
|
||||
<screen>
|
||||
@@ -124,7 +134,7 @@ $ nix-collect-garbage -d</screen>
|
||||
|
||||
<!--
|
||||
The first command deletes old “generations” of your profile (making
|
||||
rollbacks impossible, but also making the components in those old
|
||||
rollbacks impossible, but also making the packages in those old
|
||||
generations available for garbage collection), while the second
|
||||
command actually deletes them.-->
|
||||
|
||||
|
||||
@@ -8,115 +8,593 @@
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.11"><title>Release 0.11 (TBA)</title>
|
||||
<section xml:id="ssec-relnotes-0.15"><title>Release 0.15 (March 17, 2010)</title>
|
||||
|
||||
<para>This is a bug-fix release. Among other things, it fixes
|
||||
building on Mac OS X (Snow Leopard), and improves the contents of
|
||||
<filename>/etc/passwd</filename> and <filename>/etc/group</filename>
|
||||
in <literal>chroot</literal> builds.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.14"><title>Release 0.14 (February 4, 2010)</title>
|
||||
|
||||
<para>This release has the following improvements:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>The garbage collector now starts deleting garbage much
|
||||
faster than before. It no longer determines liveness of all paths
|
||||
in the store, but does so on demand.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Added a new operation, <command>nix-store --query
|
||||
--roots</command>, that shows the garbage collector roots that
|
||||
directly or indirectly point to the given store paths.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Removed support for converting Berkeley DB-based Nix
|
||||
databases to the new schema.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Removed the <option>--use-atime</option> and
|
||||
<option>--max-atime</option> garbage collector options. They were
|
||||
not very useful in practice.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>On Windows, Nix now requires Cygwin 1.7.x.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A few bug fixes.</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.13"><title>Release 0.13 (November 5,
|
||||
2009)</title>
|
||||
|
||||
<para>This is primarily a bug fix release. It has some new
|
||||
features:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>Syntactic sugar for writing nested attribute sets. Instead of
|
||||
|
||||
<programlisting>
|
||||
{
|
||||
foo = {
|
||||
bar = 123;
|
||||
xyzzy = true;
|
||||
};
|
||||
a = { b = { c = "d"; }; };
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
you can write
|
||||
|
||||
<programlisting>
|
||||
{
|
||||
foo.bar = 123;
|
||||
foo.xyzzy = true;
|
||||
a.b.c = "d";
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
This is useful, for instance, in NixOS configuration files.</para>
|
||||
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Support for Nix channels generated by Hydra, the Nix-based
|
||||
continuous build system. (Hydra generates NAR archives on the
|
||||
fly, so the size and hash of these archives isn’t known in
|
||||
advance.)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Support <literal>i686-linux</literal> builds directly on
|
||||
<literal>x86_64-linux</literal> Nix installations. This is
|
||||
implemented using the <function>personality()</function> syscall,
|
||||
which causes <command>uname</command> to return
|
||||
<literal>i686</literal> in child processes.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Various improvements to the <literal>chroot</literal>
|
||||
support. Building in a <literal>chroot</literal> works quite well
|
||||
now.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Nix no longer blocks if it tries to build a path and another
|
||||
process is already building the same path. Instead it tries to
|
||||
build another buildable path first. This improves
|
||||
parallelism.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Support for large (> 4 GiB) files in NAR archives.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Various (performance) improvements to the remote build
|
||||
mechanism.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>New primops: <varname>builtins.addErrorContext</varname> (to
|
||||
add a string to stack traces — useful for debugging),
|
||||
<varname>builtins.isBool</varname>,
|
||||
<varname>builtins.isString</varname>,
|
||||
<varname>builtins.isInt</varname>,
|
||||
<varname>builtins.intersectAttrs</varname>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>OpenSolaris support (Sander van der Burg).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Stack traces are no longer displayed unless the
|
||||
<option>--show-trace</option> option is used.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The scoping rules for <literal>inherit
|
||||
(<replaceable>e</replaceable>) ...</literal> in recursive
|
||||
attribute sets have changed. The expression
|
||||
<replaceable>e</replaceable> can now refer to the attributes
|
||||
defined in the containing set.</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.12"><title>Release 0.12 (November 20,
|
||||
2008)</title>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>Nix no longer uses Berkeley DB to store Nix store metadata.
|
||||
The principal advantages of the new storage scheme are: it works
|
||||
properly over decent implementations of NFS (allowing Nix stores
|
||||
to be shared between multiple machines); no recovery is needed
|
||||
when a Nix process crashes; no write access is needed for
|
||||
read-only operations; no more running out of Berkeley DB locks on
|
||||
certain operations.</para>
|
||||
|
||||
<para>You still need to compile Nix with Berkeley DB support if
|
||||
you want Nix to automatically convert your old Nix store to the
|
||||
new schema. If you don’t need this, you can build Nix with the
|
||||
<filename>configure</filename> option
|
||||
<option>--disable-old-db-compat</option>.</para>
|
||||
|
||||
<para>After the automatic conversion to the new schema, you can
|
||||
delete the old Berkeley DB files:
|
||||
|
||||
<screen>
|
||||
$ cd /nix/var/nix/db
|
||||
$ rm __db* log.* derivers references referrers reserved validpaths DB_CONFIG</screen>
|
||||
|
||||
The new metadata is stored in the directories
|
||||
<filename>/nix/var/nix/db/info</filename> and
|
||||
<filename>/nix/var/nix/db/referrer</filename>. Though the
|
||||
metadata is stored in human-readable plain-text files, they are
|
||||
not intended to be human-editable, as Nix is rather strict about
|
||||
the format.</para>
|
||||
|
||||
<para>The new storage schema may or may not require less disk
|
||||
space than the Berkeley DB environment, mostly depending on the
|
||||
cluster size of your file system. With 1 KiB clusters (which
|
||||
seems to be the <literal>ext3</literal> default nowadays) it
|
||||
usually takes up much less space.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem><para>There is a new substituter that copies paths
|
||||
directly from other (remote) Nix stores mounted somewhere in the
|
||||
filesystem. For instance, you can speed up an installation by
|
||||
mounting some remote Nix store that already has the packages in
|
||||
question via NFS or <literal>sshfs</literal>. The environment
|
||||
variable <envar>NIX_OTHER_STORES</envar> specifies the locations of
|
||||
the remote Nix directories,
|
||||
e.g. <literal>/mnt/remote-fs/nix</literal>.</para></listitem>
|
||||
|
||||
<listitem><para>New <command>nix-store</command> operations
|
||||
<option>--dump-db</option> and <option>--load-db</option> to dump
|
||||
and reload the Nix database.</para></listitem>
|
||||
|
||||
<listitem><para>The garbage collector has a number of new options to
|
||||
allow only some of the garbage to be deleted. The option
|
||||
<option>--max-freed <replaceable>N</replaceable></option> tells the
|
||||
collector to stop after at least <replaceable>N</replaceable> bytes
|
||||
have been deleted. The option <option>--max-links
|
||||
<replaceable>N</replaceable></option> tells it to stop after the
|
||||
link count on <filename>/nix/store</filename> has dropped below
|
||||
<replaceable>N</replaceable>. This is useful for very large Nix
|
||||
stores on filesystems with a 32000 subdirectories limit (like
|
||||
<literal>ext3</literal>). The option <option>--use-atime</option>
|
||||
causes store paths to be deleted in order of ascending last access
|
||||
time. This allows non-recently used stuff to be deleted. The
|
||||
option <option>--max-atime <replaceable>time</replaceable></option>
|
||||
specifies an upper limit to the last accessed time of paths that may
|
||||
be deleted. For instance,
|
||||
|
||||
<screen>
|
||||
$ nix-store --gc -v --max-atime $(date +%s -d "2 months ago")</screen>
|
||||
|
||||
deletes everything that hasn’t been accessed in two months.</para></listitem>
|
||||
|
||||
<listitem><para><command>nix-env</command> now uses optimistic
|
||||
profile locking when performing an operation like installing or
|
||||
upgrading, instead of setting an exclusive lock on the profile.
|
||||
This allows multiple <command>nix-env -i / -u / -e</command>
|
||||
operations on the same profile in parallel. If a
|
||||
<command>nix-env</command> operation sees at the end that the profile
|
||||
was changed in the meantime by another process, it will just
|
||||
restart. This is generally cheap because the build results are
|
||||
still in the Nix store.</para></listitem>
|
||||
|
||||
<listitem><para>The option <option>--dry-run</option> is now
|
||||
supported by <command>nix-store -r</command> and
|
||||
<command>nix-build</command>.</para></listitem>
|
||||
|
||||
<listitem><para>The information previously shown by
|
||||
<option>--dry-run</option> (i.e., which derivations will be built
|
||||
and which paths will be substituted) is now always shown by
|
||||
<command>nix-env</command>, <command>nix-store -r</command> and
|
||||
<command>nix-build</command>. The total download size of
|
||||
substitutable paths is now also shown. For instance, a build will
|
||||
show something like
|
||||
|
||||
<screen>
|
||||
the following derivations will be built:
|
||||
/nix/store/129sbxnk5n466zg6r1qmq1xjv9zymyy7-activate-configuration.sh.drv
|
||||
/nix/store/7mzy971rdm8l566ch8hgxaf89x7lr7ik-upstart-jobs.drv
|
||||
...
|
||||
the following paths will be downloaded/copied (30.02 MiB):
|
||||
/nix/store/4m8pvgy2dcjgppf5b4cj5l6wyshjhalj-samba-3.2.4
|
||||
/nix/store/7h1kwcj29ip8vk26rhmx6bfjraxp0g4l-libunwind-0.98.6
|
||||
...</screen>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>Language features:
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para>@-patterns as in Haskell. For instance, in a
|
||||
function definition
|
||||
|
||||
<programlisting>f = args @ {x, y, z}: <replaceable>...</replaceable>;</programlisting>
|
||||
|
||||
<varname>args</varname> refers to the argument as a whole, which
|
||||
is further pattern-matched against the attribute set pattern
|
||||
<literal>{x, y, z}</literal>.</para></listitem>
|
||||
|
||||
<listitem><para>“<literal>...</literal>” (ellipsis) patterns.
|
||||
An attribute set pattern can now say <literal>...</literal> at
|
||||
the end of the attribute name list to specify that the function
|
||||
takes <emphasis>at least</emphasis> the listed attributes, while
|
||||
ignoring additional attributes. For instance,
|
||||
|
||||
<programlisting>{stdenv, fetchurl, fuse, ...}: <replaceable>...</replaceable></programlisting>
|
||||
|
||||
defines a function that accepts any attribute set that includes
|
||||
at least the three listed attributes.</para></listitem>
|
||||
|
||||
<listitem><para>New primops:
|
||||
<varname>builtins.parseDrvName</varname> (split a package name
|
||||
string like <literal>"nix-0.12pre12876"</literal> into its name
|
||||
and version components, e.g. <literal>"nix"</literal> and
|
||||
<literal>"0.12pre12876"</literal>),
|
||||
<varname>builtins.compareVersions</varname> (compare two version
|
||||
strings using the same algorithm that <command>nix-env</command>
|
||||
uses), <varname>builtins.length</varname> (efficiently compute
|
||||
the length of a list), <varname>builtins.mul</varname> (integer
|
||||
multiplication), <varname>builtins.div</varname> (integer
|
||||
division).
|
||||
<!-- <varname>builtins.genericClosure</varname> -->
|
||||
</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para><command>nix-prefetch-url</command> now supports
|
||||
<literal>mirror://</literal> URLs, provided that the environment
|
||||
variable <envar>NIXPKGS_ALL</envar> points at a Nixpkgs
|
||||
tree.</para></listitem>
|
||||
|
||||
<listitem><para>Removed the commands
|
||||
<command>nix-pack-closure</command> and
|
||||
<command>nix-unpack-closure</command>. You can do almost the same
|
||||
thing but much more efficiently by doing <literal>nix-store --export
|
||||
$(nix-store -qR <replaceable>paths</replaceable>) > closure</literal> and
|
||||
<literal>nix-store --import <
|
||||
closure</literal>.</para></listitem>
|
||||
|
||||
<listitem><para>Lots of bug fixes, including a big performance bug in
|
||||
the handling of <literal>with</literal>-expressions.</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.11"><title>Release 0.11 (December 31,
|
||||
2007)</title>
|
||||
|
||||
<para>Nix 0.11 has many improvements over the previous stable release.
|
||||
The most important improvement is secure multi-user support. It also
|
||||
features many usability enhancements and language extensions, many of
|
||||
them prompted by NixOS, the purely functional Linux distribution based
|
||||
on Nix. Here is an (incomplete) list:</para>
|
||||
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
|
||||
<listitem><para>TODO: multi-user support. The old setuid method for
|
||||
sharing a store between multiple users has been
|
||||
removed.</para></listitem>
|
||||
<listitem><para>Secure multi-user support. A single Nix store can
|
||||
now be shared between multiple (possible untrusted) users. This is
|
||||
an important feature for NixOS, where it allows non-root users to
|
||||
install software. The old setuid method for sharing a store between
|
||||
multiple users has been removed. Details for setting up a
|
||||
multi-user store can be found in the manual.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>The new command <command>nix-copy-closure</command>
|
||||
gives you an easy and efficient way to exchange software between
|
||||
machines. It copies the missing parts of the closure of a set of
|
||||
store path to or from a remote machine.</para></listitem>
|
||||
store path to or from a remote machine via
|
||||
<command>ssh</command>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-prefetch-url</command> now by default
|
||||
computes the SHA-256 hash of the file instead of the MD5 hash. In
|
||||
calls to <function>fetchurl</function> you should pass an
|
||||
<literal>sha256</literal> attribute instead of
|
||||
<literal>md5</literal>. You can pass either a hexadecimal or a
|
||||
base-32 encoding of the hash.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-store</command> has a new operation
|
||||
<option>--read-log</option> (<option>-l</option>)
|
||||
<parameter>paths</parameter> that shows the build log of the given
|
||||
paths.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <varname>allowedReferences</varname> for
|
||||
checking the set of references in the output of a
|
||||
derivation.</para></listitem>
|
||||
<listitem><para>A new kind of string literal: strings between double
|
||||
single-quotes (<literal>''</literal>) have indentation
|
||||
“intelligently” removed. This allows large strings (such as shell
|
||||
scripts or configuration file fragments in NixOS) to cleanly follow
|
||||
the indentation of the surrounding expression. It also requires
|
||||
much less escaping, since <literal>''</literal> is less common in
|
||||
most languages than <literal>"</literal>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: semantic cleanups of string concatenation
|
||||
etc. (mostly in r6740).</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: now using Berkeley DB 4.5.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: option <option>--reregister</option> in
|
||||
<command>nix-store --register-validity</command>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: magic <varname>exportReferencesGraph</varname>
|
||||
attribute.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: option <option>--max-silent-time</option>,
|
||||
configuration setting
|
||||
<literal>build-max-silent-time</literal>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <command>nix-env</command>
|
||||
<option>--set</option>.</para></listitem>
|
||||
<listitem><para><command>nix-env</command> <option>--set</option>
|
||||
modifies the current generation of a profile so that it contains
|
||||
exactly the specified derivation, and nothing else. For example,
|
||||
<literal>nix-env -p /nix/var/nix/profiles/browser --set
|
||||
firefox</literal> lets the profile named
|
||||
<filename>browser</filename> contain just Firefox.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <option>--argstr</option>.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <command>nix-env</command> now maintains meta
|
||||
info about installed packages in user environments. <option>-q
|
||||
--xml --meta</option> to show all meta info.</para></listitem>
|
||||
<listitem><para><command>nix-env</command> now maintains
|
||||
meta-information about installed packages in profiles. The
|
||||
meta-information is the contents of the <varname>meta</varname>
|
||||
attribute of derivations, such as <varname>description</varname> or
|
||||
<varname>homepage</varname>. The command <literal>nix-env -q --xml
|
||||
--meta</literal> shows all meta-information.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <command>nix-env</command>
|
||||
<option>--set-flag</option>. Specific flags:
|
||||
<literal>active</literal>, <literal>priority</literal>,
|
||||
<literal>keep</literal>.</para></listitem>
|
||||
<listitem><para><command>nix-env</command> now uses the
|
||||
<varname>meta.priority</varname> attribute of derivations to resolve
|
||||
filename collisions between packages. Lower priority values denote
|
||||
a higher priority. For instance, the GCC wrapper package and the
|
||||
Binutils package in Nixpkgs both have a file
|
||||
<filename>bin/ld</filename>, so previously if you tried to install
|
||||
both you would get a collision. Now, on the other hand, the GCC
|
||||
wrapper declares a higher priority than Binutils, so the former’s
|
||||
<filename>bin/ld</filename> is symlinked in the user
|
||||
environment.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-env -i / -u</command>: instead of
|
||||
breaking package ties by version, break them by priority and version
|
||||
number. That is, if there are multiple packages with the same name,
|
||||
then pick the package with the highest priority, and only use the
|
||||
version if there are multiple packages with the same
|
||||
priority.</para>
|
||||
|
||||
<para>This makes it possible to mark specific versions/variant in
|
||||
Nixpkgs more or less desirable than others. A typical example would
|
||||
be a beta version of some package (e.g.,
|
||||
<literal>gcc-4.2.0rc1</literal>) which should not be installed even
|
||||
though it is the highest version, except when it is explicitly
|
||||
selected (e.g., <literal>nix-env -i
|
||||
gcc-4.2.0rc1</literal>).</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-env --set-flag</command> allows meta
|
||||
attributes of installed packages to be modified. There are several
|
||||
attributes that can be usefully modified, because they affect the
|
||||
behaviour of <command>nix-env</command> or the user environment
|
||||
build script:
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para><varname>meta.priority</varname> can be changed
|
||||
to resolve filename clashes (see above).</para></listitem>
|
||||
|
||||
<listitem><para><varname>meta.keep</varname> can be set to
|
||||
<literal>true</literal> to prevent the package from being
|
||||
upgraded or replaced. Useful if you want to hang on to an older
|
||||
version of a package.</para></listitem>
|
||||
|
||||
<listitem><para><varname>meta.active</varname> can be set to
|
||||
<literal>false</literal> to “disable” the package. That is, no
|
||||
symlinks will be generated to the files of the package, but it
|
||||
remains part of the profile (so it won’t be garbage-collected).
|
||||
Set it back to <literal>true</literal> to re-enable the
|
||||
package.</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: <command>nix-env</command> <option>-i</option>
|
||||
/ <option>-u</option> take package priorities into
|
||||
account.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-env -q</command> now has a flag
|
||||
<option>--prebuilt-only</option> (<option>-b</option>) that causes
|
||||
<command>nix-env</command> to show only those derivations whose
|
||||
output is already in the Nix store or that can be substituted (i.e.,
|
||||
downloaded from somewhere). In other words, it shows the packages
|
||||
that can be installed “quickly”, i.e., don’t need to be built from
|
||||
source.</para></listitem>
|
||||
source. The <option>-b</option> flag is also available in
|
||||
<command>nix-env -i</command> and <command>nix-env -u</command> to
|
||||
filter out derivations for which no pre-built binary is
|
||||
available.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: new built-ins
|
||||
<function>builtins.attrNames</function>,
|
||||
<function>builtins.filterSource</function>,
|
||||
<function>builtins.sub</function>,
|
||||
<function>builtins.stringLength</function>,
|
||||
<function>builtins.substring</function>.</para></listitem>
|
||||
<listitem><para>The new option <option>--argstr</option> (in
|
||||
<command>nix-env</command>, <command>nix-instantiate</command> and
|
||||
<command>nix-build</command>) is like <option>--arg</option>, except
|
||||
that the value is a string. For example, <literal>--argstr system
|
||||
i686-linux</literal> is equivalent to <literal>--arg system
|
||||
\"i686-linux\"</literal> (note that <option>--argstr</option>
|
||||
prevents annoying quoting around shell arguments).</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>TODO: each subscribed channel is its own attribute
|
||||
in the top-level expression generated for the channel, this allows
|
||||
disambiguation (<command>nix-env -qaA</command>).</para></listitem>
|
||||
<listitem><para><command>nix-store</command> has a new operation
|
||||
<option>--read-log</option> (<option>-l</option>)
|
||||
<parameter>paths</parameter> that shows the build log of the given
|
||||
paths.</para></listitem>
|
||||
|
||||
|
||||
<!--
|
||||
<listitem><para>TODO: semantic cleanups of string concatenation
|
||||
etc. (mostly in r6740).</para></listitem>
|
||||
-->
|
||||
|
||||
|
||||
<listitem><para>TODO: substitutes table is gone, registering
|
||||
substitutes is now much faster.</para></listitem>
|
||||
<listitem><para>Nix now uses Berkeley DB 4.5. The database is
|
||||
upgraded automatically, but you should be careful not to use old
|
||||
versions of Nix that still use Berkeley DB 4.4.</para></listitem>
|
||||
|
||||
|
||||
<!-- foo
|
||||
<listitem><para>TODO: option <option>- -reregister</option> in
|
||||
<command>nix-store - -register-validity</command>.</para></listitem>
|
||||
-->
|
||||
|
||||
|
||||
<listitem><para>The option <option>--max-silent-time</option>
|
||||
(corresponding to the configuration setting
|
||||
<literal>build-max-silent-time</literal>) allows you to set a
|
||||
timeout on builds — if a build produces no output on
|
||||
<literal>stdout</literal> or <literal>stderr</literal> for the given
|
||||
number of seconds, it is terminated. This is useful for recovering
|
||||
automatically from builds that are stuck in an infinite
|
||||
loop.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-channel</command>: each subscribed
|
||||
channel is its own attribute in the top-level expression generated
|
||||
for the channel. This allows disambiguation (e.g. <literal>nix-env
|
||||
-i -A nixpkgs_unstable.firefox</literal>).</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>The substitutes table has been removed from the
|
||||
database. This makes operations such as <command>nix-pull</command>
|
||||
and <command>nix-channel --update</command> much, much
|
||||
faster.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-pull</command> now supports
|
||||
bzip2-compressed manifests. This speeds up
|
||||
channels.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-prefetch-url</command> now has a
|
||||
limited form of caching. This is used by
|
||||
<command>nix-channel</command> to prevent unnecessary downloads when
|
||||
the channel hasn’t changed.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-prefetch-url</command> now by default
|
||||
computes the SHA-256 hash of the file instead of the MD5 hash. In
|
||||
calls to <function>fetchurl</function> you should pass the
|
||||
<literal>sha256</literal> attribute instead of
|
||||
<literal>md5</literal>. You can pass either a hexadecimal or a
|
||||
base-32 encoding of the hash.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Nix can now perform builds in an automatically
|
||||
generated “chroot”. This prevents a builder from accessing stuff
|
||||
outside of the Nix store, and thus helps ensure purity. This is an
|
||||
experimental feature.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>The new command <command>nix-store
|
||||
--optimise</command> reduces Nix store disk space usage by finding
|
||||
identical files in the store and hard-linking them to each other.
|
||||
It typically reduces the size of the store by something like
|
||||
25-35%.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><filename>~/.nix-defexpr</filename> can now be a
|
||||
directory, in which case the Nix expressions in that directory are
|
||||
combined into an attribute set, with the file names used as the
|
||||
names of the attributes. The command <command>nix-env
|
||||
--import</command> (which set the
|
||||
<filename>~/.nix-defexpr</filename> symlink) is
|
||||
removed.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Derivations can specify the new special attribute
|
||||
<varname>allowedReferences</varname> to enforce that the references
|
||||
in the output of a derivation are a subset of a declared set of
|
||||
paths. For example, if <varname>allowedReferences</varname> is an
|
||||
empty list, then the output must not have any references. This is
|
||||
used in NixOS to check that generated files such as initial ramdisks
|
||||
for booting Linux don’t have any dependencies.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>The new attribute
|
||||
<varname>exportReferencesGraph</varname> allows builders access to
|
||||
the references graph of their inputs. This is used in NixOS for
|
||||
tasks such as generating ISO-9660 images that contain a Nix store
|
||||
populated with the closure of certain paths.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Fixed-output derivations (like
|
||||
<function>fetchurl</function>) can define the attribute
|
||||
<varname>impureEnvVars</varname> to allow external environment
|
||||
variables to be passed to builders. This is used in Nixpkgs to
|
||||
support proxy configuration, among other things.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para>Several new built-in functions:
|
||||
<function>builtins.attrNames</function>,
|
||||
<function>builtins.filterSource</function>,
|
||||
<function>builtins.isAttrs</function>,
|
||||
<function>builtins.isFunction</function>,
|
||||
<function>builtins.listToAttrs</function>,
|
||||
<function>builtins.stringLength</function>,
|
||||
<function>builtins.sub</function>,
|
||||
<function>builtins.substring</function>,
|
||||
<function>throw</function>,
|
||||
<function>builtins.trace</function>,
|
||||
<function>builtins.readFile</function>.</para></listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@ h3 /* subsections */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
|
||||
@@ -4,78 +4,9 @@
|
||||
<title>Troubleshooting</title>
|
||||
|
||||
|
||||
<para>This section provides solutions for some common problems.</para>
|
||||
|
||||
|
||||
<section><title>Berkeley DB: <quote>Cannot allocate memory</quote></title>
|
||||
|
||||
<para>Symptom: Nix operations (in particular the
|
||||
<command>nix-store</command> operations <option>--gc</option>,
|
||||
<option>--verify</option>, and <option>--clear-substitutes</option> —
|
||||
the latter being called by <command>nix-channel --update</command>)
|
||||
failing:
|
||||
|
||||
<screen>
|
||||
$ nix-store --verify
|
||||
error: Db::del: Cannot allocate memory</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Possible solution: make sure that no Nix processes are running,
|
||||
then do:
|
||||
|
||||
<screen>
|
||||
$ cd /nix/var/nix/db
|
||||
$ rm __db.00*</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Berkeley DB gives weird error messages</title>
|
||||
|
||||
<para>Symptom: you get error messages such as
|
||||
|
||||
<screen>
|
||||
Berkeley DB message: Finding last valid log LSN: file: 1 offset 28
|
||||
Berkeley DB error: file validpaths (meta pgno = 0) has LSN [483][34721].
|
||||
Berkeley DB error: end of log is [1][28]
|
||||
Berkeley DB error: /nix/var/nix/db/validpaths: unexpected file type or format</screen>
|
||||
|
||||
or other weird Berkeley DB errors, and they don’t go away (i.e.,
|
||||
automatic recovery doesn’t work). This may be the case after a system
|
||||
crash.</para>
|
||||
|
||||
<para>Solution: first try to run <command>db_recover</command> and
|
||||
then <link linkend='refsec-nix-store-verify'><command>nix-store
|
||||
--verify</command></link>:
|
||||
|
||||
<screen>
|
||||
$ db_recover -h /nix/var/nix/db
|
||||
$ nix-store --verify</screen>
|
||||
|
||||
(Make sure that you have the right version of
|
||||
<command>db_recover</command>, namely, Berkeley DB 4.4 for Nix 0.10,
|
||||
and 4.5 for Nix 0.11.)</para>
|
||||
|
||||
<para>If that doesn’t work, it’s time to bring out the big guns:
|
||||
|
||||
<screen>
|
||||
$ cd /nix/var/nix
|
||||
$ cp -pr db db-backup <lineannotation>(making a backup just in case)</lineannotation>
|
||||
$ cd db
|
||||
$ rm __db.* log* <lineannotation>(removing the Berkeley DB environment)</lineannotation>
|
||||
$ mkdir tmp
|
||||
$ for i in *; do db_dump $i | (cd tmp && db_load $i); done
|
||||
<lineannotation>(ignore error messages about non-database files like “reserved”)</lineannotation>
|
||||
$ mv tmp/* .
|
||||
$ nix-store --verify</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<para>This section provides solutions for some common problems. See
|
||||
the <link xlink:href="http://bugs.strategoxt.org/browse/NIX">Nix
|
||||
bug tracker</link> for a list of currently known issues.</para>
|
||||
|
||||
|
||||
<section><title>Collisions in <command>nix-env</command></title>
|
||||
@@ -145,7 +76,8 @@ Furthermore, the <literal>st_nlink</literal> field of the
|
||||
<para>This only happens on very large Nix installations (such as build
|
||||
machines).</para>
|
||||
|
||||
<para>Quick solution: run the garbage collector.</para>
|
||||
<para>Quick solution: run the garbage collector. You may want to use
|
||||
the <option>--max-links</option> option.</para>
|
||||
|
||||
<para>Real solution: put the Nix store on a file system that supports
|
||||
more than 32,000 subdirectories per directory, such as ReiserFS.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
82
externals/Makefile.am
vendored
82
externals/Makefile.am
vendored
@@ -1,78 +1,11 @@
|
||||
# Berkeley DB
|
||||
|
||||
DB = db-4.5.20
|
||||
|
||||
$(DB).tar.gz:
|
||||
@echo "Nix requires Berkeley DB to build."
|
||||
@echo "Please download version 4.5.20 from"
|
||||
@echo " http://download-east.oracle.com/berkeley-db/db-4.5.20.tar.gz"
|
||||
@echo "and place it in the externals/ directory."
|
||||
false
|
||||
|
||||
$(DB): $(DB).tar.gz
|
||||
gunzip < $(srcdir)/$(DB).tar.gz | tar xvf -
|
||||
(cd $(DB) && $(patch) -p1) < $(srcdir)/bdb-cygwin.patch
|
||||
|
||||
have-db:
|
||||
$(MAKE) $(DB)
|
||||
touch have-db
|
||||
|
||||
if HAVE_BDB
|
||||
build-db:
|
||||
else
|
||||
build-db: have-db
|
||||
(pfx=`pwd` && \
|
||||
cd $(DB)/build_unix && \
|
||||
CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" \
|
||||
../dist/configure --prefix=$$pfx/inst-bdb \
|
||||
--enable-cxx --disable-shared --disable-cryptography \
|
||||
--disable-replication --disable-verify && \
|
||||
$(MAKE) && \
|
||||
$(MAKE) install_include install_lib)
|
||||
touch build-db
|
||||
endif
|
||||
|
||||
|
||||
# CWI ATerm
|
||||
|
||||
ATERM = aterm-2.4.2-fixes-r2
|
||||
|
||||
$(ATERM).tar.bz2:
|
||||
@echo "Nix requires the CWI ATerm library to build."
|
||||
@echo "Please download version 2.4.2-fixes-r2 from"
|
||||
@echo " http://losser.st-lab.cs.uu.nl/~eelco/dist/aterm-2.4.2-fixes-r2.tar.bz2"
|
||||
@echo "and place it in the externals/ directory."
|
||||
false
|
||||
|
||||
$(ATERM): $(ATERM).tar.bz2
|
||||
bunzip2 < $(srcdir)/$(ATERM).tar.bz2 | tar xvf -
|
||||
|
||||
have-aterm:
|
||||
$(MAKE) $(ATERM)
|
||||
touch have-aterm
|
||||
|
||||
if HAVE_ATERM
|
||||
build-aterm:
|
||||
else
|
||||
build-aterm: have-aterm
|
||||
(pfx=`pwd` && \
|
||||
cd $(ATERM) && \
|
||||
CC="$(CC)" ./configure --prefix=$$pfx/inst-aterm \
|
||||
--disable-shared --enable-static && \
|
||||
$(MAKE) && \
|
||||
$(MAKE) install)
|
||||
touch build-aterm
|
||||
endif
|
||||
|
||||
|
||||
# bzip2
|
||||
|
||||
BZIP2 = bzip2-1.0.4
|
||||
BZIP2 = bzip2-1.0.5
|
||||
|
||||
$(BZIP2).tar.gz:
|
||||
@echo "Nix requires bzip2 to build."
|
||||
@echo "Please download version 1.0.4 from"
|
||||
@echo " http://www.bzip.org/1.0.4/bzip2-1.0.4.tar.gz"
|
||||
@echo "Please download version 1.0.5 from"
|
||||
@echo " http://www.bzip.org/1.0.5/bzip2-1.0.5.tar.gz"
|
||||
@echo "and place it in the externals/ directory."
|
||||
false
|
||||
|
||||
@@ -99,11 +32,10 @@ install:
|
||||
endif
|
||||
|
||||
|
||||
all: build-db build-aterm build-bzip2
|
||||
all: build-bzip2
|
||||
|
||||
EXTRA_DIST = $(DB).tar.gz $(ATERM).tar.bz2 $(BZIP2).tar.gz \
|
||||
bdb-cygwin.patch
|
||||
EXTRA_DIST = $(BZIP2).tar.gz
|
||||
|
||||
ext-clean:
|
||||
$(RM) -f have-db build-db have-aterm build-aterm
|
||||
$(RM) -rf $(DB) $(ATERM) $(BZIP2)
|
||||
$(RM) -f have-bzip2 build-bzip2
|
||||
$(RM) -rf $(BZIP2)
|
||||
|
||||
22
externals/bdb-cygwin.patch
vendored
22
externals/bdb-cygwin.patch
vendored
@@ -1,22 +0,0 @@
|
||||
diff -rc db-4.5.20-orig/os/os_flock.c db-4.5.20/os/os_flock.c
|
||||
*** db-4.5.20-orig/os/os_flock.c 2006-10-13 12:36:12.000000000 +0200
|
||||
--- db-4.5.20/os/os_flock.c 2006-10-13 12:40:11.000000000 +0200
|
||||
***************
|
||||
*** 30,35 ****
|
||||
--- 30,44 ----
|
||||
|
||||
DB_ASSERT(dbenv, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
+ #ifdef __CYGWIN__
|
||||
+ /*
|
||||
+ * Windows file locking interferes with read/write operations, so we
|
||||
+ * map the ranges to an area past the end of the file.
|
||||
+ */
|
||||
+ DB_ASSERT(dbenv, offset < (off_t) 1 << 62);
|
||||
+ offset += (off_t) 1 << 62;
|
||||
+ #endif
|
||||
+
|
||||
fl.l_start = offset;
|
||||
fl.l_len = 1;
|
||||
fl.l_type = acquire ? F_WRLCK : F_UNLCK;
|
||||
Only in db-4.5.20/os: os_flock.c~
|
||||
@@ -76,10 +76,10 @@ The hook `nix-mode-hook' is run when Nix mode is started.
|
||||
("\\<baseNameOf\\>" . font-lock-builtin-face)
|
||||
("\\<toString\\>" . font-lock-builtin-face)
|
||||
("\\<isNull\\>" . font-lock-builtin-face)
|
||||
("\\<\\([a-zA-Z_][a-zA-Z0-9_']*\\)[ \t]*="
|
||||
(1 font-lock-variable-name-face nil nil))
|
||||
("[a-zA-Z][a-zA-Z0-9\\+-\\.]*:[a-zA-Z0-9%/\\?:@&=\\+\\$,_\\.!~\\*'-]+"
|
||||
. font-lock-constant-face)
|
||||
("\\<\\([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)
|
||||
))
|
||||
|
||||
37
misc/vim/syntax/nix.vim
Normal file
37
misc/vim/syntax/nix.vim
Normal file
@@ -0,0 +1,37 @@
|
||||
" Vim syntax file
|
||||
" Language: nix
|
||||
" Maintainer: Marc Weber <marco-oweber@gmx.de>
|
||||
" Modify and commit if you feel that way
|
||||
" Last Change: 2007 Dec
|
||||
|
||||
" Quit when a (custom) syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
syn keyword nixKeyword let throw inherit import true false null with
|
||||
syn keyword nixConditional if else then
|
||||
syn keyword nixBrace ( ) { } =
|
||||
syn keyword nixBuiltin __currentSystem __currentTime __isFunction __getEnv __trace __toPath __pathExists
|
||||
\ __readFile __toXML __toFile __filterSource __attrNames __getAttr __hasAttr __isAttrs __listToAttrs __isList
|
||||
\ __head __tail __add __sub __lessThan __substring __stringLength
|
||||
|
||||
syn match nixAttr "\w\+\ze\s*="
|
||||
syn match nixFuncArg "\zs\w\+\ze\s*:"
|
||||
syn region nixStringParam start=+\${+ end=+}+
|
||||
syn region nixMultiLineComment start=+/\*+ skip=+\\"+ end=+\*/+
|
||||
syn match nixEndOfLineComment "#.*$"
|
||||
syn region nixStringIndented start=+''+ skip=+'''\|''${\|"+ end=+''+ contains=nixStringParam
|
||||
syn region nixString start=+"+ skip=+\\"+ end=+"+ contains=nixStringParam
|
||||
|
||||
hi def link nixKeyword Keyword
|
||||
hi def link nixConditional Conditional
|
||||
hi def link nixBrace Special
|
||||
hi def link nixString String
|
||||
hi def link nixStringIndented String
|
||||
hi def link nixBuiltin Special
|
||||
hi def link nixStringParam Macro
|
||||
hi def link nixMultiLineComment Comment
|
||||
hi def link nixEndOfLineComment Comment
|
||||
hi def link nixAttr Identifier
|
||||
hi def link nixFuncArg Identifier
|
||||
@@ -29,25 +29,6 @@
|
||||
#gc-keep-derivations = true
|
||||
|
||||
|
||||
### Option `gc-reserved-space'
|
||||
#
|
||||
# This option specifies how much space should be reserved in normal
|
||||
# use so that the garbage collector can run succesfully. Since the
|
||||
# garbage collector must perform Berkeley DB transactions, it needs
|
||||
# some disk space for itself. However, when the disk is full, this
|
||||
# space is not available, so the collector would not be able to run
|
||||
# precisely when it is most needed.
|
||||
#
|
||||
# For this reason, when Nix is run, it allocates a file
|
||||
# /nix/var/nix/db/reserved of the size specified by this option. When
|
||||
# the garbage collector is run, this file is deleted before the
|
||||
# Berkeley DB environment is opened. This should give it enough room
|
||||
# to proceed.
|
||||
#
|
||||
# The default is "1048576" (1 MiB).
|
||||
#gc-reserved-space = 1048576
|
||||
|
||||
|
||||
### Option `env-keep-derivations'
|
||||
#
|
||||
# If `false' (default), derivations are not stored in Nix user
|
||||
@@ -80,7 +61,7 @@
|
||||
|
||||
### Option `build-max-silent-time'
|
||||
#
|
||||
# This option defines the maximum number of seconds that builder can
|
||||
# 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
|
||||
@@ -135,21 +116,55 @@
|
||||
#build-users-group =
|
||||
|
||||
|
||||
### Option `system'
|
||||
### Option `build-use-chroot'
|
||||
#
|
||||
# This option specifies the canonical Nix system name of the current
|
||||
# installation, such as `i686-linux' or `powerpc-darwin'. Nix can
|
||||
# only build derivations whose `system' attribute equals the value
|
||||
# specified here. In general, it never makes sense to modify this
|
||||
# value from its default, since you can use it to `lie' about the
|
||||
# platform you are building on (e.g., perform a Mac OS build on a
|
||||
# Linux machine; the result would obviously be wrong). It only makes
|
||||
# sense if the Nix binaries can run on multiple platforms, e.g.,
|
||||
# `universal binaries' that run on `powerpc-darwin' and `i686-darwin'.
|
||||
# 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.
|
||||
#
|
||||
# It defaults to the canonical Nix system name detected by `configure'
|
||||
# at build time.
|
||||
# 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:
|
||||
# system = i686-darwin
|
||||
#system =
|
||||
# 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
|
||||
|
||||
18
nix.spec.in
18
nix.spec.in
@@ -13,11 +13,10 @@ Version: @version@
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: Software Deployment
|
||||
URL: http://nix.cs.uu.nl/
|
||||
URL: http://nixos.org/
|
||||
Source0: %{name}-@version@.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
||||
%define _prefix /nix
|
||||
Prefix: %{_prefix}
|
||||
Prefix: /usr
|
||||
Requires: /usr/bin/perl
|
||||
Requires: curl
|
||||
|
||||
@@ -47,14 +46,14 @@ if test -n "%{enable_setuid}"; then
|
||||
extraFlags="$extraFlags --with-nix-group=%{nix_group}"
|
||||
fi
|
||||
fi
|
||||
./configure --prefix=%{_prefix} $extraFlags
|
||||
./configure --prefix=%{_prefix} --sysconfdir=/etc $extraFlags
|
||||
make
|
||||
make check
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make DESTDIR=$RPM_BUILD_ROOT install
|
||||
rm $RPM_BUILD_ROOT/%{_prefix}/etc/nix/nix.conf
|
||||
rm $RPM_BUILD_ROOT/etc/nix/nix.conf
|
||||
strip $RPM_BUILD_ROOT/%{_prefix}/bin/* || true
|
||||
|
||||
%clean
|
||||
@@ -76,10 +75,9 @@ fi
|
||||
%{_prefix}/lib
|
||||
%{_prefix}/libexec
|
||||
%{_prefix}/include
|
||||
%{_prefix}/var
|
||||
%{_prefix}/share
|
||||
%{_prefix}/store
|
||||
/etc/profile.d/nix.sh
|
||||
/nix/var
|
||||
/nix/store
|
||||
%config
|
||||
%{_prefix}/etc
|
||||
#%doc
|
||||
#%{_prefix}/share/nix/manual
|
||||
/etc/nix
|
||||
|
||||
206
release.nix
Normal file
206
release.nix
Normal file
@@ -0,0 +1,206 @@
|
||||
{ nixpkgs ? ../nixpkgs }:
|
||||
|
||||
let
|
||||
|
||||
jobs = rec {
|
||||
|
||||
|
||||
tarball =
|
||||
{ nix ? {outPath = ./.; rev = 1234;}
|
||||
, officialRelease ? false
|
||||
}:
|
||||
|
||||
with import nixpkgs {};
|
||||
|
||||
releaseTools.sourceTarball {
|
||||
name = "nix-tarball";
|
||||
version = builtins.readFile ./version;
|
||||
src = nix;
|
||||
inherit officialRelease;
|
||||
|
||||
buildInputs =
|
||||
[ curl bison flex2533 perl libxml2 libxslt w3m bzip2
|
||||
tetex dblatex nukeReferences
|
||||
];
|
||||
|
||||
configureFlags = ''
|
||||
--with-docbook-rng=${docbook5}/xml/rng/docbook
|
||||
--with-docbook-xsl=${docbook5_xsl}/xml/xsl/docbook
|
||||
--with-xml-flags=--nonet
|
||||
'';
|
||||
|
||||
# Include the Bzip2 tarball in the distribution.
|
||||
preConfigure = ''
|
||||
stripHash ${bzip2.src}
|
||||
cp -pv ${bzip2.src} externals/$strippedName
|
||||
|
||||
# TeX needs a writable font cache.
|
||||
export VARTEXFONTS=$TMPDIR/texfonts
|
||||
'';
|
||||
|
||||
preDist = ''
|
||||
make -C doc/manual install prefix=$out
|
||||
|
||||
make -C doc/manual manual.pdf prefix=$out
|
||||
cp doc/manual/manual.pdf $out/manual.pdf
|
||||
|
||||
# The PDF containes filenames of included graphics (see
|
||||
# http://www.tug.org/pipermail/pdftex/2007-August/007290.html).
|
||||
# This causes a retained dependency on dblatex, which Hydra
|
||||
# doesn't like (the output of the tarball job is distributed
|
||||
# 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
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
build =
|
||||
{ tarball ? jobs.tarball {}
|
||||
, system ? "i686-linux"
|
||||
}:
|
||||
|
||||
with import nixpkgs {inherit system;};
|
||||
|
||||
releaseTools.nixBuild {
|
||||
name = "nix";
|
||||
src = tarball;
|
||||
|
||||
buildInputs = [curl perl bzip2 openssl];
|
||||
|
||||
configureFlags = ''
|
||||
--disable-init-state
|
||||
--with-bzip2=${bzip2}
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
static =
|
||||
{ tarball ? jobs.tarball {}
|
||||
, system ? "i686-linux"
|
||||
}:
|
||||
|
||||
with import nixpkgs {inherit system;};
|
||||
|
||||
releaseTools.binaryTarball {
|
||||
name = "nix-static-tarball";
|
||||
src = tarball;
|
||||
|
||||
buildInputs = [curl perl bzip2];
|
||||
|
||||
configureFlags = ''
|
||||
--disable-init-state
|
||||
--with-bzip2=${bzip2}
|
||||
--enable-static-nix
|
||||
'';
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
coverage =
|
||||
{ tarball ? jobs.tarball {}
|
||||
}:
|
||||
|
||||
with import nixpkgs {};
|
||||
|
||||
releaseTools.coverageAnalysis {
|
||||
name = "nix-build";
|
||||
src = tarball;
|
||||
|
||||
buildInputs = [
|
||||
curl perl bzip2 openssl
|
||||
# These are for "make check" only:
|
||||
graphviz libxml2 libxslt
|
||||
];
|
||||
|
||||
configureFlags = ''
|
||||
--disable-init-state --disable-shared
|
||||
--with-bzip2=${bzip2}
|
||||
'';
|
||||
|
||||
lcovFilter = ["*/boost/*" "*-tab.*"];
|
||||
|
||||
# We call `dot', and even though we just use it to
|
||||
# syntax-check generated dot files, it still requires some
|
||||
# fonts. So provide those.
|
||||
FONTCONFIG_FILE = texFunctions.fontsConf;
|
||||
};
|
||||
|
||||
|
||||
rpm_fedora5i386 = makeRPM_i686 (diskImages: diskImages.fedora5i386) 10;
|
||||
rpm_fedora9i386 = makeRPM_i686 (diskImages: diskImages.fedora9i386) 20;
|
||||
rpm_fedora9x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora9x86_64) 20;
|
||||
rpm_fedora10i386 = makeRPM_i686 (diskImages: diskImages.fedora10i386) 30;
|
||||
rpm_fedora10x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora10x86_64) 30;
|
||||
rpm_fedora11i386 = makeRPM_i686 (diskImages: diskImages.fedora11i386) 40;
|
||||
rpm_fedora11x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora11x86_64) 40;
|
||||
rpm_fedora12i386 = makeRPM_i686 (diskImages: diskImages.fedora12i386) 50;
|
||||
rpm_fedora12x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora12x86_64) 50;
|
||||
rpm_opensuse103i386 = makeRPM_i686 (diskImages: diskImages.opensuse103i386) 40;
|
||||
rpm_opensuse110i386 = makeRPM_i686 (diskImages: diskImages.opensuse110i386) 50;
|
||||
rpm_opensuse110x86_64 = makeRPM_x86_64 (diskImages: diskImages.opensuse110x86_64) 50;
|
||||
|
||||
|
||||
deb_debian40i386 = makeDeb_i686 (diskImages: diskImages.debian40i386) 40;
|
||||
deb_debian40x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian40x86_64) 40;
|
||||
deb_debian50i386 = makeDeb_i686 (diskImages: diskImages.debian50i386) 50;
|
||||
deb_debian50x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian50x86_64) 50;
|
||||
deb_ubuntu804i386 = makeDeb_i686 (diskImages: diskImages.ubuntu804i386) 20;
|
||||
deb_ubuntu804x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu804x86_64) 20;
|
||||
deb_ubuntu810i386 = makeDeb_i686 (diskImages: diskImages.ubuntu810i386) 30;
|
||||
deb_ubuntu810x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu810x86_64) 30;
|
||||
deb_ubuntu904i386 = makeDeb_i686 (diskImages: diskImages.ubuntu904i386) 40;
|
||||
deb_ubuntu904x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu904x86_64) 40;
|
||||
deb_ubuntu910i386 = makeDeb_i686 (diskImages: diskImages.ubuntu910i386) 50;
|
||||
deb_ubuntu910x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu910x86_64) 50;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
makeRPM_i686 = makeRPM "i686-linux";
|
||||
makeRPM_x86_64 = makeRPM "x86_64-linux";
|
||||
|
||||
makeRPM =
|
||||
system: diskImageFun: prio:
|
||||
{ tarball ? jobs.tarball {}
|
||||
}:
|
||||
|
||||
with import nixpkgs {inherit system;};
|
||||
|
||||
releaseTools.rpmBuild rec {
|
||||
name = "nix-rpm-${diskImage.name}";
|
||||
src = tarball;
|
||||
diskImage = diskImageFun vmTools.diskImages;
|
||||
memSize = 1024;
|
||||
meta = { schedulingPriority = toString prio; };
|
||||
};
|
||||
|
||||
|
||||
makeDeb_i686 = makeDeb "i686-linux";
|
||||
makeDeb_x86_64 = makeDeb "x86_64-linux";
|
||||
|
||||
makeDeb =
|
||||
system: diskImageFun: prio:
|
||||
{ tarball ? jobs.tarball {}
|
||||
}:
|
||||
|
||||
with import nixpkgs {inherit system;};
|
||||
|
||||
releaseTools.debBuild {
|
||||
name = "nix-deb";
|
||||
src = tarball;
|
||||
diskImage = diskImageFun vmTools.diskImages;
|
||||
memSize = 1024;
|
||||
meta = { schedulingPriority = toString prio; };
|
||||
configureFlags = "--sysconfdir=/etc";
|
||||
debRequires = ["curl"];
|
||||
};
|
||||
|
||||
|
||||
in jobs
|
||||
@@ -1,22 +1,27 @@
|
||||
bin_SCRIPTS = nix-collect-garbage \
|
||||
nix-pull nix-push nix-prefetch-url \
|
||||
nix-install-package nix-channel nix-build \
|
||||
nix-pack-closure nix-unpack-closure \
|
||||
nix-copy-closure
|
||||
nix-copy-closure
|
||||
|
||||
noinst_SCRIPTS = nix-profile.sh generate-patches.pl find-runtime-roots.pl
|
||||
noinst_SCRIPTS = nix-profile.sh generate-patches.pl \
|
||||
find-runtime-roots.pl build-remote.pl nix-reduce-build \
|
||||
copy-from-other-stores.pl nix-http-export.cgi
|
||||
|
||||
nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl
|
||||
|
||||
install-exec-local: readmanifest.pm download-using-manifests.pl find-runtime-roots.pl
|
||||
install-exec-local: readmanifest.pm 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) -d $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_DATA) readmanifest.pm $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_DATA) ssh.pm $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) generate-patches.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) -d $(DESTDIR)$(sysconfdir)/nix
|
||||
|
||||
include ../substitute.mk
|
||||
@@ -27,9 +32,13 @@ EXTRA_DIST = nix-collect-garbage.in \
|
||||
nix-channel.in \
|
||||
readmanifest.pm.in \
|
||||
readconfig.pm.in \
|
||||
ssh.pm \
|
||||
nix-build.in \
|
||||
download-using-manifests.pl.in \
|
||||
copy-from-other-stores.pl.in \
|
||||
generate-patches.pl.in \
|
||||
nix-pack-closure.in nix-unpack-closure.in \
|
||||
nix-copy-closure.in \
|
||||
find-runtime-roots.pl.in
|
||||
find-runtime-roots.pl.in \
|
||||
build-remote.pl.in \
|
||||
nix-reduce-build.in \
|
||||
nix-http-export.cgi.in
|
||||
|
||||
240
scripts/build-remote.pl.in
Executable file
240
scripts/build-remote.pl.in
Executable file
@@ -0,0 +1,240 @@
|
||||
#! @perl@ -w -I@libexecdir@/nix
|
||||
|
||||
use Fcntl ':flock';
|
||||
use English '-no_match_vars';
|
||||
use IO::Handle;
|
||||
use ssh qw/sshOpts openSSHConnection/;
|
||||
|
||||
|
||||
# General operation:
|
||||
#
|
||||
# Try to find a free machine of type $neededSystem. We do this as
|
||||
# follows:
|
||||
# - We acquire an exclusive lock on $currentLoad/main-lock.
|
||||
# - For each machine $machine of type $neededSystem and for each $slot
|
||||
# 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 release the exclusive lock on $currentLoad/main-lock.
|
||||
# - We perform the build on $neededSystem.
|
||||
# - We release the exclusive lock on $currentLoad/$machine-$slot.
|
||||
#
|
||||
# The nice thing about this scheme is that if we die prematurely, the
|
||||
# locks are released automatically.
|
||||
|
||||
|
||||
# Make sure that we don't get any SSH passphrase or host key popups -
|
||||
# if there is any problem it should fail, not do something
|
||||
# interactive.
|
||||
$ENV{"DISPLAY"} = "";
|
||||
$ENV{"SSH_ASKPASS"} = "";
|
||||
|
||||
|
||||
my $loadIncreased = 0;
|
||||
|
||||
my ($amWilling, $localSystem, $neededSystem, $drvPath, $maxSilentTime) = @ARGV;
|
||||
$maxSilentTime = 0 unless defined $maxSilentTime;
|
||||
|
||||
sub sendReply {
|
||||
my $reply = shift;
|
||||
print STDERR "# $reply\n";
|
||||
}
|
||||
|
||||
sub decline {
|
||||
sendReply "decline";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
|
||||
decline unless defined $currentLoad;
|
||||
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
|
||||
|
||||
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
|
||||
decline if !defined $conf || ! -e $conf;
|
||||
|
||||
my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
|
||||
|
||||
|
||||
# Read the list of machines.
|
||||
my @machines;
|
||||
open CONF, "< $conf" or die;
|
||||
|
||||
while (<CONF>) {
|
||||
chomp;
|
||||
s/\#.*$//g;
|
||||
next if /^\s*$/;
|
||||
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)(\s+([0-9\.]+))?\s*$/ or die;
|
||||
push @machines,
|
||||
{ hostName => $1
|
||||
, systemTypes => [split(/,/, $2)]
|
||||
, sshKeys => $3
|
||||
, maxJobs => $4
|
||||
, speedFactor => 1.0 * ($6 || 1)
|
||||
, enabled => 1
|
||||
};
|
||||
}
|
||||
|
||||
close CONF;
|
||||
|
||||
|
||||
# Acquire the exclusive lock on $currentLoad/main-lock.
|
||||
my $mainLock = "$currentLoad/main-lock";
|
||||
open MAINLOCK, ">>$mainLock" or die;
|
||||
flock(MAINLOCK, LOCK_EX) or die;
|
||||
|
||||
|
||||
sub openSlotLock {
|
||||
my ($machine, $slot) = @_;
|
||||
my $slotLockFn = "$currentLoad/" . (join '+', @{$machine->{systemTypes}}) . "-" . $machine->{hostName} . "-$slot";
|
||||
my $slotLock = new IO::Handle;
|
||||
open $slotLock, ">>$slotLockFn" or die;
|
||||
return $slotLock;
|
||||
}
|
||||
|
||||
|
||||
my $hostName;
|
||||
my $slotLock;
|
||||
|
||||
while (1) {
|
||||
|
||||
# Find all machine that can execute this build, i.e., that support
|
||||
# builds for the given platform and are not at their job limit.
|
||||
my $rightType = 0;
|
||||
my @available = ();
|
||||
LOOP: foreach my $cur (@machines) {
|
||||
if ($cur->{enabled} && grep { $neededSystem eq $_ } @{$cur->{systemTypes}}) {
|
||||
$rightType = 1;
|
||||
|
||||
# We have a machine of the right type. Determine the load on
|
||||
# the machine.
|
||||
my $slot = 0;
|
||||
my $load = 0;
|
||||
my $free;
|
||||
while ($slot < $cur->{maxJobs}) {
|
||||
my $slotLock = openSlotLock($cur, $slot);
|
||||
if (flock($slotLock, LOCK_EX | LOCK_NB)) {
|
||||
$free = $slot unless defined $free;
|
||||
flock($slotLock, LOCK_UN) or die;
|
||||
} else {
|
||||
$load++;
|
||||
}
|
||||
close $slotLock;
|
||||
$slot++;
|
||||
}
|
||||
|
||||
push @available, { machine => $cur, load => $load, free => $free }
|
||||
if $load < $cur->{maxJobs};
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $ENV{NIX_DEBUG_HOOK}) {
|
||||
print STDERR "load on " . $_->{machine}->{hostName} . " = " . $_->{load} . "\n"
|
||||
foreach @available;
|
||||
}
|
||||
|
||||
|
||||
# Didn't find any available machine? Then decline or postpone.
|
||||
if (scalar @available == 0) {
|
||||
# Postpone if we have a machine of the right type, except if the
|
||||
# local system can and wants to do the build.
|
||||
if ($rightType && !$canBuildLocally) {
|
||||
sendReply "postpone";
|
||||
exit 0;
|
||||
} else {
|
||||
decline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Prioritise the available machines as follows:
|
||||
# - First by load divided by speed factor, rounded to the nearest
|
||||
# integer. This causes fast machines to be preferred over slow
|
||||
# machines with similar loads.
|
||||
# - Then by speed factor.
|
||||
# - Finally by load.
|
||||
sub lf { my $x = shift; return int($x->{load} / $x->{machine}->{speedFactor} + 0.4999); }
|
||||
@available = sort
|
||||
{ lf($a) <=> lf($b)
|
||||
|| $b->{machine}->{speedFactor} <=> $a->{machine}->{speedFactor}
|
||||
|| $a->{load} <=> $b->{load}
|
||||
} @available;
|
||||
|
||||
|
||||
# Select the best available machine and lock a free slot.
|
||||
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;
|
||||
|
||||
close MAINLOCK;
|
||||
|
||||
|
||||
# Connect to the selected machine.
|
||||
@sshOpts = ("-i", $machine->{sshKeys}, "-x");
|
||||
$hostName = $machine->{hostName};
|
||||
last if openSSHConnection $hostName;
|
||||
|
||||
warn "unable to open SSH connection to $hostName, trying other available machines...\n";
|
||||
$machine->{enabled} = 0;
|
||||
}
|
||||
|
||||
|
||||
# Tell Nix we've accepted the build.
|
||||
sendReply "accept";
|
||||
my $x = <STDIN>;
|
||||
chomp $x;
|
||||
|
||||
if ($x ne "okay") {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
# Do the actual build.
|
||||
print STDERR "building `$drvPath' on `$hostName'\n";
|
||||
|
||||
my $inputs = `cat inputs`; die if ($? != 0);
|
||||
$inputs =~ s/\n/ /g;
|
||||
|
||||
my $outputs = `cat outputs`; die if ($? != 0);
|
||||
$outputs =~ s/\n/ /g;
|
||||
|
||||
print "copying inputs...\n";
|
||||
|
||||
my $maybeSign = "";
|
||||
$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec";
|
||||
|
||||
system("NIX_SSHOPTS=\"@sshOpts\" @bindir@/nix-copy-closure $hostName $maybeSign $drvPath $inputs") == 0
|
||||
or die "cannot copy inputs to $hostName: $?";
|
||||
|
||||
print "building...\n";
|
||||
|
||||
my $buildFlags = "--max-silent-time $maxSilentTime";
|
||||
|
||||
# `-tt' forces allocation of a pseudo-terminal. This is required to
|
||||
# make the remote nix-store process receive a signal when the
|
||||
# connection dies. Without it, the remote process might continue to
|
||||
# run indefinitely (that is, until it next tries to write to
|
||||
# stdout/stderr).
|
||||
if (system("ssh $hostName @sshOpts -tt 'nix-store --realise $buildFlags $drvPath > /dev/null'") != 0) {
|
||||
# If we couldn't run ssh or there was an ssh problem (indicated by
|
||||
# exit code 255), then we return exit code 1; otherwise we assume
|
||||
# that the builder failed, which we indicate to Nix using exit
|
||||
# code 100. It's important to distinguish between the two because
|
||||
# the first is a transient failure and the latter is permanent.
|
||||
my $res = $? == -1 || ($? >> 8) == 255 ? 1 : 100;
|
||||
print STDERR "build of `$drvPath' on `$hostName' failed with exit code $?\n";
|
||||
exit $res;
|
||||
}
|
||||
|
||||
print "build of `$drvPath' on `$hostName' succeeded\n";
|
||||
|
||||
foreach my $output (split '\n', $outputs) {
|
||||
my $maybeSignRemote = "";
|
||||
$maybeSignRemote = "--sign" if $UID != 0;
|
||||
|
||||
system("ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output' | @bindir@/nix-store --import > /dev/null") == 0
|
||||
or die "cannot copy $output from $hostName: $?";
|
||||
}
|
||||
98
scripts/copy-from-other-stores.pl.in
Normal file
98
scripts/copy-from-other-stores.pl.in
Normal file
@@ -0,0 +1,98 @@
|
||||
#! @perl@ -w
|
||||
|
||||
use strict;
|
||||
use File::Basename;
|
||||
use IO::Handle;
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
|
||||
my @remoteStoresAll = split ':', ($ENV{"NIX_OTHER_STORES"} or "");
|
||||
|
||||
my @remoteStores;
|
||||
foreach my $dir (@remoteStoresAll) {
|
||||
push @remoteStores, glob($dir);
|
||||
}
|
||||
|
||||
|
||||
sub findStorePath {
|
||||
my $storePath = shift;
|
||||
|
||||
my $storePathName = basename $storePath;
|
||||
|
||||
foreach my $store (@remoteStores) {
|
||||
# Determine whether $storePath exists by looking for the
|
||||
# existence of the info file, and if so, get store path info
|
||||
# from that file. This rather breaks abstraction: we should
|
||||
# be using `nix-store' for that. But right now there is no
|
||||
# good way to tell nix-store to access a store mounted under a
|
||||
# different location (there's $NIX_STORE, but that only works
|
||||
# if the remote store is mounted under its "real" location).
|
||||
my $infoFile = "$store/var/nix/db/info/$storePathName";
|
||||
my $storePath2 = "$store/store/$storePathName";
|
||||
if (-f $infoFile && -e $storePath2) {
|
||||
return ($infoFile, $storePath2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($ARGV[0] eq "--query") {
|
||||
|
||||
while (<STDIN>) {
|
||||
my $cmd = $_; chomp $cmd;
|
||||
|
||||
if ($cmd eq "have") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
(my $infoFile) = findStorePath $storePath;
|
||||
print STDOUT ($infoFile ? "1\n" : "0\n");
|
||||
}
|
||||
|
||||
elsif ($cmd eq "info") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
(my $infoFile) = findStorePath $storePath;
|
||||
if (!$infoFile) {
|
||||
print "0\n";
|
||||
next; # not an error
|
||||
}
|
||||
print "1\n";
|
||||
|
||||
my $deriver = "";
|
||||
my @references = ();
|
||||
|
||||
open INFO, "<$infoFile" or die "cannot read info file $infoFile\n";
|
||||
while (<INFO>) {
|
||||
chomp;
|
||||
/^([\w-]+): (.*)$/ or die "bad info file";
|
||||
my $key = $1;
|
||||
my $value = $2;
|
||||
if ($key eq "Deriver") { $deriver = $value; }
|
||||
elsif ($key eq "References") { @references = split ' ', $value; }
|
||||
}
|
||||
close INFO;
|
||||
|
||||
print "$deriver\n";
|
||||
print scalar @references, "\n";
|
||||
print "$_\n" foreach @references;
|
||||
print "0\n"; # !!! showing size not supported (yet)
|
||||
}
|
||||
|
||||
else { die "unknown command `$cmd'"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
elsif ($ARGV[0] eq "--substitute") {
|
||||
die unless scalar @ARGV == 2;
|
||||
my $storePath = $ARGV[1];
|
||||
(my $infoFile, my $sourcePath) = findStorePath $storePath;
|
||||
die unless $infoFile;
|
||||
print "\n*** Copying `$storePath' from `$sourcePath'\n\n";
|
||||
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $storePath") == 0
|
||||
or die "cannot copy `$sourcePath' to `$storePath'";
|
||||
}
|
||||
|
||||
|
||||
else { die; }
|
||||
@@ -5,22 +5,13 @@ use readmanifest;
|
||||
use POSIX qw(strftime);
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
my $manifestDir = "@localstatedir@/nix/manifests";
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
|
||||
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "@localstatedir@/nix/manifests");
|
||||
my $logFile = "@localstatedir@/log/nix/downloads";
|
||||
|
||||
open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
|
||||
|
||||
# Create a temporary directory.
|
||||
my $tmpDir = tempdir("nix-download.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
chdir $tmpDir or die "cannot change to `$tmpDir': $!";
|
||||
|
||||
my $tmpNar = "$tmpDir/nar";
|
||||
my $tmpNar2 = "$tmpDir/nar2";
|
||||
|
||||
END { unlink $tmpNar; unlink $tmpNar2; rmdir $tmpDir; }
|
||||
|
||||
|
||||
# Load all manifests.
|
||||
my %narFiles;
|
||||
@@ -28,49 +19,61 @@ my %localPaths;
|
||||
my %patches;
|
||||
|
||||
for my $manifest (glob "$manifestDir/*.nixmanifest") {
|
||||
# print STDERR "reading $manifest\n";
|
||||
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
|
||||
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
|
||||
if ($version < 3) {
|
||||
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
|
||||
exit 1;
|
||||
}
|
||||
if ($version >= 10) {
|
||||
print STDERR "manifest `$manifest' is too new; please delete it or upgrade Nix\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Parse the arguments.
|
||||
|
||||
if ($ARGV[0] eq "--query-paths") {
|
||||
foreach my $storePath (keys %narFiles) { print "$storePath\n"; }
|
||||
foreach my $storePath (keys %localPaths) { print "$storePath\n"; }
|
||||
exit 0;
|
||||
}
|
||||
if ($ARGV[0] eq "--query") {
|
||||
|
||||
elsif ($ARGV[0] eq "--query-info") {
|
||||
shift @ARGV;
|
||||
foreach my $storePath (@ARGV) {
|
||||
my $info;
|
||||
if (defined $narFiles{$storePath}) {
|
||||
$info = @{$narFiles{$storePath}}[0];
|
||||
while (<STDIN>) {
|
||||
my $cmd = $_; chomp $cmd;
|
||||
|
||||
if ($cmd eq "have") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
print STDOUT ((defined $narFiles{$storePath} or defined $localPaths{$storePath})
|
||||
? "1\n" : "0\n");
|
||||
}
|
||||
elsif (defined $localPaths{$storePath}) {
|
||||
$info = @{$localPaths{$storePath}}[0];
|
||||
}
|
||||
else {
|
||||
next; # not an error
|
||||
}
|
||||
print "$storePath\n";
|
||||
print "$info->{deriver}\n";
|
||||
my @references = split " ", $info->{references};
|
||||
my $count = scalar @references;
|
||||
print "$count\n";
|
||||
foreach my $reference (@references) {
|
||||
print "$reference\n";
|
||||
|
||||
elsif ($cmd eq "info") {
|
||||
my $storePath = <STDIN>; chomp $storePath;
|
||||
my $info;
|
||||
if (defined $narFiles{$storePath}) {
|
||||
$info = @{$narFiles{$storePath}}[0];
|
||||
}
|
||||
elsif (defined $localPaths{$storePath}) {
|
||||
$info = @{$localPaths{$storePath}}[0];
|
||||
}
|
||||
else {
|
||||
print "0\n";
|
||||
next; # not an error
|
||||
}
|
||||
print "1\n";
|
||||
print "$info->{deriver}\n";
|
||||
my @references = split " ", $info->{references};
|
||||
print scalar @references, "\n";
|
||||
print "$_\n" foreach @references;
|
||||
my $size = $info->{size} || 0;
|
||||
print "$size\n";
|
||||
}
|
||||
|
||||
else { die "unknown command `$cmd'"; }
|
||||
}
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
elsif ($ARGV[0] ne "--substitute") {
|
||||
die "syntax: $0 [--query-paths | --query-info PATHS... | --substitute PATH]\n";
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +81,16 @@ die unless scalar @ARGV == 2;
|
||||
my $targetPath = $ARGV[1];
|
||||
|
||||
|
||||
# Create a temporary directory.
|
||||
my $tmpDir = tempdir("nix-download.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
my $tmpNar = "$tmpDir/nar";
|
||||
my $tmpNar2 = "$tmpDir/nar2";
|
||||
|
||||
|
||||
open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
|
||||
|
||||
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
|
||||
print LOGFILE "$$ get $targetPath $date\n";
|
||||
|
||||
@@ -90,7 +103,7 @@ foreach my $localPath (@{$localPathList}) {
|
||||
my $sourcePath = $localPath->{copyFrom};
|
||||
if (-e $sourcePath) {
|
||||
print "\n*** Step 1/1: copying from $sourcePath\n";
|
||||
system("@bindir@/nix-store --dump $sourcePath | @bindir@/nix-store --restore $targetPath") == 0
|
||||
system("$binDir/nix-store --dump $sourcePath | $binDir/nix-store --restore $targetPath") == 0
|
||||
or die "cannot copy `$sourcePath' to `$targetPath'";
|
||||
exit 0;
|
||||
}
|
||||
@@ -139,7 +152,7 @@ addToQueue $targetPath;
|
||||
|
||||
sub isValidPath {
|
||||
my $p = shift;
|
||||
return system("@bindir@/nix-store --check-validity '$p' 2> /dev/null") == 0;
|
||||
return system("$binDir/nix-store --check-validity '$p' 2> /dev/null") == 0;
|
||||
}
|
||||
|
||||
sub parseHash {
|
||||
@@ -173,15 +186,13 @@ while ($queueFront < scalar @queue) {
|
||||
my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash};
|
||||
my $format = "--base32";
|
||||
$format = "" if $baseHashAlgo eq "md5";
|
||||
my $hash = `@bindir@/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
|
||||
my $hash = `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
|
||||
chomp $hash;
|
||||
# print " MY HASH is $hash\n";
|
||||
if ($hash ne $baseHash) {
|
||||
print LOGFILE "$$ rejecting $patch->{basePath}\n";
|
||||
next;
|
||||
}
|
||||
}
|
||||
# print " PATCH from $patch->{basePath}\n";
|
||||
addToQueue $patch->{basePath};
|
||||
addEdge $patch->{basePath}, $u, $patch->{size}, "patch", $patch;
|
||||
}
|
||||
@@ -189,10 +200,12 @@ while ($queueFront < scalar @queue) {
|
||||
# Add NAR file edges to the start node.
|
||||
my $narFileList = $narFiles{$u};
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
# print " NAR from $narFile->{url}\n";
|
||||
addEdge "start", $u, $narFile->{size}, "narfile", $narFile;
|
||||
# !!! how to handle files whose size is not known in advance?
|
||||
# For now, assume some arbitrary size (1 MB).
|
||||
addEdge "start", $u, ($narFile->{size} || 1000000), "narfile", $narFile;
|
||||
if ($u eq $targetPath) {
|
||||
print LOGFILE "$$ full-download-would-be $narFile->{size}\n";
|
||||
my $size = $narFile->{size} || -1;
|
||||
print LOGFILE "$$ full-download-would-be $size\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +231,6 @@ while (scalar @todo > 0) {
|
||||
|
||||
my $u_ = $graph{$u};
|
||||
|
||||
# print "IN $u $u_->{d}\n";
|
||||
|
||||
foreach my $edge (@{$u_->{edges}}) {
|
||||
my $v_ = $graph{$edge->{end}};
|
||||
if ($v_->{d} > $u_->{d} + $edge->{weight}) {
|
||||
@@ -227,7 +238,6 @@ while (scalar @todo > 0) {
|
||||
# Store the edge; to edge->start is actually the
|
||||
# predecessor.
|
||||
$v_->{pred} = $edge;
|
||||
# print " RELAX $edge->{end} $v_->{d}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,20 +259,18 @@ while ($cur ne "start") {
|
||||
my $curStep = 1;
|
||||
my $maxStep = scalar @path;
|
||||
|
||||
sub downloadFile {
|
||||
my $url = shift;
|
||||
my ($hashAlgo, $hash) = parseHash(shift);
|
||||
sub downloadFile {
|
||||
my $url = shift;
|
||||
$ENV{"PRINT_PATH"} = 1;
|
||||
$ENV{"QUIET"} = 1;
|
||||
$ENV{"NIX_HASH_ALGO"} = $hashAlgo;
|
||||
my ($hash2, $path) = `@bindir@/nix-prefetch-url '$url' '$hash'`;
|
||||
my ($hash, $path) = `$binDir/nix-prefetch-url '$url'`;
|
||||
die "download of `$url' failed" unless $? == 0;
|
||||
chomp $hash2;
|
||||
chomp $path;
|
||||
die "hash mismatch, expected $hash, got $hash2" if $hash ne $hash2;
|
||||
return $path;
|
||||
}
|
||||
|
||||
my $finalNarHash;
|
||||
|
||||
while (scalar @path > 0) {
|
||||
my $edge = pop @path;
|
||||
my $u = $edge->{start};
|
||||
@@ -279,7 +287,7 @@ while (scalar @path > 0) {
|
||||
# as a base to one or more patches. So turn the base path
|
||||
# into a NAR archive, to which we can apply the patch.
|
||||
print " packing base path...\n";
|
||||
system("@bindir@/nix-store --dump $v > $tmpNar") == 0
|
||||
system("$binDir/nix-store --dump $v > $tmpNar") == 0
|
||||
or die "cannot dump `$v'";
|
||||
}
|
||||
}
|
||||
@@ -292,7 +300,7 @@ while (scalar @path > 0) {
|
||||
|
||||
# Download the patch.
|
||||
print " downloading patch...\n";
|
||||
my $patchPath = downloadFile "$patch->{url}", "$patch->{hash}";
|
||||
my $patchPath = downloadFile "$patch->{url}";
|
||||
|
||||
# Apply the patch to the NAR archive produced in step 1 (for
|
||||
# the already present path) or a later step (for patch sequences).
|
||||
@@ -307,20 +315,23 @@ while (scalar @path > 0) {
|
||||
# This was the last patch. Unpack the final NAR archive
|
||||
# into the target path.
|
||||
print " unpacking patched archive...\n";
|
||||
system("@bindir@/nix-store --restore $v < $tmpNar2") == 0
|
||||
system("$binDir/nix-store --restore $v < $tmpNar2") == 0
|
||||
or die "cannot unpack $tmpNar2 into `$v'";
|
||||
}
|
||||
|
||||
$finalNarHash = $patch->{narHash};
|
||||
}
|
||||
|
||||
elsif ($edge->{type} eq "narfile") {
|
||||
my $narFile = $edge->{info};
|
||||
print "downloading `$narFile->{url}' into `$v'\n";
|
||||
|
||||
print LOGFILE "$$ narfile $narFile->{url} $narFile->{size} $v\n";
|
||||
my $size = $narFile->{size} || -1;
|
||||
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
|
||||
|
||||
# Download the archive.
|
||||
print " downloading archive...\n";
|
||||
my $narFilePath = downloadFile "$narFile->{url}", "$narFile->{hash}";
|
||||
my $narFilePath = downloadFile "$narFile->{url}";
|
||||
|
||||
if ($curStep < $maxStep) {
|
||||
# The archive will be used a base to a patch.
|
||||
@@ -329,14 +340,39 @@ while (scalar @path > 0) {
|
||||
} else {
|
||||
# Unpack the archive into the target path.
|
||||
print " unpacking archive...\n";
|
||||
system("@bunzip2@ < '$narFilePath' | @bindir@/nix-store --restore '$v'") == 0
|
||||
system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0
|
||||
or die "cannot unpack `$narFilePath' into `$v'";
|
||||
}
|
||||
|
||||
$finalNarHash = $narFile->{narHash};
|
||||
}
|
||||
|
||||
$curStep++;
|
||||
}
|
||||
|
||||
|
||||
# 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 $extraFlag =
|
||||
($hashAlgo eq "sha256" && length($hash) != 64)
|
||||
? "--base32" : "";
|
||||
|
||||
my $hash2 = `@bindir@/nix-hash --type $hashAlgo $extraFlag $targetPath`
|
||||
or die "cannot compute hash of path `$targetPath'";
|
||||
chomp $hash2;
|
||||
|
||||
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2"
|
||||
if $hash ne $hash2;
|
||||
} else {
|
||||
die "cannot check integrity of the downloaded path since its hash is not known";
|
||||
}
|
||||
|
||||
|
||||
print LOGFILE "$$ success\n";
|
||||
close LOGFILE;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
use strict;
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
|
||||
my $addDrvLink = 0;
|
||||
my $addOutLink = 1;
|
||||
@@ -9,6 +11,9 @@ my $addOutLink = 1;
|
||||
my $outLink;
|
||||
my $drvLink;
|
||||
|
||||
my $dryRun = 0;
|
||||
my $verbose = 0;
|
||||
|
||||
my @instArgs = ();
|
||||
my @buildArgs = ();
|
||||
my @exprs = ();
|
||||
@@ -73,22 +78,51 @@ EOF
|
||||
|
||||
elsif ($arg eq "--attr" or $arg eq "-A") {
|
||||
$n++;
|
||||
die "$0: `--attr' requires an argument\n" unless $n < scalar @ARGV;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @instArgs, ("--attr", $ARGV[$n]);
|
||||
}
|
||||
|
||||
elsif ($arg eq "--arg") {
|
||||
die "$0: `--arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
|
||||
push @instArgs, ("--arg", $ARGV[$n + 1], $ARGV[$n + 2]);
|
||||
elsif ($arg eq "--arg" || $arg eq "--argstr") {
|
||||
die "$0: `$arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
|
||||
push @instArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
|
||||
$n += 2;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time") {
|
||||
elsif ($arg eq "--log-type") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @instArgs, ($arg, $ARGV[$n]);
|
||||
push @buildArgs, ($arg, $ARGV[$n]);
|
||||
}
|
||||
|
||||
elsif ($arg eq "--option") {
|
||||
die "$0: `$arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
|
||||
push @instArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
|
||||
push @buildArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
|
||||
$n += 2;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time" or $arg eq "--log-type") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @buildArgs, ($arg, $ARGV[$n]);
|
||||
}
|
||||
|
||||
elsif ($arg eq "--dry-run") {
|
||||
push @buildArgs, "--dry-run";
|
||||
$dryRun = 1;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--show-trace") {
|
||||
push @instArgs, $arg;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--verbose" or substr($arg, 0, 2) eq "-v") {
|
||||
push @buildArgs, $arg;
|
||||
push @instArgs, $arg;
|
||||
$verbose = 1;
|
||||
}
|
||||
|
||||
elsif (substr($arg, 0, 1) eq "-") {
|
||||
push @buildArgs, $arg;
|
||||
}
|
||||
@@ -117,21 +151,29 @@ foreach my $expr (@exprs) {
|
||||
# Instantiate.
|
||||
my @drvPaths;
|
||||
# !!! would prefer the perl 5.8.0 pipe open feature here.
|
||||
my $pid = open(DRVPATHS, "-|") || exec "@bindir@/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
||||
my $pid = open(DRVPATHS, "-|") || exec "$binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
|
||||
while (<DRVPATHS>) {chomp; push @drvPaths, $_;}
|
||||
close DRVPATHS or exit 1;
|
||||
if (!close DRVPATHS) {
|
||||
die "nix-instantiate killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||
exit 1;
|
||||
}
|
||||
|
||||
foreach my $drvPath (@drvPaths) {
|
||||
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
|
||||
print STDERR "store derivation is $target\n";
|
||||
print STDERR "derivation is $target\n" if $verbose;
|
||||
}
|
||||
|
||||
# Build.
|
||||
my @outPaths;
|
||||
$pid = open(OUTPATHS, "-|") || exec "@bindir@/nix-store", "--add-root", $outLink, "--indirect", "-rv",
|
||||
$pid = open(OUTPATHS, "-|") || exec "$binDir/nix-store", "--add-root", $outLink, "--indirect", "-rv",
|
||||
@buildArgs, @drvPaths;
|
||||
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
|
||||
close OUTPATHS or exit 1;
|
||||
if (!close OUTPATHS) {
|
||||
die "nix-store killed by signal " . ($? & 127) . "\n" if ($? & 127);
|
||||
exit 1;
|
||||
}
|
||||
|
||||
next if $dryRun;
|
||||
|
||||
foreach my $outPath (@outPaths) {
|
||||
my $target = readlink $outPath or die "cannot read symlink `$outPath'";
|
||||
|
||||
@@ -78,6 +78,9 @@ sub removeChannel {
|
||||
sub update {
|
||||
readChannels;
|
||||
|
||||
# Create the manifests directory if it doesn't exist.
|
||||
mkdir "$stateDir/manifests", 0755 unless -e "$stateDir/manifests";
|
||||
|
||||
# Do we have write permission to the manifests directory? If not,
|
||||
# then just skip pulling the manifest and just download the Nix
|
||||
# expressions. If the user is a non-privileged user in a
|
||||
@@ -85,11 +88,6 @@ sub update {
|
||||
# source.
|
||||
if (-W "$stateDir/manifests") {
|
||||
|
||||
# Remove all the old manifests.
|
||||
for my $manifest (glob "$stateDir/manifests/*.nixmanifest") {
|
||||
unlink $manifest or die "cannot remove `$manifest': $!";
|
||||
}
|
||||
|
||||
# Pull cache manifests.
|
||||
foreach my $url (@channels) {
|
||||
#print "pulling cache manifest from `$url'\n";
|
||||
@@ -125,15 +123,13 @@ sub update {
|
||||
|
||||
my $rootFile = "$rootsDir/per-user/$userName/channels";
|
||||
|
||||
# Instantiate the Nix expression.
|
||||
# Build the Nix expression.
|
||||
print "unpacking channel Nix expressions...\n";
|
||||
my $storeExpr = `@bindir@/nix-instantiate --add-root '$rootFile'.tmp @datadir@/nix/corepkgs/channels/unpack.nix --argstr system @system@ --arg inputs '$inputs'`
|
||||
or die "cannot instantiate Nix expression";
|
||||
chomp $storeExpr;
|
||||
|
||||
# Build the resulting derivation.
|
||||
my $outPath = `@bindir@/nix-store --add-root '$rootFile' -r '$storeExpr'`
|
||||
or die "cannot realise store expression";
|
||||
my $outPath = `\\
|
||||
@bindir@/nix-build --out-link '$rootFile' --drv-link '$rootFile'.tmp \\
|
||||
@datadir@/nix/corepkgs/channels/unpack.nix \\
|
||||
--argstr system @system@ --arg inputs '$inputs'`
|
||||
or die "cannot unpack the channels";
|
||||
chomp $outPath;
|
||||
|
||||
unlink "$rootFile.tmp";
|
||||
|
||||
@@ -4,6 +4,8 @@ use strict;
|
||||
|
||||
my $profilesDir = "@localstatedir@/nix/profiles";
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
|
||||
# Process the command line arguments.
|
||||
my @args = ();
|
||||
@@ -34,7 +36,7 @@ sub removeOldGenerations {
|
||||
$name = $dir . "/" . $name;
|
||||
if (-l $name && (readlink($name) =~ /link/)) {
|
||||
print STDERR "removing old generations of profile $name\n";
|
||||
system("@bindir@/nix-env", "-p", $name, "--delete-generations", "old");
|
||||
system("$binDir/nix-env", "-p", $name, "--delete-generations", "old");
|
||||
}
|
||||
elsif (! -l $name && -d $name) {
|
||||
removeOldGenerations $name;
|
||||
@@ -48,4 +50,4 @@ removeOldGenerations $profilesDir if $removeOld;
|
||||
|
||||
|
||||
# Run the actual garbage collector.
|
||||
exec "@bindir@/nix-store", "--gc", @args;
|
||||
exec "$binDir/nix-store", "--gc", @args;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#! @perl@ -w
|
||||
#! @perl@ -w -I@libexecdir@/nix
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
use ssh;
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
print STDERR <<EOF
|
||||
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] PATHS...
|
||||
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
|
||||
EOF
|
||||
;
|
||||
exit 1;
|
||||
@@ -15,12 +16,11 @@ EOF
|
||||
|
||||
# Get the target host.
|
||||
my $sshHost;
|
||||
my @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
|
||||
|
||||
my $sign = 0;
|
||||
|
||||
my $compressor = "cat";
|
||||
my $decompressor = "cat";
|
||||
my $compressor = "";
|
||||
my $decompressor = "";
|
||||
|
||||
my $toMode = 1;
|
||||
|
||||
@@ -35,8 +35,8 @@ while (@ARGV) {
|
||||
$sign = 1;
|
||||
}
|
||||
elsif ($arg eq "--gzip") {
|
||||
$compressor = "gzip";
|
||||
$decompressor = "gunzip";
|
||||
$compressor = "| gzip";
|
||||
$decompressor = "gunzip |";
|
||||
}
|
||||
elsif ($arg eq "--from") {
|
||||
$toMode = 0;
|
||||
@@ -53,40 +53,30 @@ while (@ARGV) {
|
||||
}
|
||||
|
||||
|
||||
openSSHConnection $sshHost or die "$0: unable to start SSH\n";
|
||||
|
||||
|
||||
if ($toMode) { # Copy TO the remote machine.
|
||||
|
||||
my @allStorePaths;
|
||||
my %storePathsSeen;
|
||||
|
||||
foreach my $storePath (@storePaths) {
|
||||
# $arg might be a symlink to the store, so resolve it.
|
||||
my $storePath2 = (`$binDir/nix-store --query --resolve '$storePath'`
|
||||
or die "cannot resolve `$storePath'");
|
||||
chomp $storePath2;
|
||||
|
||||
# Get the closure of this path.
|
||||
my $pid = open(READ,
|
||||
"$binDir/nix-store --query --requisites '$storePath2'|") or die;
|
||||
# Get the closure of this path.
|
||||
my $pid = open(READ, "$binDir/nix-store --query --requisites @storePaths|") or die;
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
if (!defined $storePathsSeen{$_}) {
|
||||
push @allStorePaths, $_;
|
||||
$storePathsSeen{$_} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
close READ or die "nix-store failed: $?";
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
push @allStorePaths, $_;
|
||||
}
|
||||
|
||||
close READ or die "nix-store failed: $?";
|
||||
|
||||
|
||||
# Ask the remote host which paths are invalid.
|
||||
open(READ, "ssh @sshOpts $sshHost nix-store --check-validity --print-invalid @allStorePaths|");
|
||||
open(READ, "ssh $sshHost @sshOpts nix-store --check-validity --print-invalid @allStorePaths|");
|
||||
my @missing = ();
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
print STDERR "target machine needs $_\n";
|
||||
push @missing, $_;
|
||||
}
|
||||
close READ or die;
|
||||
@@ -94,9 +84,11 @@ if ($toMode) { # Copy TO the remote machine.
|
||||
|
||||
# Export the store paths and import them on the remote machine.
|
||||
if (scalar @missing > 0) {
|
||||
print STDERR "copying these missing paths:\n";
|
||||
print STDERR " $_\n" foreach @missing;
|
||||
my $extraOpts = "";
|
||||
$extraOpts .= "--sign" if $sign == 1;
|
||||
system("nix-store --export $extraOpts @missing | $compressor | ssh @sshOpts $sshHost '$decompressor | nix-store --import'") == 0
|
||||
system("nix-store --export $extraOpts @missing $compressor | ssh $sshHost @sshOpts '$decompressor nix-store --import'") == 0
|
||||
or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
|
||||
@@ -112,15 +104,11 @@ else { # Copy FROM the remote machine.
|
||||
"ssh @sshOpts $sshHost nix-store --query --requisites @storePaths|") or die;
|
||||
|
||||
my @allStorePaths;
|
||||
my %storePathsSeen;
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
if (!defined $storePathsSeen{$_}) {
|
||||
push @allStorePaths, $_;
|
||||
$storePathsSeen{$_} = 1;
|
||||
}
|
||||
push @allStorePaths, $_;
|
||||
}
|
||||
|
||||
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
|
||||
@@ -131,7 +119,6 @@ else { # Copy FROM the remote machine.
|
||||
my @missing = ();
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
print STDERR "local machine needs $_\n";
|
||||
push @missing, $_;
|
||||
}
|
||||
close READ or die;
|
||||
@@ -139,10 +126,12 @@ else { # Copy FROM the remote machine.
|
||||
|
||||
# Export the store paths on the remote machine and import them on locally.
|
||||
if (scalar @missing > 0) {
|
||||
print STDERR "copying these missing paths:\n";
|
||||
print STDERR " $_\n" foreach @missing;
|
||||
my $extraOpts = "";
|
||||
$extraOpts .= "--sign" if $sign == 1;
|
||||
system("ssh @sshOpts $sshHost 'nix-store --export $extraOpts @missing | $compressor' | $decompressor | @bindir@/nix-store --import") == 0
|
||||
or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||
system("ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor @bindir@/nix-store --import") == 0
|
||||
or die "copying store paths from remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
51
scripts/nix-http-export.cgi.in
Executable file
51
scripts/nix-http-export.cgi.in
Executable file
@@ -0,0 +1,51 @@
|
||||
#! /bin/sh
|
||||
|
||||
export HOME=/tmp
|
||||
export NIX_REMOTE=daemon
|
||||
|
||||
TMP_DIR="${TMP_DIR:-/tmp/nix-export}"
|
||||
|
||||
@coreutils@/mkdir -p "$TMP_DIR" || true
|
||||
@coreutils@/chmod a+r "$TMP_DIR"
|
||||
|
||||
needed_path="?$QUERY_STRING"
|
||||
needed_path="${needed_path#*[?&]needed_path=}"
|
||||
needed_path="${needed_path%%&*}"
|
||||
#needed_path="$(echo $needed_path | ./unhttp)"
|
||||
needed_path="${needed_path//%2B/+}"
|
||||
needed_path="${needed_path//%3D/=}"
|
||||
|
||||
echo needed_path: "$needed_path" >&2
|
||||
|
||||
NIX_STORE="${NIX_STORE_DIR:-/nix/store}"
|
||||
|
||||
echo NIX_STORE: "${NIX_STORE}" >&2
|
||||
|
||||
full_path="${NIX_STORE}"/"$needed_path"
|
||||
|
||||
if [ "$needed_path" != "${needed_path%.drv}" ]; then
|
||||
echo "Status: 403 You should create the derivation file yourself"
|
||||
echo "Content-Type: text/plain"
|
||||
echo
|
||||
echo "Refusing to disclose derivation contents"
|
||||
exit
|
||||
fi
|
||||
|
||||
if @bindir@/nix-store --check-validity "$full_path"; then
|
||||
if ! [ -e nix-export/"$needed_path".nar.gz ]; then
|
||||
@bindir@/nix-store --export "$full_path" | @gzip@ > "$TMP_DIR"/"$needed_path".nar.gz
|
||||
@coreutils@/ln -fs "$TMP_DIR"/"$needed_path".nar.gz nix-export/"$needed_path".nar.gz
|
||||
fi;
|
||||
echo "Status: 301 Moved"
|
||||
echo "Location: nix-export/"$needed_path".nar.gz"
|
||||
echo
|
||||
else
|
||||
echo "Status: 404 No such path found"
|
||||
echo "Content-Type: text/plain"
|
||||
echo
|
||||
echo "Path not found:"
|
||||
echo "$needed_path"
|
||||
echo "checked:"
|
||||
echo "$full_path"
|
||||
fi
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
|
||||
sub usageError {
|
||||
print STDERR <<EOF;
|
||||
@@ -59,7 +61,7 @@ if ($interactive && !defined $ENV{"NIX_HAVE_TERMINAL"}) {
|
||||
$ENV{"NIX_HAVE_TERMINAL"} = "1";
|
||||
$ENV{"LD_LIBRARY_PATH"} = "";
|
||||
foreach my $term ("xterm", "konsole", "gnome-terminal", "xterm") {
|
||||
exec($term, "-e", "@bindir@/nix-install-package", @ARGV);
|
||||
exec($term, "-e", "$binDir/nix-install-package", @ARGV);
|
||||
}
|
||||
die "cannot execute `xterm'";
|
||||
}
|
||||
@@ -121,13 +123,18 @@ if ($interactive) {
|
||||
}
|
||||
|
||||
|
||||
# Store the manifest in the temporary directory so that we don't
|
||||
# pollute /nix/var/nix/manifests.
|
||||
$ENV{NIX_MANIFESTS_DIR} = $tmpDir;
|
||||
|
||||
|
||||
print "\nPulling manifests...\n";
|
||||
system("@bindir@/nix-pull", $manifestURL) == 0
|
||||
system("$binDir/nix-pull", $manifestURL) == 0
|
||||
or barf "nix-pull failed: $?";
|
||||
|
||||
|
||||
print "\nInstalling package...\n";
|
||||
system("@bindir@/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
|
||||
system("$binDir/nix-env", "--install", $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
|
||||
or barf "nix-env failed: $?";
|
||||
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#! @perl@ -w
|
||||
|
||||
# This tool computes the closure of a path (using "nix-store --query
|
||||
# --requisites") and puts the contents of each path in the closure in
|
||||
# a big NAR archive that can be installed on another Nix installation
|
||||
# using "nix-unpack-closure".
|
||||
|
||||
# TODO: make this program "streamy", i.e., don't use a temporary
|
||||
# directory.
|
||||
|
||||
use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
my $tmpDir = tempdir("nix-pack-closure.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
mkdir "$tmpDir/contents", 0755 or die;
|
||||
mkdir "$tmpDir/references", 0755 or die;
|
||||
mkdir "$tmpDir/derivers", 0755 or die;
|
||||
|
||||
open TOPLEVEL, ">$tmpDir/top-level" or die;
|
||||
|
||||
|
||||
my %storePaths;
|
||||
|
||||
|
||||
while (@ARGV) {
|
||||
my $storePath = shift @ARGV;
|
||||
|
||||
# $storePath might be a symlink to the store, so resolve it.
|
||||
$storePath = (`$binDir/nix-store --query --resolve '$storePath'`
|
||||
or die "cannot resolve `$storePath'");
|
||||
chomp $storePath;
|
||||
print TOPLEVEL $storePath, "\n";
|
||||
|
||||
# Get the closure of this path.
|
||||
my $pid = open(READ,
|
||||
"$binDir/nix-store --query --requisites '$storePath'|") or die;
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
$storePaths{$_} = "";
|
||||
}
|
||||
|
||||
close READ or die "nix-store failed: $?";
|
||||
}
|
||||
|
||||
|
||||
close TOPLEVEL or die;
|
||||
|
||||
|
||||
foreach my $storePath (sort(keys %storePaths)) {
|
||||
print STDERR "packing `$storePath'...\n";
|
||||
|
||||
$storePath =~ /\/([^\/]+)$/;
|
||||
my $name = $1;
|
||||
|
||||
system("$binDir/nix-store --dump '$storePath' > $tmpDir/contents/$name") == 0
|
||||
or die "nix-store --dump failed on `$storePath': $?";
|
||||
|
||||
system("$binDir/nix-store --query --references '$storePath' > $tmpDir/references/$name") == 0
|
||||
or die "nix-store --query --references failed on `$storePath': $?";
|
||||
|
||||
system("$binDir/nix-store --query --deriver '$storePath' > $tmpDir/derivers/$name") == 0
|
||||
or die "nix-store --query --deriver failed on `$storePath': $?";
|
||||
}
|
||||
|
||||
|
||||
# Write a NAR archive of everything to standard output.
|
||||
system("nix-store --dump '$tmpDir'") == 0
|
||||
or die "nix-store --dump failed";
|
||||
@@ -21,7 +21,10 @@ if test -z "$url"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
name=$(basename "$url")
|
||||
# Handle escaped characters in the URI. `+', `=' and `?' are the only
|
||||
# characters that are valid in Nix store path names but have a special
|
||||
# meaning in URIs.
|
||||
name=$(basename "$url" | @sed@ -e 's/%2b/+/g' -e 's/%3d/=/g' -e 's/%3f/\?/g')
|
||||
if test -z "$name"; then echo "invalid url"; exit 1; fi
|
||||
|
||||
|
||||
@@ -36,19 +39,62 @@ if test -n "$expHash"; then
|
||||
fi
|
||||
|
||||
|
||||
mkTempDir() {
|
||||
if test -n "$tmpPath"; then return; fi
|
||||
local i=0
|
||||
while true; do
|
||||
if test -z "$TMPDIR"; then TMPDIR=/tmp; fi
|
||||
tmpPath=$TMPDIR/nix-prefetch-url-$$-$i
|
||||
if mkdir "$tmpPath"; then break; fi
|
||||
# !!! to bad we can't check for ENOENT in mkdir, so this check
|
||||
# is slightly racy (it bombs out if somebody just removed
|
||||
# $tmpPath...).
|
||||
if ! test -e "$tmpPath"; then exit 1; fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
trap removeTempDir EXIT SIGINT SIGQUIT
|
||||
}
|
||||
|
||||
removeTempDir() {
|
||||
if test -n "$tmpPath"; then
|
||||
rm -rf "$tmpPath" || true
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
doDownload() {
|
||||
@curl@ $cacheFlags --fail -# --location --max-redirs 20 --disable-epsv \
|
||||
@curl@ $cacheFlags --fail --location --max-redirs 20 --disable-epsv \
|
||||
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
|
||||
}
|
||||
|
||||
|
||||
# Hack to support the mirror:// scheme from Nixpkgs.
|
||||
if test "${url:0:9}" = "mirror://"; then
|
||||
if test -z "$NIXPKGS_ALL"; then
|
||||
echo "Resolving mirror:// URLs requires Nixpkgs. Please point \$NIXPKGS_ALL at a Nixpkgs tree." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkTempDir
|
||||
nix-build "$NIXPKGS_ALL" -A resolveMirrorURLs --argstr url "$url" -o $tmpPath/urls > /dev/null
|
||||
|
||||
expanded=($(cat $tmpPath/urls))
|
||||
if test "${#expanded[*]}" = 0; then
|
||||
echo "$0: cannot resolve $url." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$url expands to ${expanded[*]} (using ${expanded[0]})" >&2
|
||||
url="${expanded[0]}"
|
||||
fi
|
||||
|
||||
|
||||
# If we don't know the hash or a file with that hash doesn't exist,
|
||||
# download the file and add it to the store.
|
||||
if test -z "$finalPath"; then
|
||||
|
||||
tmpPath=/tmp/nix-prefetch-url-$$ # !!! security?
|
||||
mkTempDir
|
||||
tmpFile=$tmpPath/$name
|
||||
mkdir $tmpPath # !!! retry if tmpPath already exists
|
||||
|
||||
# Optionally do timestamp-based caching of the download.
|
||||
# Actually, the only thing that we cache in $NIX_DOWNLOAD_CACHE is
|
||||
@@ -57,7 +103,7 @@ if test -z "$finalPath"; then
|
||||
# garbage-collected independently.
|
||||
if test -n "$NIX_DOWNLOAD_CACHE"; then
|
||||
echo -n "$url" > $tmpPath/url
|
||||
urlHash=$(nix-hash --type sha256 --base32 --flat $tmpPath/url)
|
||||
urlHash=$(@bindir@/nix-hash --type sha256 --base32 --flat $tmpPath/url)
|
||||
echo "$url" > "$NIX_DOWNLOAD_CACHE/$urlHash.url"
|
||||
cachedHashFN="$NIX_DOWNLOAD_CACHE/$urlHash.$hashType"
|
||||
cachedTimestampFN="$NIX_DOWNLOAD_CACHE/$urlHash.stamp"
|
||||
@@ -98,8 +144,6 @@ if test -z "$finalPath"; then
|
||||
# Add the downloaded file to the Nix store.
|
||||
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
|
||||
|
||||
if test -n "$tmpPath"; then rm -rf $tmpPath || true; fi
|
||||
|
||||
if test -n "$expHash" -a "$expHash" != "$hash"; then
|
||||
echo "hash mismatch for URL \`$url'" >&2
|
||||
exit 1
|
||||
|
||||
@@ -7,5 +7,12 @@ if test -n "$HOME"; then
|
||||
@coreutils@/ln -s "$_NIX_DEF_LINK" "$NIX_LINK"
|
||||
fi
|
||||
|
||||
export PATH=$NIX_LINK/bin:@prefix@/bin:$PATH
|
||||
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
|
||||
|
||||
@@ -7,23 +7,23 @@ use readmanifest;
|
||||
my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
my $libexecDir = $ENV{"NIX_LIBEXEC_DIR"};
|
||||
$libexecDir = "@libexecdir@" unless defined $libexecDir;
|
||||
|
||||
my $stateDir = $ENV{"NIX_STATE_DIR"};
|
||||
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
|
||||
|
||||
my $storeDir = $ENV{"NIX_STORE_DIR"};
|
||||
$storeDir = "@storedir@" unless defined $storeDir;
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
my $libexecDir = ($ENV{"NIX_LIBEXEC_DIR"} or "@libexecdir@");
|
||||
my $storeDir = ($ENV{"NIX_STORE_DIR"} or "@storedir@");
|
||||
my $stateDir = ($ENV{"NIX_STATE_DIR"} or "@localstatedir@/nix");
|
||||
my $manifestDir = ($ENV{"NIX_MANIFESTS_DIR"} or "$stateDir/manifests");
|
||||
|
||||
|
||||
# Prevent access problems in shared-stored installations.
|
||||
umask 0022;
|
||||
|
||||
|
||||
# Create the manifests directory if it doesn't exist.
|
||||
if (! -e $manifestDir) {
|
||||
mkdir $manifestDir, 0755 or die "cannot create directory `$manifestDir'";
|
||||
}
|
||||
|
||||
|
||||
# Process the URLs specified on the command line.
|
||||
my %narFiles;
|
||||
my %localPaths;
|
||||
@@ -51,7 +51,7 @@ sub processURL {
|
||||
|
||||
# First see if a bzipped manifest is available.
|
||||
if (system("@curl@ --fail --silent --head '$url'.bz2 > /dev/null") == 0) {
|
||||
print "obtaining list of Nix archives at `$url.bz2'...\n";
|
||||
print "fetching list of Nix archives at `$url.bz2'...\n";
|
||||
my $bzipped = downloadFile "$url.bz2";
|
||||
|
||||
$manifest = "$tmpDir/MANIFEST";
|
||||
@@ -69,10 +69,11 @@ sub processURL {
|
||||
print "obtaining list of Nix archives at `$url'...\n";
|
||||
$manifest = downloadFile $url;
|
||||
}
|
||||
|
||||
my $version = readManifest($manifest, \%narFiles, \%localPaths, \%patches);
|
||||
|
||||
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
|
||||
die "`$url' is not manifest or it is too old (i.e., for Nix <= 0.7)\n";
|
||||
}
|
||||
die "`$url' is not a manifest or it is too old (i.e., for Nix <= 0.7)\n" if $version < 3;
|
||||
die "manifest `$url' is too new\n" if $version >= 5;
|
||||
|
||||
if ($skipWrongStore) {
|
||||
foreach my $path (keys %narFiles) {
|
||||
@@ -91,11 +92,31 @@ sub processURL {
|
||||
my $hash = `$binDir/nix-hash --flat '$manifest'`
|
||||
or die "cannot hash `$manifest'";
|
||||
chomp $hash;
|
||||
|
||||
my $urlFile = "$manifestDir/$baseName-$hash.url";
|
||||
open URL, ">$urlFile" or die "cannot create `$urlFile'";
|
||||
print URL "$url";
|
||||
close URL;
|
||||
|
||||
my $finalPath = "$stateDir/manifests/$baseName-$hash.nixmanifest";
|
||||
|
||||
system("@coreutils@/ln", "-sfn", "$manifest", "$finalPath") == 0
|
||||
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 $url eq $url2;
|
||||
my $base = $urlFile2; $base =~ s/.url$//;
|
||||
unlink "${base}.url";
|
||||
unlink "${base}.nixmanifest";
|
||||
}
|
||||
}
|
||||
|
||||
while (@ARGV) {
|
||||
|
||||
@@ -16,8 +16,7 @@ my $curl = "@curl@ --fail --silent";
|
||||
my $extraCurlFlags = ${ENV{'CURL_FLAGS'}};
|
||||
$curl = "$curl $extraCurlFlags" if defined $extraCurlFlags;
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@";
|
||||
|
||||
my $dataDir = $ENV{"NIX_DATA_DIR"};
|
||||
$dataDir = "@datadir@" unless defined $dataDir;
|
||||
@@ -107,7 +106,7 @@ foreach my $storePath (@storePaths) {
|
||||
# Construct a Nix expression that creates a Nix archive.
|
||||
my $nixexpr =
|
||||
"((import $dataDir/nix/corepkgs/nar/nar.nix) " .
|
||||
"{storePath = builtins.toPath \"$storePath\"; system = \"@system@\"; hashAlgo = \"$hashAlgo\";}) ";
|
||||
"{storePath = builtins.storePath \"$storePath\"; system = \"@system@\"; hashAlgo = \"$hashAlgo\";}) ";
|
||||
|
||||
print NIX $nixexpr;
|
||||
}
|
||||
@@ -116,9 +115,9 @@ print NIX "]";
|
||||
close NIX;
|
||||
|
||||
|
||||
# Instantiate store expressions from the Nix expression.
|
||||
# Instantiate store derivations from the Nix expression.
|
||||
my @storeExprs;
|
||||
print STDERR "instantiating store expressions...\n";
|
||||
print STDERR "instantiating store derivations...\n";
|
||||
my $pid = open(READ, "$binDir/nix-instantiate $nixExpr|")
|
||||
or die "cannot run nix-instantiate";
|
||||
while (<READ>) {
|
||||
@@ -129,7 +128,7 @@ while (<READ>) {
|
||||
close READ or die "nix-instantiate failed: $?";
|
||||
|
||||
|
||||
# Realise the store expressions.
|
||||
# Build the derivations.
|
||||
print STDERR "creating archives...\n";
|
||||
|
||||
my @narPaths;
|
||||
@@ -141,11 +140,6 @@ while (scalar @tmp > 0) {
|
||||
my @tmp2 = @tmp[0..$n - 1];
|
||||
@tmp = @tmp[$n..scalar @tmp - 1];
|
||||
|
||||
# Note: we disable build hooks because of the impure path
|
||||
# reference (see above). Even if that is fixed, using a hook
|
||||
# probably wouldn't make that much sense; pumping lots of data
|
||||
# around just to compress them won't gain that much.
|
||||
$ENV{"NIX_BUILD_HOOK"} = "";
|
||||
my $pid = open(READ, "$binDir/nix-store --realise @tmp2|")
|
||||
or die "cannot run nix-store";
|
||||
while (<READ>) {
|
||||
@@ -224,13 +218,14 @@ writeManifest $manifest, \%narFiles, \%patches;
|
||||
sub copyFile {
|
||||
my $src = shift;
|
||||
my $dst = shift;
|
||||
system("@coreutils@/cp", $src, "$dst.tmp") == 0 or die "cannot copy file";
|
||||
rename("$dst.tmp", "$dst") or die "cannot rename file";
|
||||
my $tmp = "$dst.tmp.$$";
|
||||
system("@coreutils@/cp", $src, $tmp) == 0 or die "cannot copy file";
|
||||
rename($tmp, $dst) or die "cannot rename file: $!";
|
||||
}
|
||||
|
||||
|
||||
# Upload the archives.
|
||||
print STDERR "uploading archives...\n";
|
||||
# Upload/copy the archives.
|
||||
print STDERR "uploading/copying archives...\n";
|
||||
|
||||
sub archiveExists {
|
||||
my $name = shift;
|
||||
@@ -244,9 +239,12 @@ foreach my $narArchive (@narArchives) {
|
||||
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, "$localArchivesDir/$basename";
|
||||
copyFile $narArchive, $dst;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
171
scripts/nix-reduce-build.in
Normal file
171
scripts/nix-reduce-build.in
Normal file
@@ -0,0 +1,171 @@
|
||||
#! @shell@
|
||||
|
||||
WORKING_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}"/nix-reduce-build-XXXXXX);
|
||||
cd "$WORKING_DIRECTORY";
|
||||
|
||||
if test -z "$1" || test "a--help" = "a$1" ; then
|
||||
echo 'nix-reduce-build (paths or Nix expressions) -- (package sources)' >&2
|
||||
echo As in: >&2
|
||||
echo nix-reduce-build /etc/nixos/nixos -- ssh://user@somewhere.nowhere.example.org >&2
|
||||
echo nix-reduce-build /etc/nixos/nixos -- \\
|
||||
echo " " \''http://somewhere.nowhere.example.org/nix/nix-http-export.cgi?needed_path='\' >&2
|
||||
echo " store path name will be added into the end of the URL" >&2
|
||||
echo nix-reduce-build /etc/nixos/nixos -- file://home/user/nar/ >&2
|
||||
echo " that should be a directory where gzipped 'nix-store --export' ">&2
|
||||
echo " files are located (they should have .nar.gz extension)" >&2
|
||||
echo " Or all together: " >&2
|
||||
echo -e nix-reduce-build /expr.nix /e2.nix -- \\\\\\\n\
|
||||
" ssh://a@b.example.com http://n.example.com/get-nar?q= file://nar/" >&2
|
||||
echo " Also supports best-effort local builds of failing expression set:" >&2
|
||||
echo "nix-reduce-build /e.nix -- nix-daemon:// nix-self://" >&2
|
||||
echo " nix-daemon:// builds using daemon"
|
||||
echo " nix-self:// builds directly using nix-store from current installation" >&2
|
||||
echo " nix-daemon-fixed:// and nix-self-fixed:// do the same, but only for" >&2;
|
||||
echo "derivations with specified output hash (sha256, sha1 or md5)." >&2
|
||||
echo " nix-daemon-substitute:// and nix-self-substitute:// try to substitute" >&2;
|
||||
echo "maximum amount of paths" >&2;
|
||||
echo " nix-daemon-build:// and nix-self-build:// try to build (not substitute)" >&2;
|
||||
echo "maximum amount of paths" >&2;
|
||||
echo " If no package sources are specified, required paths are listed." >&2;
|
||||
exit;
|
||||
fi;
|
||||
|
||||
while ! test "$1" = "--" || test "$1" = "" ; do
|
||||
echo "$1" >> initial; >&2
|
||||
shift;
|
||||
done
|
||||
shift;
|
||||
echo Will work on $(cat initial | wc -l) targets. >&2
|
||||
|
||||
while read ; do
|
||||
case "$REPLY" in
|
||||
${NIX_STORE_DIR:-/nix/store}/*)
|
||||
echo "$REPLY" >> paths; >&2
|
||||
;;
|
||||
*)
|
||||
(
|
||||
IFS=: ;
|
||||
nix-instantiate $REPLY >> paths;
|
||||
);
|
||||
;;
|
||||
esac;
|
||||
done < initial;
|
||||
echo Proceeding $(cat paths | wc -l) paths. >&2
|
||||
|
||||
while read; do
|
||||
case "$REPLY" in
|
||||
*.drv)
|
||||
echo "$REPLY" >> derivers; >&2
|
||||
;;
|
||||
*)
|
||||
nix-store --query --deriver "$REPLY" >>derivers;
|
||||
;;
|
||||
esac;
|
||||
done < paths;
|
||||
echo Found $(cat derivers | wc -l) derivers. >&2
|
||||
|
||||
cat derivers | xargs nix-store --query -R > derivers-closure;
|
||||
echo Proceeding at most $(cat derivers-closure | wc -l) derivers. >&2
|
||||
|
||||
cat derivers-closure | egrep '[.]drv$' | xargs nix-store --query --outputs > wanted-paths;
|
||||
cat derivers-closure | egrep -v '[.]drv$' >> wanted-paths;
|
||||
echo Prepared $(cat wanted-paths | wc -l) paths to get. >&2
|
||||
|
||||
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
|
||||
echo We need $(cat needed-paths | wc -l) paths. >&2
|
||||
|
||||
egrep '[.]drv$' derivers-closure > critical-derivers;
|
||||
|
||||
if test -z "$1" ; then
|
||||
cat needed-paths;
|
||||
fi;
|
||||
|
||||
refresh_critical_derivers() {
|
||||
echo "Finding needed derivers..." >&2;
|
||||
cat critical-derivers | while read; do
|
||||
if ! (nix-store --query --outputs "$REPLY" | xargs nix-store --check-validity &> /dev/null;); then
|
||||
echo "$REPLY";
|
||||
fi;
|
||||
done > new-critical-derivers;
|
||||
mv new-critical-derivers critical-derivers;
|
||||
echo The needed paths are realized by $(cat critical-derivers | wc -l) derivers. >&2
|
||||
}
|
||||
|
||||
build_here() {
|
||||
cat critical-derivers | while read; do
|
||||
echo "Realising $REPLY using nix-daemon" >&2
|
||||
@bindir@/nix-store -r "${REPLY}"
|
||||
done;
|
||||
}
|
||||
|
||||
try_to_substitute(){
|
||||
cat needed-paths | while read ; do
|
||||
echo "Building $REPLY using nix-daemon" >&2
|
||||
@bindir@/nix-store -r "${NIX_STORE_DIR:-/nix/store}/${REPLY##*/}"
|
||||
done;
|
||||
}
|
||||
|
||||
for i in "$@"; do
|
||||
sshHost="${i#ssh://}";
|
||||
httpHost="${i#http://}";
|
||||
httpsHost="${i#https://}";
|
||||
filePath="${i#file:/}";
|
||||
if [ "$i" != "$sshHost" ]; then
|
||||
cat needed-paths | while read; do
|
||||
echo "Getting $REPLY and its closure over ssh" >&2
|
||||
nix-copy-closure --from "$sshHost" --gzip "$REPLY" </dev/null || true;
|
||||
done;
|
||||
elif [ "$i" != "$httpHost" ] || [ "$i" != "$httpsHost" ]; then
|
||||
cat needed-paths | while read; do
|
||||
echo "Getting $REPLY over http/https" >&2
|
||||
curl ${BAD_CERTIFICATE:+-k} -L "$i${REPLY##*/}" | gunzip | nix-store --import;
|
||||
done;
|
||||
elif [ "$i" != "$filePath" ] ; then
|
||||
cat needed-paths | while read; do
|
||||
echo "Installing $REPLY from file" >&2
|
||||
gunzip < "$filePath/${REPLY##*/}".nar.gz | nix-store --import;
|
||||
done;
|
||||
elif [ "$i" = "nix-daemon://" ] ; then
|
||||
NIX_REMOTE=daemon try_to_substitute;
|
||||
refresh_critical_derivers;
|
||||
NIX_REMOTE=daemon build_here;
|
||||
elif [ "$i" = "nix-self://" ] ; then
|
||||
NIX_REMOTE= try_to_substitute;
|
||||
refresh_critical_derivers;
|
||||
NIX_REMOTE= build_here;
|
||||
elif [ "$i" = "nix-daemon-fixed://" ] ; then
|
||||
refresh_critical_derivers;
|
||||
|
||||
cat critical-derivers | while read; do
|
||||
if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then
|
||||
echo "Realising $REPLY using nix-daemon" >&2
|
||||
NIX_REMOTE=daemon @bindir@/nix-store -r "${REPLY}"
|
||||
fi;
|
||||
done;
|
||||
elif [ "$i" = "nix-self-fixed://" ] ; then
|
||||
refresh_critical_derivers;
|
||||
|
||||
cat critical-derivers | while read; do
|
||||
if egrep '"(md5|sha1|sha256)"' "$REPLY" &>/dev/null; then
|
||||
echo "Realising $REPLY using direct Nix build" >&2
|
||||
NIX_REMOTE= @bindir@/nix-store -r "${REPLY}"
|
||||
fi;
|
||||
done;
|
||||
elif [ "$i" = "nix-daemon-substitute://" ] ; then
|
||||
NIX_REMOTE=daemon try_to_substitute;
|
||||
elif [ "$i" = "nix-self-substitute://" ] ; then
|
||||
NIX_REMOTE= try_to_substitute;
|
||||
elif [ "$i" = "nix-daemon-build://" ] ; then
|
||||
refresh_critical_derivers;
|
||||
NIX_REMOTE=daemon build_here;
|
||||
elif [ "$i" = "nix-self-build://" ] ; then
|
||||
refresh_critical_derivers;
|
||||
NIX_REMOTE= build_here;
|
||||
fi;
|
||||
mv needed-paths wanted-paths;
|
||||
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
|
||||
echo We still need $(cat needed-paths | wc -l) paths. >&2
|
||||
done;
|
||||
|
||||
cd /
|
||||
rm -r "$WORKING_DIRECTORY"
|
||||
@@ -1,88 +0,0 @@
|
||||
#! @perl@ -w
|
||||
|
||||
# This tool unpacks the closures created by "nix-pack-closure" and
|
||||
# adds them to the Nix store.
|
||||
|
||||
# TODO: make this program "streamy", i.e., don't use a temporary
|
||||
# directory.
|
||||
|
||||
use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
my $tmpDir = tempdir("nix-unpack-closure.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
|
||||
# Unpack the NAR archive on standard input.
|
||||
system("nix-store --restore '$tmpDir/unpacked'") == 0
|
||||
or die "nix-store --restore failed";
|
||||
|
||||
|
||||
open VALID, ">$tmpDir/validity" or die;
|
||||
|
||||
|
||||
# For each path in the closure that is not yet valid, add it to the
|
||||
# store. TODO: use proper locking. Or even better, let nix-store do
|
||||
# this.
|
||||
opendir(DIR, "$tmpDir/unpacked/contents") or die "cannot open directory: $!";
|
||||
|
||||
foreach my $name (sort(readdir DIR)) {
|
||||
next if $name eq "." or $name eq "..";
|
||||
|
||||
my $storePath = "@storedir@/$name"; # !!!
|
||||
|
||||
# !!! this really isn't a good validity check!
|
||||
system "$binDir/nix-store --check-validity '$storePath' 2> /dev/null";
|
||||
if ($? != 0) {
|
||||
print STDERR "unpacking `$storePath'...\n";
|
||||
|
||||
# !!! race
|
||||
system("@coreutils@/rm -rf '$storePath'") == 0
|
||||
or die "cannot remove `$storePath': $?";
|
||||
|
||||
system("$binDir/nix-store --restore '$storePath' < '$tmpDir/unpacked/contents/$name'") == 0
|
||||
or die "nix-store --dump failed on `$storePath': $?";
|
||||
|
||||
print VALID "$storePath\n";
|
||||
|
||||
open DRV, "<$tmpDir/unpacked/derivers/$name" or die;
|
||||
my $deriver = <DRV>;
|
||||
chomp $deriver;
|
||||
$deriver = "" if $deriver eq "unknown-deriver";
|
||||
close DRV;
|
||||
|
||||
my @refs;
|
||||
open REFS, "<$tmpDir/unpacked/references/$name" or die;
|
||||
while (<REFS>) {
|
||||
chomp;
|
||||
push @refs, $_;
|
||||
}
|
||||
close REFS;
|
||||
|
||||
print VALID "$deriver\n";
|
||||
|
||||
print VALID (scalar @refs), "\n";
|
||||
foreach my $ref (@refs) {
|
||||
print VALID "$ref\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(DIR) or die;
|
||||
|
||||
|
||||
# Register the invalid paths as valid.
|
||||
system("nix-store --register-validity <'$tmpDir/validity'") == 0
|
||||
or die "nix-store --register-validity failed";
|
||||
|
||||
|
||||
# Show the top-level paths so that something useful can be done with
|
||||
# them, e.g., passing them to `nix-env -i'.
|
||||
if (-e "$tmpDir/unpacked/top-level") {
|
||||
open TOPLEVEL, "<$tmpDir/unpacked/top-level" or die;
|
||||
while (<TOPLEVEL>) { print "$_"; }
|
||||
close TOPLEVEL;
|
||||
}
|
||||
@@ -2,10 +2,7 @@ use strict;
|
||||
|
||||
|
||||
sub addPatch {
|
||||
my $patches = shift;
|
||||
my $storePath = shift;
|
||||
my $patch = shift;
|
||||
my $allowConflicts = shift;
|
||||
my ($patches, $storePath, $patch) = @_;
|
||||
|
||||
$$patches{$storePath} = []
|
||||
unless defined $$patches{$storePath};
|
||||
@@ -14,15 +11,9 @@ sub addPatch {
|
||||
|
||||
my $found = 0;
|
||||
foreach my $patch2 (@{$patchList}) {
|
||||
if ($patch2->{url} eq $patch->{url}) {
|
||||
if ($patch2->{hash} eq $patch->{hash}) {
|
||||
$found = 1 if ($patch2->{basePath} eq $patch->{basePath});
|
||||
} else {
|
||||
die "conflicting hashes for URL $patch->{url}, " .
|
||||
"namely $patch2->{hash} and $patch->{hash}"
|
||||
unless $allowConflicts;
|
||||
}
|
||||
}
|
||||
$found = 1 if
|
||||
$patch2->{url} eq $patch->{url} &&
|
||||
$patch2->{basePath} eq $patch->{basePath};
|
||||
}
|
||||
|
||||
push @{$patchList}, $patch if !$found;
|
||||
@@ -32,12 +23,7 @@ sub addPatch {
|
||||
|
||||
|
||||
sub readManifest {
|
||||
my $manifest = shift;
|
||||
my $narFiles = shift;
|
||||
my $localPaths = shift;
|
||||
my $patches = shift;
|
||||
my $allowConflicts = shift;
|
||||
$allowConflicts = 0 unless defined $allowConflicts;
|
||||
my ($manifest, $narFiles, $localPaths, $patches) = @_;
|
||||
|
||||
open MANIFEST, "<$manifest"
|
||||
or die "cannot open `$manifest': $!";
|
||||
@@ -98,15 +84,7 @@ sub readManifest {
|
||||
|
||||
my $found = 0;
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
if ($narFile->{url} eq $url) {
|
||||
if ($narFile->{hash} eq $hash) {
|
||||
$found = 1;
|
||||
} else {
|
||||
die "conflicting hashes for URL $url, " .
|
||||
"namely $narFile->{hash} and $hash"
|
||||
unless $allowConflicts;
|
||||
}
|
||||
}
|
||||
$found = 1 if $narFile->{url} eq $url;
|
||||
}
|
||||
if (!$found) {
|
||||
push @{$narFileList},
|
||||
@@ -124,7 +102,7 @@ sub readManifest {
|
||||
, basePath => $basePath, baseHash => $baseHash
|
||||
, narHash => $narHash, patchType => $patchType
|
||||
, hashAlgo => $hashAlgo
|
||||
}, $allowConflicts;
|
||||
};
|
||||
}
|
||||
|
||||
elsif ($type eq "localPath") {
|
||||
@@ -171,12 +149,8 @@ sub readManifest {
|
||||
}
|
||||
|
||||
|
||||
sub writeManifest
|
||||
{
|
||||
my $manifest = shift;
|
||||
my $narFiles = shift;
|
||||
my $patches = shift;
|
||||
my $copySources = shift;
|
||||
sub writeManifest {
|
||||
my ($manifest, $narFiles, $patches) = @_;
|
||||
|
||||
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
|
||||
|
||||
@@ -190,9 +164,9 @@ sub writeManifest
|
||||
print MANIFEST "{\n";
|
||||
print MANIFEST " StorePath: $storePath\n";
|
||||
print MANIFEST " NarURL: $narFile->{url}\n";
|
||||
print MANIFEST " Hash: $narFile->{hash}\n";
|
||||
print MANIFEST " Hash: $narFile->{hash}\n" if defined $narFile->{hash};
|
||||
print MANIFEST " NarHash: $narFile->{narHash}\n";
|
||||
print MANIFEST " Size: $narFile->{size}\n";
|
||||
print MANIFEST " Size: $narFile->{size}\n" if defined $narFile->{size};
|
||||
print MANIFEST " References: $narFile->{references}\n"
|
||||
if defined $narFile->{references} && $narFile->{references} ne "";
|
||||
print MANIFEST " Deriver: $narFile->{deriver}\n"
|
||||
|
||||
47
scripts/ssh.pm
Normal file
47
scripts/ssh.pm
Normal file
@@ -0,0 +1,47 @@
|
||||
use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
|
||||
our @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
|
||||
|
||||
my $sshStarted = 0;
|
||||
my $sshHost;
|
||||
|
||||
# Open a master SSH connection to `host', unless there already is a
|
||||
# running master connection (as determined by `-O check').
|
||||
sub openSSHConnection {
|
||||
my ($host) = @_;
|
||||
die if $sshStarted;
|
||||
$sshHost = $host;
|
||||
return 1 if system("ssh $sshHost @sshOpts -O check 2> /dev/null") == 0;
|
||||
|
||||
my $tmpDir = tempdir("nix-ssh.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
push @sshOpts, "-S", "$tmpDir/control";
|
||||
|
||||
# Start the master. We can't use the `-f' flag (fork into
|
||||
# background after establishing the connection) because then the
|
||||
# child continues to run if we are killed. So instead make SSH
|
||||
# print "started" when it has established the connection, and wait
|
||||
# until we see that.
|
||||
open SSH, "ssh $sshHost @sshOpts -M -N -o LocalCommand='echo started' -o PermitLocalCommand=yes |" or die;
|
||||
while (<SSH>) {
|
||||
chomp;
|
||||
last if /started/;
|
||||
}
|
||||
|
||||
$sshStarted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Tell the master SSH client to exit.
|
||||
sub closeSSHConnection {
|
||||
if ($sshStarted) {
|
||||
system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0
|
||||
or warn "unable to stop SSH master: $?";
|
||||
}
|
||||
}
|
||||
|
||||
END { my $saved = $?; closeSSHConnection; $? = $saved; }
|
||||
|
||||
return 1;
|
||||
@@ -1,5 +1,3 @@
|
||||
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
|
||||
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
|
||||
nix-log2xml bsdiff-4.3
|
||||
|
||||
EXTRA_DIST = aterm-helper.pl
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
# This program generates C/C++ code for efficiently manipulating
|
||||
# ATerms. It generates functions to build and match ATerms according
|
||||
# to a set of constructor definitions defined in a file read from
|
||||
# standard input. A constructor is defined by a line with the
|
||||
# following format:
|
||||
#
|
||||
# SYM | ARGS | TYPE | FUN?
|
||||
#
|
||||
# where SYM is the name of the constructor, ARGS is a
|
||||
# whitespace-separated list of argument types, TYPE is the type of the
|
||||
# resulting ATerm (which should be `ATerm' or a type synonym for
|
||||
# `ATerm'), and the optional FUN is used to construct the names of the
|
||||
# build and match functions (it defaults to SYM; overriding it is
|
||||
# useful if there are overloaded constructors, e.g., with different
|
||||
# arities). Note that SYM may be empty.
|
||||
#
|
||||
# A line of the form
|
||||
#
|
||||
# VAR = EXPR
|
||||
#
|
||||
# causes a ATerm variable to be generated that is initialised to the
|
||||
# value EXPR.
|
||||
#
|
||||
# Finally, a line of the form
|
||||
#
|
||||
# init NAME
|
||||
#
|
||||
# causes the initialisation function to be called `NAME'. This
|
||||
# function must be called before any of the build/match functions or
|
||||
# the generated variables are used.
|
||||
|
||||
die if scalar @ARGV != 2;
|
||||
|
||||
my $syms = "";
|
||||
my $init = "";
|
||||
my $initFun = "init";
|
||||
|
||||
open HEADER, ">$ARGV[0]";
|
||||
open IMPL, ">$ARGV[1]";
|
||||
|
||||
print HEADER "#include <aterm2.h>\n";
|
||||
print HEADER "#ifdef __cplusplus\n";
|
||||
print HEADER "namespace nix {\n";
|
||||
print HEADER "#endif\n\n\n";
|
||||
print IMPL "namespace nix {\n";
|
||||
|
||||
while (<STDIN>) {
|
||||
s/\#.*//;
|
||||
next if (/^\s*$/);
|
||||
|
||||
if (/^\s*(\w*)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) {
|
||||
my $const = $1;
|
||||
my @types = split ' ', $2;
|
||||
my $result = $3;
|
||||
my $funname = $4;
|
||||
$funname = $const unless defined $funname;
|
||||
|
||||
my $formals = "";
|
||||
my $formals2 = "";
|
||||
my $args = "";
|
||||
my $unpack = "";
|
||||
my $n = 1;
|
||||
foreach my $type (@types) {
|
||||
my $realType = $type;
|
||||
$args .= ", ";
|
||||
if ($type eq "string") {
|
||||
# $args .= "(ATerm) ATmakeAppl0(ATmakeAFun((char *) e$n, 0, ATtrue))";
|
||||
# $type = "const char *";
|
||||
$type = "ATerm";
|
||||
$args .= "e$n";
|
||||
# !!! in the matcher, we should check that the
|
||||
# argument is a string (i.e., a nullary application).
|
||||
} elsif ($type eq "int") {
|
||||
$args .= "(ATerm) ATmakeInt(e$n)";
|
||||
} elsif ($type eq "ATermList" || $type eq "ATermBlob") {
|
||||
$args .= "(ATerm) e$n";
|
||||
} else {
|
||||
$args .= "e$n";
|
||||
}
|
||||
$formals .= ", " if $formals ne "";
|
||||
$formals .= "$type e$n";
|
||||
$formals2 .= ", ";
|
||||
$formals2 .= "$type & e$n";
|
||||
my $m = $n - 1;
|
||||
# !!! more checks here
|
||||
if ($type eq "int") {
|
||||
$unpack .= " e$n = ATgetInt((ATermInt) ATgetArgument(e, $m));\n";
|
||||
} elsif ($type eq "ATermList") {
|
||||
$unpack .= " e$n = (ATermList) ATgetArgument(e, $m);\n";
|
||||
} elsif ($type eq "ATermBlob") {
|
||||
$unpack .= " e$n = (ATermBlob) ATgetArgument(e, $m);\n";
|
||||
} elsif ($realType eq "string") {
|
||||
$unpack .= " e$n = ATgetArgument(e, $m);\n";
|
||||
$unpack .= " if (ATgetType(e$n) != AT_APPL) return false;\n";
|
||||
} else {
|
||||
$unpack .= " e$n = ATgetArgument(e, $m);\n";
|
||||
}
|
||||
$n++;
|
||||
}
|
||||
|
||||
my $arity = scalar @types;
|
||||
|
||||
print HEADER "extern AFun sym$funname;\n\n";
|
||||
|
||||
print IMPL "AFun sym$funname = 0;\n";
|
||||
|
||||
if ($arity == 0) {
|
||||
print HEADER "extern ATerm const$funname;\n\n";
|
||||
print IMPL "ATerm const$funname = 0;\n";
|
||||
}
|
||||
|
||||
print HEADER "static inline $result make$funname($formals) __attribute__ ((pure, nothrow));\n";
|
||||
print HEADER "static inline $result make$funname($formals) {\n";
|
||||
if ($arity == 0) {
|
||||
print HEADER " return const$funname;\n";
|
||||
}
|
||||
elsif ($arity <= 6) {
|
||||
print HEADER " return (ATerm) ATmakeAppl$arity(sym$funname$args);\n";
|
||||
} else {
|
||||
$args =~ s/^,//;
|
||||
print HEADER " ATerm array[$arity] = {$args};\n";
|
||||
print HEADER " return (ATerm) ATmakeApplArray(sym$funname, array);\n";
|
||||
}
|
||||
print HEADER "}\n\n";
|
||||
|
||||
print HEADER "#ifdef __cplusplus\n";
|
||||
print HEADER "static inline bool match$funname(ATerm e$formals2) {\n";
|
||||
print HEADER " if (ATgetType(e) != AT_APPL || (AFun) ATgetAFun(e) != sym$funname) return false;\n";
|
||||
print HEADER "$unpack";
|
||||
print HEADER " return true;\n";
|
||||
print HEADER "}\n";
|
||||
print HEADER "#endif\n\n\n";
|
||||
|
||||
$init .= " sym$funname = ATmakeAFun(\"$const\", $arity, ATfalse);\n";
|
||||
$init .= " ATprotectAFun(sym$funname);\n";
|
||||
if ($arity == 0) {
|
||||
$init .= " const$funname = (ATerm) ATmakeAppl0(sym$funname);\n";
|
||||
$init .= " ATprotect(&const$funname);\n";
|
||||
}
|
||||
}
|
||||
|
||||
elsif (/^\s*(\w+)\s*=\s*(.*)$/) {
|
||||
my $name = $1;
|
||||
my $value = $2;
|
||||
print HEADER "extern ATerm $name;\n";
|
||||
print IMPL "ATerm $name = 0;\n";
|
||||
$init .= " $name = $value;\n";
|
||||
}
|
||||
|
||||
elsif (/^\s*init\s+(\w+)\s*$/) {
|
||||
$initFun = $1;
|
||||
}
|
||||
|
||||
else {
|
||||
die "bad line: `$_'";
|
||||
}
|
||||
}
|
||||
|
||||
print HEADER "void $initFun();\n\n";
|
||||
|
||||
print HEADER "static inline const char * aterm2String(ATerm t) {\n";
|
||||
print HEADER " return (const char *) ATgetName(ATgetAFun(t));\n";
|
||||
print HEADER "}\n\n";
|
||||
|
||||
print IMPL "\n";
|
||||
print IMPL "void $initFun() {\n";
|
||||
print IMPL "$init";
|
||||
print IMPL "}\n";
|
||||
|
||||
print HEADER "#ifdef __cplusplus\n";
|
||||
print HEADER "}\n";
|
||||
print HEADER "#endif\n\n\n";
|
||||
print IMPL "}\n";
|
||||
|
||||
close HEADER;
|
||||
close IMPL;
|
||||
@@ -1,3 +1,6 @@
|
||||
noinst_PROGRAMS = bin2c
|
||||
|
||||
bin2c_SOURCES = bin2c.c
|
||||
|
||||
bin2c$(EXEEXT): bin2c.c
|
||||
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -o bin2c bin2c.c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SUBDIRS = format
|
||||
|
||||
pkginclude_HEADERS = assert.hpp checked_delete.hpp format.hpp \
|
||||
nobase_pkginclude_HEADERS = assert.hpp checked_delete.hpp format.hpp \
|
||||
shared_ptr.hpp weak_ptr.hpp throw_exception.hpp \
|
||||
enable_shared_from_this.hpp \
|
||||
detail/shared_count.hpp detail/workaround.hpp
|
||||
|
||||
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static off_t offtin(u_char *buf)
|
||||
{
|
||||
|
||||
@@ -2,25 +2,25 @@ pkglib_LTLIBRARIES = libexpr.la
|
||||
|
||||
libexpr_la_SOURCES = \
|
||||
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
|
||||
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.cc
|
||||
get-drvs.cc attr-path.cc value-to-xml.cc common-opts.cc \
|
||||
names.cc
|
||||
|
||||
pkginclude_HEADERS = \
|
||||
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
||||
get-drvs.hh attr-path.hh expr-to-xml.hh common-opts.hh
|
||||
get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \
|
||||
names.hh symbol-table.hh
|
||||
|
||||
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
||||
../boost/format/libformat.la
|
||||
|
||||
BUILT_SOURCES = nixexpr-ast.cc nixexpr-ast.hh \
|
||||
BUILT_SOURCES = \
|
||||
parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc
|
||||
|
||||
EXTRA_DIST = lexer.l parser.y nixexpr-ast.def nixexpr-ast.cc
|
||||
EXTRA_DIST = lexer.l parser.y
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
-I$(srcdir)/.. ${bdb_include} ${aterm_include} \
|
||||
-I$(srcdir)/.. \
|
||||
-I$(srcdir)/../libutil -I$(srcdir)/../libstore
|
||||
AM_CFLAGS = \
|
||||
${aterm_include}
|
||||
|
||||
|
||||
# Parser generation.
|
||||
@@ -32,15 +32,6 @@ lexer-tab.cc lexer-tab.hh: lexer.l
|
||||
$(flex) --outfile lexer-tab.cc --header-file=lexer-tab.hh $(srcdir)/lexer.l
|
||||
|
||||
|
||||
# ATerm helper function generation.
|
||||
|
||||
nixexpr-ast.cc nixexpr-ast.hh: ../aterm-helper.pl nixexpr-ast.def
|
||||
$(perl) $(srcdir)/../aterm-helper.pl nixexpr-ast.hh nixexpr-ast.cc < $(srcdir)/nixexpr-ast.def
|
||||
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
|
||||
# SDF stuff (not built by default).
|
||||
nix.tbl: nix.sdf
|
||||
sdf2table -m Nix -s -i nix.sdf -o nix.tbl
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
#include "attr-path.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
bool isAttrs(EvalState & state, Expr e, ATermMap & attrs)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATermList dummy;
|
||||
if (!matchAttrs(e, dummy)) return false;
|
||||
queryAllAttrs(e, attrs, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
const ATermMap & autoArgs, Expr e)
|
||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
const Bindings & autoArgs, Expr * e, Value & v)
|
||||
{
|
||||
Strings tokens = tokenizeString(attrPath, ".");
|
||||
|
||||
@@ -25,8 +14,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
Error(format("attribute selection path `%1%' does not match expression") % attrPath);
|
||||
|
||||
string curPath;
|
||||
|
||||
state.mkThunk_(v, e);
|
||||
|
||||
for (Strings::iterator i = tokens.begin(); i != tokens.end(); ++i) {
|
||||
foreach (Strings::iterator, i, tokens) {
|
||||
|
||||
if (!curPath.empty()) curPath += ".";
|
||||
curPath += *i;
|
||||
@@ -38,7 +29,10 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||
|
||||
/* Evaluate the expression. */
|
||||
e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs));
|
||||
Value vTmp;
|
||||
state.autoCallFunction(autoArgs, v, vTmp);
|
||||
v = vTmp;
|
||||
state.forceValue(v);
|
||||
|
||||
/* It should evaluate to either an attribute set or an
|
||||
expression, according to what is specified in the
|
||||
@@ -46,36 +40,31 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
|
||||
if (apType == apAttr) {
|
||||
|
||||
ATermMap attrs;
|
||||
|
||||
if (!isAttrs(state, e, attrs))
|
||||
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(e));
|
||||
|
||||
e = attrs.get(toATerm(attr));
|
||||
if (!e)
|
||||
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
||||
% curPath % showType(v));
|
||||
|
||||
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->second.value;
|
||||
}
|
||||
|
||||
else if (apType == apIndex) {
|
||||
|
||||
ATermList es;
|
||||
if (!matchList(e, es))
|
||||
if (v.type != tList)
|
||||
throw TypeError(
|
||||
format("the expression selected by the selection path `%1%' should be a list but is %2%")
|
||||
% curPath % showType(e));
|
||||
% curPath % showType(v));
|
||||
|
||||
e = ATelementAt(es, attrIndex);
|
||||
if (!e)
|
||||
throw Error(format("list index %1% in selection path `%2%' not found") % attrIndex % curPath);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
namespace nix {
|
||||
|
||||
|
||||
Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
const ATermMap & autoArgs, Expr e);
|
||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
const Bindings & autoArgs, Expr * e, Value & v);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace nix {
|
||||
|
||||
bool parseOptionArg(const string & arg, Strings::iterator & i,
|
||||
const Strings::iterator & argsEnd, EvalState & state,
|
||||
ATermMap & autoArgs)
|
||||
Bindings & autoArgs)
|
||||
{
|
||||
if (arg != "--arg" && arg != "--argstr") return false;
|
||||
|
||||
@@ -19,11 +19,13 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
|
||||
string name = *i++;
|
||||
if (i == argsEnd) throw error;
|
||||
string value = *i++;
|
||||
|
||||
Expr e = arg == "--arg"
|
||||
? parseExprFromString(state, value, absPath("."))
|
||||
: makeStr(value);
|
||||
autoArgs.set(toATerm(name), e);
|
||||
|
||||
Value & v(autoArgs[state.symbols.create(name)].value);
|
||||
|
||||
if (arg == "--arg")
|
||||
state.mkThunk_( v, parseExprFromString(state, value, absPath(".")));
|
||||
else
|
||||
mkString(v, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace nix {
|
||||
/* Some common option parsing between nix-env and nix-instantiate. */
|
||||
bool parseOptionArg(const string & arg, Strings::iterator & i,
|
||||
const Strings::iterator & argsEnd, EvalState & state,
|
||||
ATermMap & autoArgs);
|
||||
Bindings & autoArgs);
|
||||
|
||||
}
|
||||
|
||||
|
||||
1590
src/libexpr/eval.cc
1590
src/libexpr/eval.cc
File diff suppressed because it is too large
Load Diff
@@ -3,17 +3,165 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "aterm.hh"
|
||||
#include "nixexpr.hh"
|
||||
#include "symbol-table.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
class Hash;
|
||||
|
||||
class EvalState;
|
||||
struct Env;
|
||||
struct Value;
|
||||
struct Attr;
|
||||
|
||||
typedef std::map<Symbol, Attr> Bindings;
|
||||
|
||||
|
||||
typedef enum {
|
||||
tInt = 1,
|
||||
tBool,
|
||||
tString,
|
||||
tPath,
|
||||
tNull,
|
||||
tAttrs,
|
||||
tList,
|
||||
tThunk,
|
||||
tApp,
|
||||
tLambda,
|
||||
tCopy,
|
||||
tBlackhole,
|
||||
tPrimOp,
|
||||
tPrimOpApp,
|
||||
} ValueType;
|
||||
|
||||
|
||||
typedef void (* PrimOp) (EvalState & state, Value * * args, Value & v);
|
||||
|
||||
|
||||
struct Value
|
||||
{
|
||||
ValueType type;
|
||||
union
|
||||
{
|
||||
int 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
|
||||
|
||||
"--with-freetype2-library=" + freetype + "/lib"
|
||||
|
||||
where `freetype' is a derivation (or a source to be copied
|
||||
to the store). If we just concatenated the strings without
|
||||
keeping track of the referenced store paths, then if the
|
||||
string is used as a derivation attribute, the derivation
|
||||
will not have the correct dependencies in its inputDrvs and
|
||||
inputSrcs.
|
||||
|
||||
The semantics of the context is as follows: when a string
|
||||
with context C is used as a derivation attribute, then the
|
||||
derivations in C will be added to the inputDrvs of the
|
||||
derivation, and the other store paths in C will be added to
|
||||
the inputSrcs of the derivations.
|
||||
|
||||
For canonicity, the store paths should be in sorted order. */
|
||||
struct {
|
||||
const char * s;
|
||||
const char * * context; // must be in sorted order
|
||||
} string;
|
||||
|
||||
const char * path;
|
||||
Bindings * attrs;
|
||||
struct {
|
||||
unsigned int length;
|
||||
Value * * elems;
|
||||
} list;
|
||||
struct {
|
||||
Env * env;
|
||||
Expr * expr;
|
||||
} thunk;
|
||||
struct {
|
||||
Value * left, * right;
|
||||
} app;
|
||||
struct {
|
||||
Env * env;
|
||||
ExprLambda * fun;
|
||||
} lambda;
|
||||
Value * val;
|
||||
struct {
|
||||
PrimOp fun;
|
||||
char * name;
|
||||
unsigned int arity;
|
||||
} primOp;
|
||||
struct {
|
||||
Value * left, * right;
|
||||
unsigned int argsLeft;
|
||||
} primOpApp;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct Env
|
||||
{
|
||||
Env * up;
|
||||
unsigned int prevWith; // nr of levels up to next `with' environment
|
||||
Value values[0];
|
||||
};
|
||||
|
||||
|
||||
struct Attr
|
||||
{
|
||||
Value value;
|
||||
Pos * pos;
|
||||
Attr() : pos(&noPos) { };
|
||||
};
|
||||
|
||||
|
||||
static inline void mkInt(Value & v, int n)
|
||||
{
|
||||
v.type = tInt;
|
||||
v.integer = n;
|
||||
}
|
||||
|
||||
|
||||
static inline void mkBool(Value & v, bool b)
|
||||
{
|
||||
v.type = tBool;
|
||||
v.boolean = b;
|
||||
}
|
||||
|
||||
|
||||
static inline void mkThunk(Value & v, Env & env, Expr * expr)
|
||||
{
|
||||
v.type = tThunk;
|
||||
v.thunk.env = &env;
|
||||
v.thunk.expr = expr;
|
||||
}
|
||||
|
||||
|
||||
static inline void mkCopy(Value & v, Value & src)
|
||||
{
|
||||
v.type = tCopy;
|
||||
v.val = &src;
|
||||
}
|
||||
|
||||
|
||||
static inline void mkApp(Value & v, Value & left, Value & right)
|
||||
{
|
||||
v.type = tApp;
|
||||
v.app.left = &left;
|
||||
v.app.right = &right;
|
||||
}
|
||||
|
||||
|
||||
void mkString(Value & v, const char * s);
|
||||
void mkString(Value & v, const string & s, const PathSet & context = PathSet());
|
||||
void mkPath(Value & v, const char * s);
|
||||
|
||||
|
||||
typedef std::map<Path, PathSet> DrvRoots;
|
||||
typedef std::map<Path, Hash> DrvHashes;
|
||||
|
||||
/* Cache for calls to addToStore(); maps source paths to the store
|
||||
@@ -22,73 +170,153 @@ typedef std::map<Path, Path> SrcToStore;
|
||||
|
||||
struct EvalState;
|
||||
|
||||
/* Note: using a ATermVector is safe here, since when we call a primop
|
||||
we also have an ATermList on the stack. */
|
||||
typedef Expr (* PrimOp) (EvalState &, const ATermVector & args);
|
||||
|
||||
std::ostream & operator << (std::ostream & str, Value & v);
|
||||
|
||||
|
||||
struct EvalState
|
||||
class EvalState
|
||||
{
|
||||
ATermMap normalForms;
|
||||
ATermMap primOps;
|
||||
DrvRoots drvRoots;
|
||||
public:
|
||||
DrvHashes drvHashes; /* normalised derivation hashes */
|
||||
|
||||
SymbolTable symbols;
|
||||
|
||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sSystem;
|
||||
|
||||
private:
|
||||
SrcToStore srcToStore;
|
||||
|
||||
unsigned int nrEvaluated;
|
||||
unsigned int nrCached;
|
||||
bool allowUnsafeEquality;
|
||||
|
||||
std::map<Path, Expr *> parseTrees;
|
||||
|
||||
public:
|
||||
|
||||
EvalState();
|
||||
~EvalState();
|
||||
|
||||
/* Evaluate an expression read from the given file to normal
|
||||
form. */
|
||||
void evalFile(const Path & path, Value & v);
|
||||
|
||||
/* Evaluate an expression to normal form, storing the result in
|
||||
value `v'. */
|
||||
void eval(Expr * e, Value & v);
|
||||
void eval(Env & env, Expr * e, Value & v);
|
||||
|
||||
/* Evaluation the expression, then verify that it has the expected
|
||||
type. */
|
||||
bool evalBool(Env & env, Expr * e);
|
||||
void evalAttrs(Env & env, Expr * e, Value & v);
|
||||
|
||||
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
||||
of the evaluation of the thunk. If `v' is a delayed function
|
||||
application, call the function and overwrite `v' with the
|
||||
result. Otherwise, this is a no-op. */
|
||||
void forceValue(Value & v);
|
||||
|
||||
/* Force a value, then recursively force list elements and
|
||||
attributes. */
|
||||
void strictForceValue(Value & v);
|
||||
|
||||
/* Force `v', and then verify that it has the expected type. */
|
||||
int forceInt(Value & v);
|
||||
bool forceBool(Value & v);
|
||||
void forceAttrs(Value & v);
|
||||
void forceList(Value & v);
|
||||
void forceFunction(Value & v); // either lambda or primop
|
||||
string forceString(Value & v);
|
||||
string forceString(Value & v, PathSet & context);
|
||||
string forceStringNoCtx(Value & v);
|
||||
|
||||
/* Return true iff the value `v' denotes a derivation (i.e. a
|
||||
set with attribute `type = "derivation"'). */
|
||||
bool isDerivation(Value & v);
|
||||
|
||||
/* 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 */
|
||||
string coerceToString(Value & v, PathSet & context,
|
||||
bool coerceMore = false, bool copyToStore = true);
|
||||
|
||||
/* Path coercion. Converts strings, paths and derivations to a
|
||||
path. The result is guaranteed to be a canonicalised, absolute
|
||||
path. Nothing is copied to the store. */
|
||||
Path coerceToPath(Value & v, PathSet & context);
|
||||
|
||||
private:
|
||||
|
||||
/* 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:
|
||||
|
||||
void createBaseEnv();
|
||||
|
||||
void addConstant(const string & name, Value & v);
|
||||
|
||||
void addPrimOps();
|
||||
void addPrimOp(const string & name,
|
||||
unsigned int arity, PrimOp primOp);
|
||||
|
||||
Value * lookupVar(Env * env, const VarRef & var);
|
||||
|
||||
friend class ExprVar;
|
||||
friend class ExprAttrs;
|
||||
friend class ExprLet;
|
||||
|
||||
public:
|
||||
|
||||
/* Do a deep equality test between two values. That is, list
|
||||
elements and attributes are compared recursively. */
|
||||
bool eqValues(Value & v1, Value & v2);
|
||||
|
||||
void callFunction(Value & fun, Value & arg, Value & v);
|
||||
|
||||
/* Automatically call a function for which each argument has a
|
||||
default value or has a binding in the `args' map. */
|
||||
void autoCallFunction(const Bindings & args, Value & fun, Value & res);
|
||||
|
||||
/* Allocation primitives. */
|
||||
Value * allocValues(unsigned int count);
|
||||
Env & allocEnv(unsigned int size);
|
||||
|
||||
void mkList(Value & v, unsigned int length);
|
||||
void mkAttrs(Value & v);
|
||||
void mkThunk_(Value & v, Expr * expr);
|
||||
|
||||
void cloneAttrs(Value & src, Value & dst);
|
||||
|
||||
/* Print statistics. */
|
||||
void printStats();
|
||||
|
||||
private:
|
||||
|
||||
unsigned long nrEnvs;
|
||||
unsigned long nrValuesInEnvs;
|
||||
unsigned long nrValues;
|
||||
unsigned long nrListElems;
|
||||
unsigned long nrEvaluated;
|
||||
unsigned int recursionDepth;
|
||||
unsigned int maxRecursionDepth;
|
||||
char * deepestStack; /* for measuring stack usage */
|
||||
|
||||
friend class RecursionCounter;
|
||||
};
|
||||
|
||||
|
||||
/* Evaluate an expression to normal form. */
|
||||
Expr evalExpr(EvalState & state, Expr e);
|
||||
/* Return a string representing the type of the value `v'. */
|
||||
string showType(const Value & v);
|
||||
|
||||
/* Evaluate an expression read from the given file to normal form. */
|
||||
Expr evalFile(EvalState & state, const Path & path);
|
||||
|
||||
/* Evaluate an expression, and recursively evaluate list elements and
|
||||
attributes. If `canonicalise' is true, we remove things like
|
||||
position information and make sure that attribute sets are in
|
||||
sorded order. */
|
||||
Expr strictEvalExpr(EvalState & state, Expr e);
|
||||
|
||||
/* Specific results. */
|
||||
string evalString(EvalState & state, Expr e, PathSet & context);
|
||||
string evalStringNoCtx(EvalState & state, Expr e);
|
||||
int evalInt(EvalState & state, Expr e);
|
||||
bool evalBool(EvalState & state, Expr e);
|
||||
ATermList evalList(EvalState & state, Expr e);
|
||||
|
||||
/* Flatten nested lists into a single list (or expand a singleton into
|
||||
a list). */
|
||||
ATermList flattenList(EvalState & state, Expr e);
|
||||
|
||||
/* String coercion. Converts strings, paths and derivations to a
|
||||
string. If `coerceMore' is set, also converts nulls, integers,
|
||||
booleans and lists to a string. */
|
||||
string coerceToString(EvalState & state, Expr e, PathSet & context,
|
||||
bool coerceMore = false, bool copyToStore = true);
|
||||
|
||||
/* Path coercion. Converts strings, paths and derivations to a path.
|
||||
The result is guaranteed to be an canonicalised, absolute path.
|
||||
Nothing is copied to the store. */
|
||||
Path coerceToPath(EvalState & state, Expr e, PathSet & context);
|
||||
|
||||
/* Automatically call a function for which each argument has a default
|
||||
value or has a binding in the `args' map. Note: result is a call,
|
||||
not a normal form; it should be evaluated by calling evalExpr(). */
|
||||
Expr autoCallFunction(Expr e, const ATermMap & args);
|
||||
|
||||
/* Print statistics. */
|
||||
void printEvalStats(EvalState & state);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
#include "expr-to-xml.hh"
|
||||
#include "xml-writer.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "aterm.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
static XMLAttrs singletonAttrs(const string & name, const string & value)
|
||||
{
|
||||
XMLAttrs attrs;
|
||||
attrs[name] = value;
|
||||
return attrs;
|
||||
}
|
||||
|
||||
|
||||
/* set<Expr> is safe because all the expressions are also reachable
|
||||
from the stack, therefore can't be garbage-collected. */
|
||||
typedef set<Expr> ExprSet;
|
||||
|
||||
|
||||
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
||||
ExprSet & drvsSeen);
|
||||
|
||||
|
||||
static void showAttrs(const ATermMap & attrs, XMLWriter & doc,
|
||||
PathSet & context, ExprSet & drvsSeen)
|
||||
{
|
||||
StringSet names;
|
||||
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
|
||||
names.insert(aterm2String(i->key));
|
||||
for (StringSet::iterator i = names.begin(); i != names.end(); ++i) {
|
||||
XMLOpenElement _(doc, "attr", singletonAttrs("name", *i));
|
||||
printTermAsXML(attrs.get(toATerm(*i)), doc, context, drvsSeen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
|
||||
ExprSet & drvsSeen)
|
||||
{
|
||||
XMLAttrs attrs;
|
||||
string s;
|
||||
ATerm s2;
|
||||
int i;
|
||||
ATermList as, es, formals;
|
||||
ATerm body, pos;
|
||||
|
||||
checkInterrupt();
|
||||
|
||||
if (matchStr(e, s, context)) /* !!! show the context? */
|
||||
doc.writeEmptyElement("string", singletonAttrs("value", s));
|
||||
|
||||
else if (matchPath(e, s2))
|
||||
doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s2)));
|
||||
|
||||
else if (matchNull(e))
|
||||
doc.writeEmptyElement("null");
|
||||
|
||||
else if (matchInt(e, i))
|
||||
doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % i).str()));
|
||||
|
||||
else if (e == eTrue)
|
||||
doc.writeEmptyElement("bool", singletonAttrs("value", "true"));
|
||||
|
||||
else if (e == eFalse)
|
||||
doc.writeEmptyElement("bool", singletonAttrs("value", "false"));
|
||||
|
||||
else if (matchAttrs(e, as)) {
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(e, attrs);
|
||||
|
||||
Expr a = attrs.get(toATerm("type"));
|
||||
if (a && matchStr(a, s, context) && s == "derivation") {
|
||||
|
||||
XMLAttrs xmlAttrs;
|
||||
Path outPath, drvPath;
|
||||
|
||||
a = attrs.get(toATerm("drvPath"));
|
||||
if (matchStr(a, drvPath, context))
|
||||
xmlAttrs["drvPath"] = drvPath;
|
||||
|
||||
a = attrs.get(toATerm("outPath"));
|
||||
if (matchStr(a, outPath, context))
|
||||
xmlAttrs["outPath"] = outPath;
|
||||
|
||||
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
||||
|
||||
if (drvsSeen.find(e) == drvsSeen.end()) {
|
||||
drvsSeen.insert(e);
|
||||
showAttrs(attrs, doc, context, drvsSeen);
|
||||
} else
|
||||
doc.writeEmptyElement("repeated");
|
||||
}
|
||||
|
||||
else {
|
||||
XMLOpenElement _(doc, "attrs");
|
||||
showAttrs(attrs, doc, context, drvsSeen);
|
||||
}
|
||||
}
|
||||
|
||||
else if (matchList(e, es)) {
|
||||
XMLOpenElement _(doc, "list");
|
||||
for (ATermIterator i(es); i; ++i)
|
||||
printTermAsXML(*i, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
else if (matchFunction(e, formals, body, pos)) {
|
||||
XMLOpenElement _(doc, "function");
|
||||
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
Expr name; ValidValues valids; ATerm dummy;
|
||||
if (!matchFormal(*i, name, valids, dummy)) abort();
|
||||
XMLOpenElement _(doc, "arg", singletonAttrs("name", aterm2String(name)));
|
||||
|
||||
ATermList valids2;
|
||||
if (matchValidValues(valids, valids2)) {
|
||||
for (ATermIterator j(valids2); j; ++j) {
|
||||
XMLOpenElement _(doc, "value");
|
||||
printTermAsXML(*j, doc, context, drvsSeen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
doc.writeEmptyElement("unevaluated");
|
||||
}
|
||||
|
||||
|
||||
void printTermAsXML(Expr e, std::ostream & out, PathSet & context)
|
||||
{
|
||||
XMLWriter doc(true, out);
|
||||
XMLOpenElement root(doc, "expr");
|
||||
ExprSet drvsSeen;
|
||||
printTermAsXML(e, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef __EXPR_TO_XML_H
|
||||
#define __EXPR_TO_XML_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "nixexpr.hh"
|
||||
#include "aterm.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
void printTermAsXML(Expr e, std::ostream & out, PathSet & context);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__EXPR_TO_XML_H */
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "get-drvs.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
@@ -8,17 +7,10 @@ namespace nix {
|
||||
|
||||
string DrvInfo::queryDrvPath(EvalState & state) const
|
||||
{
|
||||
if (drvPath == "") {
|
||||
Expr a = attrs->get(toATerm("drvPath"));
|
||||
|
||||
/* Backwards compatibility hack with user environments made by
|
||||
Nix <= 0.10: these contain illegal Path("") expressions. */
|
||||
ATerm t;
|
||||
if (a && matchPath(evalExpr(state, a), t))
|
||||
return aterm2String(t);
|
||||
|
||||
if (drvPath == "" && attrs) {
|
||||
Bindings::iterator i = attrs->find(state.sDrvPath);
|
||||
PathSet context;
|
||||
(string &) drvPath = a ? coerceToPath(state, a, context) : "";
|
||||
(string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : "";
|
||||
}
|
||||
return drvPath;
|
||||
}
|
||||
@@ -26,11 +18,10 @@ string DrvInfo::queryDrvPath(EvalState & state) const
|
||||
|
||||
string DrvInfo::queryOutPath(EvalState & state) const
|
||||
{
|
||||
if (outPath == "") {
|
||||
Expr a = attrs->get(toATerm("outPath"));
|
||||
if (!a) throw TypeError("output path missing");
|
||||
if (outPath == "" && attrs) {
|
||||
Bindings::iterator i = attrs->find(state.sOutPath);
|
||||
PathSet context;
|
||||
(string &) outPath = coerceToPath(state, a, context);
|
||||
(string &) outPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : "";
|
||||
}
|
||||
return outPath;
|
||||
}
|
||||
@@ -38,93 +29,85 @@ string DrvInfo::queryOutPath(EvalState & state) const
|
||||
|
||||
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||
{
|
||||
MetaInfo meta;
|
||||
if (metaInfoRead) return meta;
|
||||
|
||||
Expr a = attrs->get(toATerm("meta"));
|
||||
if (!a) return meta; /* fine, empty meta information */
|
||||
(bool &) metaInfoRead = true;
|
||||
|
||||
Bindings::iterator a = attrs->find(state.sMeta);
|
||||
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
||||
|
||||
ATermMap attrs2;
|
||||
queryAllAttrs(evalExpr(state, a), attrs2);
|
||||
state.forceAttrs(a->second.value);
|
||||
|
||||
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
|
||||
Expr e = evalExpr(state, i->value);
|
||||
string s;
|
||||
PathSet context;
|
||||
if (matchStr(e, s, context))
|
||||
meta[aterm2String(i->key)] = s;
|
||||
/* For future compatibility, ignore attribute values that are
|
||||
not strings. */
|
||||
foreach (Bindings::iterator, i, *a->second.value.attrs) {
|
||||
MetaValue value;
|
||||
state.forceValue(i->second.value);
|
||||
if (i->second.value.type == tString) {
|
||||
value.type = MetaValue::tpString;
|
||||
value.stringValue = i->second.value.string.s;
|
||||
} else if (i->second.value.type == tInt) {
|
||||
value.type = MetaValue::tpInt;
|
||||
value.intValue = i->second.value.integer;
|
||||
} else if (i->second.value.type == tList) {
|
||||
value.type = MetaValue::tpStrings;
|
||||
for (unsigned int j = 0; j < i->second.value.list.length; ++j)
|
||||
value.stringValues.push_back(state.forceStringNoCtx(*i->second.value.list.elems[j]));
|
||||
} else continue;
|
||||
((MetaInfo &) meta)[i->first] = value;
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
||||
string DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
|
||||
MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
|
||||
{
|
||||
/* !!! evaluates all meta attributes => inefficient */
|
||||
MetaInfo meta = queryMetaInfo(state);
|
||||
MetaInfo::iterator i = meta.find(name);
|
||||
return i == meta.end() ? "" : i->second;
|
||||
return queryMetaInfo(state)[name];
|
||||
}
|
||||
|
||||
|
||||
void DrvInfo::setMetaInfo(const MetaInfo & meta)
|
||||
{
|
||||
ATermMap metaAttrs;
|
||||
for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i)
|
||||
metaAttrs.set(toATerm(i->first),
|
||||
makeAttrRHS(makeStr(i->second), makeNoPos()));
|
||||
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
|
||||
metaInfoRead = true;
|
||||
this->meta = meta;
|
||||
}
|
||||
|
||||
|
||||
/* Cache for already evaluated derivations. Usually putting ATerms in
|
||||
a STL container is unsafe (they're not scanning for GC roots), but
|
||||
here it doesn't matter; everything in this set is reachable from
|
||||
the stack as well. */
|
||||
typedef set<Expr> Exprs;
|
||||
/* Cache for already considered attrsets. */
|
||||
typedef set<Bindings *> Done;
|
||||
|
||||
|
||||
/* Evaluate expression `e'. 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 `e'. */
|
||||
static bool getDerivation(EvalState & state, Expr e,
|
||||
const string & attrPath, DrvInfos & drvs, Exprs & doneExprs)
|
||||
/* 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'. */
|
||||
static bool getDerivation(EvalState & state, Value & v,
|
||||
const string & attrPath, DrvInfos & drvs, Done & done)
|
||||
{
|
||||
try {
|
||||
|
||||
ATermList es;
|
||||
e = evalExpr(state, e);
|
||||
if (!matchAttrs(e, es)) return true;
|
||||
|
||||
boost::shared_ptr<ATermMap> attrs(new ATermMap());
|
||||
queryAllAttrs(e, *attrs, false);
|
||||
|
||||
Expr a = attrs->get(toATerm("type"));
|
||||
if (!a || evalStringNoCtx(state, a) != "derivation") return true;
|
||||
state.forceValue(v);
|
||||
if (!state.isDerivation(v)) return true;
|
||||
|
||||
/* Remove spurious duplicates (e.g., an attribute set like
|
||||
`rec { x = derivation {...}; y = x;}'. */
|
||||
if (doneExprs.find(e) != doneExprs.end()) return false;
|
||||
doneExprs.insert(e);
|
||||
if (done.find(v.attrs) != done.end()) return false;
|
||||
done.insert(v.attrs);
|
||||
|
||||
DrvInfo drv;
|
||||
|
||||
a = attrs->get(toATerm("name"));
|
||||
Bindings::iterator i = v.attrs->find(state.sName);
|
||||
/* !!! We really would like to have a decent back trace here. */
|
||||
if (!a) throw TypeError("derivation name missing");
|
||||
drv.name = evalStringNoCtx(state, a);
|
||||
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
||||
drv.name = state.forceStringNoCtx(i->second.value);
|
||||
|
||||
a = attrs->get(toATerm("system"));
|
||||
if (!a)
|
||||
i = v.attrs->find(state.sSystem);
|
||||
if (i == v.attrs->end())
|
||||
drv.system = "unknown";
|
||||
else
|
||||
drv.system = evalStringNoCtx(state, a);
|
||||
drv.system = state.forceStringNoCtx(i->second.value);
|
||||
|
||||
drv.attrs = attrs;
|
||||
drv.attrs = v.attrs;
|
||||
|
||||
drv.attrPath = attrPath;
|
||||
|
||||
@@ -137,11 +120,11 @@ static bool getDerivation(EvalState & state, Expr e,
|
||||
}
|
||||
|
||||
|
||||
bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
|
||||
bool getDerivation(EvalState & state, Value & v, DrvInfo & drv)
|
||||
{
|
||||
Exprs doneExprs;
|
||||
Done done;
|
||||
DrvInfos drvs;
|
||||
getDerivation(state, e, "", drvs, doneExprs);
|
||||
getDerivation(state, v, "", drvs, done);
|
||||
if (drvs.size() != 1) return false;
|
||||
drv = drvs.front();
|
||||
return true;
|
||||
@@ -154,77 +137,73 @@ static string addToPath(const string & s1, const string & s2)
|
||||
}
|
||||
|
||||
|
||||
static void getDerivations(EvalState & state, Expr e,
|
||||
const string & pathPrefix, const ATermMap & autoArgs,
|
||||
DrvInfos & drvs, Exprs & doneExprs)
|
||||
static void getDerivations(EvalState & state, Value & vIn,
|
||||
const string & pathPrefix, const Bindings & autoArgs,
|
||||
DrvInfos & drvs, Done & done)
|
||||
{
|
||||
e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs));
|
||||
|
||||
Value v;
|
||||
state.autoCallFunction(autoArgs, vIn, v);
|
||||
|
||||
/* Process the expression. */
|
||||
ATermList es;
|
||||
DrvInfo drv;
|
||||
|
||||
if (!getDerivation(state, e, pathPrefix, drvs, doneExprs))
|
||||
return;
|
||||
if (!getDerivation(state, v, pathPrefix, drvs, done)) ;
|
||||
|
||||
if (matchAttrs(e, es)) {
|
||||
ATermMap drvMap(ATgetLength(es));
|
||||
queryAllAttrs(e, drvMap);
|
||||
else if (v.type == tAttrs) {
|
||||
|
||||
/* !!! undocumented hackery to support combining channels in
|
||||
nix-env.cc. */
|
||||
Expr e2 = drvMap.get(toATerm("_combineChannels"));
|
||||
bool combineChannels = e2 && evalBool(state, e2);
|
||||
|
||||
for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
|
||||
startNest(nest, lvlDebug,
|
||||
format("evaluating attribute `%1%'") % aterm2String(i->key));
|
||||
string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key));
|
||||
if (combineChannels) {
|
||||
if (((string) aterm2String(i->key)) != "_combineChannels")
|
||||
getDerivations(state, i->value, pathPrefix2, autoArgs, drvs, doneExprs);
|
||||
}
|
||||
else if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
|
||||
bool combineChannels = v.attrs->find(state.symbols.create("_combineChannels")) != v.attrs->end();
|
||||
|
||||
/* Consider the attributes in sorted order to get more
|
||||
deterministic behaviour in nix-env operations (e.g. when
|
||||
there are names clashes between derivations, the derivation
|
||||
bound to the attribute with the "lower" name should take
|
||||
precedence). */
|
||||
typedef std::map<string, Symbol> SortedSymbols;
|
||||
SortedSymbols attrs;
|
||||
foreach (Bindings::iterator, i, *v.attrs)
|
||||
attrs.insert(std::pair<string, Symbol>(i->first, i->first));
|
||||
|
||||
foreach (SortedSymbols::iterator, i, attrs) {
|
||||
startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first);
|
||||
string pathPrefix2 = addToPath(pathPrefix, i->first);
|
||||
Value & v2((*v.attrs)[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. */
|
||||
ATermList es;
|
||||
Expr e = evalExpr(state, i->value);
|
||||
if (matchAttrs(e, es)) {
|
||||
ATermMap attrs(ATgetLength(es));
|
||||
queryAllAttrs(e, attrs, false);
|
||||
if (((e2 = attrs.get(toATerm("recurseForDerivations")))
|
||||
&& evalBool(state, e2)))
|
||||
getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
|
||||
if (v2.type == tAttrs) {
|
||||
Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations"));
|
||||
if (j != v2.attrs->end() && state.forceBool(j->second.value))
|
||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (matchList(e, es)) {
|
||||
int n = 0;
|
||||
for (ATermIterator i(es); i; ++i, ++n) {
|
||||
else if (v.type == tList) {
|
||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
||||
startNest(nest, lvlDebug,
|
||||
format("evaluating list element"));
|
||||
string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
|
||||
if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs))
|
||||
getDerivations(state, *i, pathPrefix2, autoArgs, drvs, doneExprs);
|
||||
if (getDerivation(state, *v.list.elems[n], pathPrefix2, drvs, done))
|
||||
getDerivations(state, *v.list.elems[n], pathPrefix2, autoArgs, drvs, done);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
|
||||
else throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
|
||||
}
|
||||
|
||||
|
||||
void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
|
||||
const ATermMap & autoArgs, DrvInfos & drvs)
|
||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||
const Bindings & autoArgs, DrvInfos & drvs)
|
||||
{
|
||||
Exprs doneExprs;
|
||||
getDerivations(state, e, pathPrefix, autoArgs, drvs, doneExprs);
|
||||
Done done;
|
||||
getDerivations(state, v, pathPrefix, autoArgs, drvs, done);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,16 @@
|
||||
namespace nix {
|
||||
|
||||
|
||||
typedef std::map<string, string> MetaInfo;
|
||||
struct MetaValue
|
||||
{
|
||||
enum { tpNone, tpString, tpStrings, tpInt } type;
|
||||
string stringValue;
|
||||
Strings stringValues;
|
||||
int intValue;
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<string, MetaValue> MetaInfo;
|
||||
|
||||
|
||||
struct DrvInfo
|
||||
@@ -20,21 +29,24 @@ struct DrvInfo
|
||||
private:
|
||||
string drvPath;
|
||||
string outPath;
|
||||
|
||||
bool metaInfoRead;
|
||||
MetaInfo meta;
|
||||
|
||||
public:
|
||||
string name;
|
||||
string attrPath; /* path towards the derivation */
|
||||
string system;
|
||||
|
||||
/* !!! these should really be hidden, and setMetaInfo() should
|
||||
make a copy since the ATermMap can be shared between multiple
|
||||
DrvInfos. */
|
||||
boost::shared_ptr<ATermMap> attrs;
|
||||
/* !!! make this private */
|
||||
Bindings * attrs;
|
||||
|
||||
DrvInfo() : metaInfoRead(false), attrs(0) { };
|
||||
|
||||
string queryDrvPath(EvalState & state) const;
|
||||
string queryOutPath(EvalState & state) const;
|
||||
MetaInfo queryMetaInfo(EvalState & state) const;
|
||||
string queryMetaInfo(EvalState & state, const string & name) const;
|
||||
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
|
||||
|
||||
void setDrvPath(const string & s)
|
||||
{
|
||||
@@ -53,13 +65,12 @@ public:
|
||||
typedef list<DrvInfo> DrvInfos;
|
||||
|
||||
|
||||
/* Evaluate expression `e'. If it evaluates to a derivation, store
|
||||
information about the derivation in `drv' and return true.
|
||||
Otherwise, return false. */
|
||||
bool getDerivation(EvalState & state, Expr e, DrvInfo & drv);
|
||||
/* 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);
|
||||
|
||||
void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
|
||||
const ATermMap & autoArgs, DrvInfos & drvs);
|
||||
void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
|
||||
const Bindings & autoArgs, DrvInfos & drvs);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
|
||||
|
||||
%x STRING
|
||||
%x IND_STRING
|
||||
|
||||
|
||||
%{
|
||||
#include "aterm.hh"
|
||||
#include "nixexpr.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#define BISON_HEADER_HACK
|
||||
#include "parser-tab.hh"
|
||||
|
||||
@@ -20,13 +19,16 @@ namespace nix {
|
||||
|
||||
static void initLoc(YYLTYPE * loc)
|
||||
{
|
||||
loc->first_line = 1;
|
||||
loc->first_column = 1;
|
||||
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;
|
||||
loc->first_column = loc->last_column;
|
||||
|
||||
while (len--) {
|
||||
switch (*s++) {
|
||||
case '\r':
|
||||
@@ -34,17 +36,17 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
||||
s++;
|
||||
/* fall through */
|
||||
case '\n':
|
||||
++loc->first_line;
|
||||
loc->first_column = 1;
|
||||
++loc->last_line;
|
||||
loc->last_column = 1;
|
||||
break;
|
||||
default:
|
||||
++loc->first_column;
|
||||
++loc->last_column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Expr unescapeStr(const char * s)
|
||||
static Expr * unescapeStr(const char * s)
|
||||
{
|
||||
string t;
|
||||
char c;
|
||||
@@ -64,7 +66,7 @@ static Expr unescapeStr(const char * s)
|
||||
}
|
||||
else t += c;
|
||||
}
|
||||
return makeStr(toATerm(t), ATempty);
|
||||
return new ExprString(t);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +96,7 @@ let { return LET; }
|
||||
in { return IN; }
|
||||
rec { return REC; }
|
||||
inherit { return INHERIT; }
|
||||
\.\.\. { return ELLIPSIS; }
|
||||
|
||||
\=\= { return EQ; }
|
||||
\!\= { return NEQ; }
|
||||
@@ -103,28 +106,53 @@ inherit { return INHERIT; }
|
||||
\/\/ { return UPDATE; }
|
||||
\+\+ { return CONCAT; }
|
||||
|
||||
{ID} { yylval->t = toATerm(yytext); return ID; /* !!! alloc */ }
|
||||
{ID} { yylval->id = strdup(yytext); return ID; }
|
||||
{INT} { int n = atoi(yytext); /* !!! overflow */
|
||||
yylval->t = ATmake("<int>", n);
|
||||
yylval->n = n;
|
||||
return INT;
|
||||
}
|
||||
|
||||
\" { BEGIN(STRING); return '"'; }
|
||||
<STRING>([^\$\"\\]|\$[^\{\"]|\\.)+ {
|
||||
/* !!! Not quite right: we want a follow restriction on "$", it
|
||||
shouldn't be followed by a "{". Right now "$\"" will be consumed
|
||||
as part of a string, rather than a "$" followed by the string
|
||||
terminator. Disallow "$\"" for now. */
|
||||
yylval->t = unescapeStr(yytext); /* !!! alloc */
|
||||
/* !!! Not quite right: we want a follow restriction on
|
||||
"$", it shouldn't be followed by a "{". Right now
|
||||
"$\"" will be consumed as part of a string, rather
|
||||
than a "$" followed by the string terminator.
|
||||
Disallow "$\"" for now. */
|
||||
yylval->e = unescapeStr(yytext);
|
||||
return STR;
|
||||
}
|
||||
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
||||
<STRING>\" { BEGIN(INITIAL); return '"'; }
|
||||
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
||||
|
||||
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
|
||||
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
||||
yylval->e = new ExprIndStr(yytext);
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\$ {
|
||||
yylval->e = new ExprIndStr("$");
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\' {
|
||||
yylval->e = new ExprIndStr("''");
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\\. {
|
||||
yylval->e = unescapeStr(yytext + 2);
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
||||
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
|
||||
<IND_STRING>\' {
|
||||
yylval->e = new ExprIndStr("'");
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
||||
|
||||
{PATH} { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ }
|
||||
{URI} { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ }
|
||||
{PATH} { yylval->path = strdup(yytext); return PATH; }
|
||||
{URI} { yylval->uri = strdup(yytext); return URI; }
|
||||
|
||||
[ \t\r\n]+ /* eat up whitespace */
|
||||
\#[^\r\n]* /* single-line comments */
|
||||
@@ -148,4 +176,10 @@ void backToString(yyscan_t scanner)
|
||||
BEGIN(STRING);
|
||||
}
|
||||
|
||||
void backToIndString(yyscan_t scanner)
|
||||
{
|
||||
struct yyguts_t * yyg = (struct yyguts_t *) scanner;
|
||||
BEGIN(IND_STRING);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,25 +92,6 @@ int compareVersions(const string & v1, const string & v2)
|
||||
}
|
||||
|
||||
|
||||
static void testCompareVersions()
|
||||
{
|
||||
#define TEST(v1, v2, n) assert( \
|
||||
compareVersions(v1, v2) == n && compareVersions(v2, v1) == -n)
|
||||
TEST("1.0", "2.3", -1);
|
||||
TEST("2.1", "2.3", -1);
|
||||
TEST("2.3", "2.3", 0);
|
||||
TEST("2.5", "2.3", 1);
|
||||
TEST("3.1", "2.3", 1);
|
||||
TEST("2.3.1", "2.3", 1);
|
||||
TEST("2.3.1", "2.3a", 1);
|
||||
TEST("2.3pre1", "2.3", -1);
|
||||
TEST("2.3pre3", "2.3pre12", -1);
|
||||
TEST("2.3a", "2.3c", -1);
|
||||
TEST("2.3pre1", "2.3c", -1);
|
||||
TEST("2.3pre1", "2.3q", -1);
|
||||
}
|
||||
|
||||
|
||||
DrvNames drvNamesFromArgs(const Strings & opArgs)
|
||||
{
|
||||
DrvNames result;
|
||||
@@ -1,10 +1,13 @@
|
||||
%% Note: this SDF grammar is no longer used in the Nix expression
|
||||
%% parser and may not be up to date.
|
||||
|
||||
definition
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Top level syntax.
|
||||
|
||||
module Nix
|
||||
module Main
|
||||
imports Nix-Exprs Nix-Layout
|
||||
|
||||
|
||||
@@ -38,6 +41,7 @@ exports
|
||||
"with" Expr ";" Expr -> Expr {cons("With")}
|
||||
|
||||
"rec" "{" Bind* "}" -> Expr {cons("Rec")}
|
||||
"let" Bind* "in" Expr -> Expr {cons("Let")}
|
||||
"let" "{" Bind* "}" -> Expr {cons("LetRec")}
|
||||
"{" Bind* "}" -> Expr {cons("Attrs")}
|
||||
|
||||
@@ -102,7 +106,8 @@ exports
|
||||
|
||||
[0-9]+ -> Int
|
||||
|
||||
"\"" ~[\n\"]* "\"" -> Str
|
||||
"\"" (~[\"\\] | ("\\" ~[]) )* "\"" -> Str
|
||||
"''" (~[\"\\] | ("\\" ~[]) )* "''" -> Str
|
||||
|
||||
[a-zA-Z0-9\.\_\-\+]* ("/"[a-zA-Z0-9\.\_\-\+]+)+ -> Path
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
init initNixExprHelpers
|
||||
|
||||
Pos | string int int | Pos |
|
||||
NoPos | | Pos |
|
||||
|
||||
Function | ATermList Expr Pos | Expr |
|
||||
Function1 | string Expr Pos | Expr |
|
||||
Assert | Expr Expr Pos | Expr |
|
||||
With | Expr Expr Pos | Expr |
|
||||
If | Expr Expr Expr | Expr |
|
||||
OpNot | Expr | Expr |
|
||||
OpEq | Expr Expr | Expr |
|
||||
OpNEq | Expr Expr | Expr |
|
||||
OpAnd | Expr Expr | Expr |
|
||||
OpOr | Expr Expr | Expr |
|
||||
OpImpl | Expr Expr | Expr |
|
||||
OpUpdate | Expr Expr | Expr |
|
||||
SubPath | Expr Expr | Expr |
|
||||
OpHasAttr | Expr string | Expr |
|
||||
OpPlus | Expr Expr | Expr |
|
||||
OpConcat | Expr Expr | Expr |
|
||||
ConcatStrings | ATermList | Expr |
|
||||
Call | Expr Expr | Expr |
|
||||
Select | Expr string | Expr |
|
||||
Var | string | Expr |
|
||||
Int | int | Expr |
|
||||
|
||||
# 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
|
||||
#
|
||||
# "--with-freetype2-library=" + freetype + "/lib"
|
||||
#
|
||||
# where `freetype' is a derivation (or a source to be copied to the
|
||||
# store). If we just concatenated the strings without keeping track
|
||||
# of the referenced store paths, then if the string is used as a
|
||||
# derivation attribute, the derivation will not have the correct
|
||||
# dependencies in its inputDrvs and inputSrcs.
|
||||
#
|
||||
# The semantics of the context is as follows: when a string with
|
||||
# context C is used as a derivation attribute, then the derivations in
|
||||
# C will be added to the inputDrvs of the derivation, and the other
|
||||
# store paths in C will be added to the inputSrcs of the derivations.
|
||||
#
|
||||
# For canonicity, the store paths should be in sorted order.
|
||||
Str | string ATermList | Expr |
|
||||
Str | string | Expr | ObsoleteStr
|
||||
|
||||
# A path is a reference to a file system object that is to be copied
|
||||
# to the Nix store when used as a derivation attribute. When it is
|
||||
# concatenated to a string (i.e., `str + path'), it is also copied and
|
||||
# the resulting store path is concatenated to the string (with the
|
||||
# store path in the context). If a string or path is concatenated to
|
||||
# a path (i.e., `path + str' or `path + path'), the result is a new
|
||||
# path (if the right-hand side is a string, the context must be
|
||||
# empty).
|
||||
Path | string | Expr |
|
||||
|
||||
List | ATermList | Expr |
|
||||
BlackHole | | Expr |
|
||||
Undefined | | Expr |
|
||||
Removed | | Expr |
|
||||
PrimOp | int ATermBlob ATermList | Expr |
|
||||
Attrs | ATermList | Expr |
|
||||
Closed | Expr | Expr |
|
||||
Rec | ATermList ATermList | Expr |
|
||||
Bool | ATerm | Expr |
|
||||
Null | | Expr |
|
||||
|
||||
Bind | string Expr Pos | ATerm |
|
||||
Bind | string Expr | ATerm | ObsoleteBind
|
||||
Inherit | Expr ATermList Pos | ATerm |
|
||||
|
||||
Scope | | Expr |
|
||||
|
||||
Formal | string ValidValues DefaultValue | ATerm |
|
||||
|
||||
ValidValues | ATermList | ValidValues |
|
||||
UnrestrictedValues | | ValidValues |
|
||||
|
||||
DefaultValue | Expr | DefaultValue |
|
||||
NoDefaultValue | | DefaultValue |
|
||||
|
||||
True | | ATerm |
|
||||
False | | ATerm |
|
||||
|
||||
PrimOpDef | int ATermBlob | ATerm |
|
||||
|
||||
AttrRHS | Expr Pos | ATerm |
|
||||
|
||||
eTrue = makeBool(makeTrue())
|
||||
eFalse = makeBool(makeFalse())
|
||||
@@ -1,403 +1,325 @@
|
||||
#include "nixexpr.hh"
|
||||
#include "derivations.hh"
|
||||
#include "util.hh"
|
||||
#include "aterm.hh"
|
||||
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "nixexpr-ast.cc"
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
/* Displaying abstract syntax trees. */
|
||||
|
||||
std::ostream & operator << (std::ostream & str, Expr & e)
|
||||
{
|
||||
e.show(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
void Expr::show(std::ostream & str)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void ExprInt::show(std::ostream & str)
|
||||
{
|
||||
str << n;
|
||||
}
|
||||
|
||||
void ExprString::show(std::ostream & str)
|
||||
{
|
||||
str << "\"" << s << "\""; // !!! escaping
|
||||
}
|
||||
|
||||
void ExprPath::show(std::ostream & str)
|
||||
{
|
||||
str << s;
|
||||
}
|
||||
|
||||
void ExprVar::show(std::ostream & str)
|
||||
{
|
||||
str << info.name;
|
||||
}
|
||||
|
||||
void ExprSelect::show(std::ostream & str)
|
||||
{
|
||||
str << "(" << *e << ")." << name;
|
||||
}
|
||||
|
||||
void ExprOpHasAttr::show(std::ostream & str)
|
||||
{
|
||||
str << "(" << *e << ") ? " << name;
|
||||
}
|
||||
|
||||
void ExprAttrs::show(std::ostream & str)
|
||||
{
|
||||
if (recursive) str << "rec ";
|
||||
str << "{ ";
|
||||
foreach (list<Inherited>::iterator, i, inherited)
|
||||
str << "inherit " << i->first.name << "; ";
|
||||
foreach (Attrs::iterator, i, attrs)
|
||||
str << i->first << " = " << *i->second.first << "; ";
|
||||
str << "}";
|
||||
}
|
||||
|
||||
void ExprList::show(std::ostream & str)
|
||||
{
|
||||
str << "[ ";
|
||||
foreach (vector<Expr *>::iterator, i, elems)
|
||||
str << "(" << **i << ") ";
|
||||
str << "]";
|
||||
}
|
||||
|
||||
void ExprLambda::show(std::ostream & str)
|
||||
{
|
||||
str << "(";
|
||||
if (matchAttrs) {
|
||||
str << "{ ";
|
||||
bool first = true;
|
||||
foreach (Formals::Formals_::iterator, i, formals->formals) {
|
||||
if (first) first = false; else str << ", ";
|
||||
str << i->name;
|
||||
if (i->def) str << " ? " << *i->def;
|
||||
}
|
||||
str << " }";
|
||||
if (!arg.empty()) str << " @ ";
|
||||
}
|
||||
if (!arg.empty()) str << arg;
|
||||
str << ": " << *body << ")";
|
||||
}
|
||||
|
||||
void ExprLet::show(std::ostream & str)
|
||||
{
|
||||
str << "let ";
|
||||
foreach (list<ExprAttrs::Inherited>::iterator, i, attrs->inherited)
|
||||
str << "inherit " << i->first.name << "; ";
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
||||
str << i->first << " = " << *i->second.first << "; ";
|
||||
str << "in " << *body;
|
||||
}
|
||||
|
||||
void ExprWith::show(std::ostream & str)
|
||||
{
|
||||
str << "with " << *attrs << "; " << *body;
|
||||
}
|
||||
|
||||
void ExprIf::show(std::ostream & str)
|
||||
{
|
||||
str << "if " << *cond << " then " << *then << " else " << *else_;
|
||||
}
|
||||
|
||||
void ExprAssert::show(std::ostream & str)
|
||||
{
|
||||
str << "assert " << *cond << "; " << *body;
|
||||
}
|
||||
|
||||
void ExprOpNot::show(std::ostream & str)
|
||||
{
|
||||
str << "! " << *e;
|
||||
}
|
||||
|
||||
void ExprConcatStrings::show(std::ostream & str)
|
||||
{
|
||||
bool first = true;
|
||||
foreach (vector<Expr *>::iterator, i, *es) {
|
||||
if (first) first = false; else str << " + ";
|
||||
str << **i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Pos & pos)
|
||||
{
|
||||
if (!pos.line)
|
||||
str << "undefined position";
|
||||
else
|
||||
str << (format("`%1%:%2%:%3%'") % pos.file % pos.line % pos.column).str();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
Pos noPos;
|
||||
|
||||
|
||||
/* Computing levels/displacements for variables. */
|
||||
|
||||
void Expr::bindVars(const StaticEnv & env)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void ExprInt::bindVars(const StaticEnv & env)
|
||||
{
|
||||
}
|
||||
|
||||
void ExprString::bindVars(const StaticEnv & env)
|
||||
{
|
||||
}
|
||||
|
||||
void ExprPath::bindVars(const StaticEnv & env)
|
||||
{
|
||||
}
|
||||
|
||||
void VarRef::bind(const StaticEnv & env)
|
||||
{
|
||||
/* Check whether the variable appears in the environment. If so,
|
||||
set its level and displacement. */
|
||||
const StaticEnv * curEnv;
|
||||
unsigned int level;
|
||||
int withLevel = -1;
|
||||
for (curEnv = &env, level = 0; curEnv; curEnv = curEnv->up, level++) {
|
||||
if (curEnv->isWith) {
|
||||
if (withLevel == -1) withLevel = level;
|
||||
} else {
|
||||
StaticEnv::Vars::const_iterator i = curEnv->vars.find(name);
|
||||
if (i != curEnv->vars.end()) {
|
||||
fromWith = false;
|
||||
this->level = level;
|
||||
displ = i->second;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
fromWith = true;
|
||||
this->level = withLevel;
|
||||
}
|
||||
|
||||
void ExprVar::bindVars(const StaticEnv & env)
|
||||
{
|
||||
info.bind(env);
|
||||
}
|
||||
|
||||
void ExprSelect::bindVars(const StaticEnv & env)
|
||||
{
|
||||
e->bindVars(env);
|
||||
}
|
||||
|
||||
void ExprOpHasAttr::bindVars(const StaticEnv & env)
|
||||
{
|
||||
e->bindVars(env);
|
||||
}
|
||||
|
||||
void ExprAttrs::bindVars(const StaticEnv & env)
|
||||
{
|
||||
if (recursive) {
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
unsigned int displ = 0;
|
||||
|
||||
string showPos(ATerm pos)
|
||||
{
|
||||
ATerm path;
|
||||
int line, column;
|
||||
if (matchNoPos(pos)) return "undefined position";
|
||||
if (!matchPos(pos, path, line, column))
|
||||
throw badTerm("position expected", pos);
|
||||
return (format("`%1%', line %2%") % aterm2String(path) % line).str();
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
||||
newEnv.vars[i->first] = displ++;
|
||||
|
||||
foreach (list<Inherited>::iterator, i, inherited) {
|
||||
newEnv.vars[i->first.name] = displ++;
|
||||
i->first.bind(env);
|
||||
}
|
||||
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
||||
i->second.first->bindVars(newEnv);
|
||||
}
|
||||
|
||||
else {
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs)
|
||||
i->second.first->bindVars(env);
|
||||
|
||||
foreach (list<Inherited>::iterator, i, inherited)
|
||||
i->first.bind(env);
|
||||
}
|
||||
}
|
||||
|
||||
void ExprList::bindVars(const StaticEnv & env)
|
||||
{
|
||||
foreach (vector<Expr *>::iterator, i, elems)
|
||||
(*i)->bindVars(env);
|
||||
}
|
||||
|
||||
void ExprLambda::bindVars(const StaticEnv & env)
|
||||
{
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
|
||||
ATerm bottomupRewrite(TermFun & f, ATerm e)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
if (ATgetType(e) == AT_APPL) {
|
||||
AFun fun = ATgetAFun(e);
|
||||
int arity = ATgetArity(fun);
|
||||
ATerm args[arity];
|
||||
|
||||
for (int i = 0; i < arity; ++i)
|
||||
args[i] = bottomupRewrite(f, ATgetArgument(e, i));
|
||||
|
||||
e = (ATerm) ATmakeApplArray(fun, args);
|
||||
}
|
||||
|
||||
else if (ATgetType(e) == AT_LIST) {
|
||||
ATermList in = (ATermList) e;
|
||||
ATermList out = ATempty;
|
||||
|
||||
for (ATermIterator i(in); i; ++i)
|
||||
out = ATinsert(out, bottomupRewrite(f, *i));
|
||||
|
||||
e = (ATerm) ATreverse(out);
|
||||
}
|
||||
|
||||
return f(e);
|
||||
}
|
||||
|
||||
|
||||
void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
|
||||
{
|
||||
ATermList bnds;
|
||||
if (!matchAttrs(e, bnds))
|
||||
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
|
||||
|
||||
for (ATermIterator i(bnds); i; ++i) {
|
||||
ATerm name;
|
||||
Expr e;
|
||||
ATerm pos;
|
||||
if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
|
||||
attrs.set(name, withPos ? makeAttrRHS(e, pos) : e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Expr queryAttr(Expr e, const string & name)
|
||||
{
|
||||
ATerm dummy;
|
||||
return queryAttr(e, name, dummy);
|
||||
}
|
||||
|
||||
|
||||
Expr queryAttr(Expr e, const string & name, ATerm & pos)
|
||||
{
|
||||
ATermList bnds;
|
||||
if (!matchAttrs(e, bnds))
|
||||
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
|
||||
|
||||
for (ATermIterator i(bnds); i; ++i) {
|
||||
ATerm name2, pos2;
|
||||
Expr e;
|
||||
if (!matchBind(*i, name2, e, pos2))
|
||||
abort(); /* can't happen */
|
||||
if (aterm2String(name2) == name) {
|
||||
pos = pos2;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Expr makeAttrs(const ATermMap & attrs)
|
||||
{
|
||||
ATermList bnds = ATempty;
|
||||
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
|
||||
Expr e;
|
||||
ATerm pos;
|
||||
if (!matchAttrRHS(i->value, e, pos))
|
||||
abort(); /* can't happen */
|
||||
bnds = ATinsert(bnds, makeBind(i->key, e, pos));
|
||||
}
|
||||
return makeAttrs(bnds);
|
||||
}
|
||||
|
||||
|
||||
Expr substitute(const Substitution & subs, Expr e)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
//if (subs.size() == 0) return e;
|
||||
|
||||
ATerm name, pos, e2;
|
||||
|
||||
/* As an optimisation, don't substitute in subterms known to be
|
||||
closed. */
|
||||
if (matchClosed(e, e2)) return e;
|
||||
|
||||
if (matchVar(e, name)) {
|
||||
Expr sub = subs.lookup(name);
|
||||
if (sub == makeRemoved()) sub = 0;
|
||||
Expr wrapped;
|
||||
/* Add a "closed" wrapper around terms that aren't already
|
||||
closed. The check is necessary to prevent repeated
|
||||
wrapping, e.g., closed(closed(closed(...))), which kills
|
||||
caching. */
|
||||
return sub ? (matchClosed(sub, wrapped) ? sub : makeClosed(sub)) : e;
|
||||
}
|
||||
|
||||
/* In case of a function, filter out all variables bound by this
|
||||
function. */
|
||||
ATermList formals;
|
||||
ATerm body;
|
||||
if (matchFunction(e, formals, body, pos)) {
|
||||
ATermMap map(ATgetLength(formals));
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
ATerm d1, d2;
|
||||
if (!matchFormal(*i, name, d1, d2)) abort();
|
||||
map.set(name, makeRemoved());
|
||||
}
|
||||
Substitution subs2(&subs, &map);
|
||||
return makeFunction(
|
||||
(ATermList) substitute(subs2, (ATerm) formals),
|
||||
substitute(subs2, body), pos);
|
||||
}
|
||||
|
||||
if (matchFunction1(e, name, body, pos)) {
|
||||
ATermMap map(1);
|
||||
map.set(name, makeRemoved());
|
||||
return makeFunction1(name, substitute(Substitution(&subs, &map), body), pos);
|
||||
}
|
||||
|
||||
/* Idem for a mutually recursive attribute set. */
|
||||
ATermList rbnds, nrbnds;
|
||||
if (matchRec(e, rbnds, nrbnds)) {
|
||||
ATermMap map(ATgetLength(rbnds) + ATgetLength(nrbnds));
|
||||
for (ATermIterator i(rbnds); i; ++i)
|
||||
if (matchBind(*i, name, e2, pos)) map.set(name, makeRemoved());
|
||||
else abort(); /* can't happen */
|
||||
for (ATermIterator i(nrbnds); i; ++i)
|
||||
if (matchBind(*i, name, e2, pos)) map.set(name, makeRemoved());
|
||||
else abort(); /* can't happen */
|
||||
return makeRec(
|
||||
(ATermList) substitute(Substitution(&subs, &map), (ATerm) rbnds),
|
||||
(ATermList) substitute(subs, (ATerm) nrbnds));
|
||||
}
|
||||
|
||||
if (ATgetType(e) == AT_APPL) {
|
||||
AFun fun = ATgetAFun(e);
|
||||
int arity = ATgetArity(fun);
|
||||
ATerm args[arity];
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < arity; ++i) {
|
||||
ATerm arg = ATgetArgument(e, i);
|
||||
args[i] = substitute(subs, arg);
|
||||
if (args[i] != arg) changed = true;
|
||||
}
|
||||
|
||||
return changed ? (ATerm) ATmakeApplArray(fun, args) : e;
|
||||
}
|
||||
|
||||
if (ATgetType(e) == AT_LIST) {
|
||||
unsigned int len = ATgetLength((ATermList) e);
|
||||
ATerm es[len];
|
||||
ATermIterator i((ATermList) e);
|
||||
for (unsigned int j = 0; i; ++i, ++j)
|
||||
es[j] = substitute(subs, *i);
|
||||
ATermList out = ATempty;
|
||||
for (unsigned int j = len; j; --j)
|
||||
out = ATinsert(out, es[j - 1]);
|
||||
return (ATerm) out;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/* We use memoisation to prevent exponential complexity on heavily
|
||||
shared ATerms (remember, an ATerm is a graph, not a tree!). Note
|
||||
that using an STL set is fine here wrt to ATerm garbage collection
|
||||
since all the ATerms in the set are already reachable from
|
||||
somewhere else. */
|
||||
static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
|
||||
{
|
||||
if (done.find(e) != done.end()) return;
|
||||
done.insert(e);
|
||||
unsigned int displ = 0;
|
||||
|
||||
ATerm name, pos, value;
|
||||
ATermList formals;
|
||||
ATerm with, body;
|
||||
ATermList rbnds, nrbnds;
|
||||
if (!arg.empty()) newEnv.vars[arg] = displ++;
|
||||
|
||||
if (matchVar(e, name)) {
|
||||
if (!defs.get(name))
|
||||
throw EvalError(format("undefined variable `%1%'")
|
||||
% aterm2String(name));
|
||||
if (matchAttrs) {
|
||||
foreach (Formals::Formals_::iterator, i, formals->formals)
|
||||
newEnv.vars[i->name] = displ++;
|
||||
|
||||
foreach (Formals::Formals_::iterator, i, formals->formals)
|
||||
if (i->def) i->def->bindVars(newEnv);
|
||||
}
|
||||
|
||||
else if (matchFunction(e, formals, body, pos)) {
|
||||
ATermMap defs2(defs);
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
ATerm d1, d2;
|
||||
if (!matchFormal(*i, name, d1, d2)) abort();
|
||||
defs2.set(name, (ATerm) ATempty);
|
||||
}
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
ATerm valids, deflt;
|
||||
set<Expr> done2;
|
||||
if (!matchFormal(*i, name, valids, deflt)) abort();
|
||||
checkVarDefs2(done, defs, valids);
|
||||
checkVarDefs2(done2, defs2, deflt);
|
||||
}
|
||||
set<Expr> done2;
|
||||
checkVarDefs2(done2, defs2, body);
|
||||
}
|
||||
|
||||
else if (matchFunction1(e, name, body, pos)) {
|
||||
ATermMap defs2(defs);
|
||||
defs2.set(name, (ATerm) ATempty);
|
||||
set<Expr> done2;
|
||||
checkVarDefs2(done2, defs2, body);
|
||||
}
|
||||
|
||||
else if (matchRec(e, rbnds, nrbnds)) {
|
||||
checkVarDefs2(done, defs, (ATerm) nrbnds);
|
||||
ATermMap defs2(defs);
|
||||
for (ATermIterator i(rbnds); i; ++i) {
|
||||
if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
|
||||
defs2.set(name, (ATerm) ATempty);
|
||||
}
|
||||
for (ATermIterator i(nrbnds); i; ++i) {
|
||||
if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
|
||||
defs2.set(name, (ATerm) ATempty);
|
||||
}
|
||||
set<Expr> done2;
|
||||
checkVarDefs2(done2, defs2, (ATerm) rbnds);
|
||||
}
|
||||
body->bindVars(newEnv);
|
||||
}
|
||||
|
||||
else if (matchWith(e, with, body, pos)) {
|
||||
/* We can't check the body without evaluating the definitions
|
||||
(which is an arbitrary expression), so we don't do that
|
||||
here but only when actually evaluating the `with'. */
|
||||
checkVarDefs2(done, defs, with);
|
||||
}
|
||||
void ExprLet::bindVars(const StaticEnv & env)
|
||||
{
|
||||
StaticEnv newEnv(false, &env);
|
||||
|
||||
else if (ATgetType(e) == AT_APPL) {
|
||||
int arity = ATgetArity(ATgetAFun(e));
|
||||
for (int i = 0; i < arity; ++i)
|
||||
checkVarDefs2(done, defs, ATgetArgument(e, i));
|
||||
unsigned int displ = 0;
|
||||
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
||||
newEnv.vars[i->first] = displ++;
|
||||
|
||||
foreach (list<ExprAttrs::Inherited>::iterator, i, attrs->inherited) {
|
||||
newEnv.vars[i->first.name] = displ++;
|
||||
i->first.bind(env);
|
||||
}
|
||||
|
||||
else if (ATgetType(e) == AT_LIST)
|
||||
for (ATermIterator i((ATermList) e); i; ++i)
|
||||
checkVarDefs2(done, defs, *i);
|
||||
foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
|
||||
i->second.first->bindVars(newEnv);
|
||||
|
||||
body->bindVars(newEnv);
|
||||
}
|
||||
|
||||
|
||||
void checkVarDefs(const ATermMap & defs, Expr e)
|
||||
void ExprWith::bindVars(const StaticEnv & env)
|
||||
{
|
||||
set<Expr> done;
|
||||
checkVarDefs2(done, defs, e);
|
||||
}
|
||||
|
||||
|
||||
struct Canonicalise : TermFun
|
||||
{
|
||||
ATerm operator () (ATerm e)
|
||||
{
|
||||
/* Remove position info. */
|
||||
ATerm path;
|
||||
int line, column;
|
||||
if (matchPos(e, path, line, column))
|
||||
return makeNoPos();
|
||||
|
||||
/* Sort attribute sets. */
|
||||
ATermList _;
|
||||
if (matchAttrs(e, _)) {
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(e, attrs);
|
||||
StringSet names;
|
||||
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
|
||||
names.insert(aterm2String(i->key));
|
||||
|
||||
ATermList attrs2 = ATempty;
|
||||
for (StringSet::reverse_iterator i = names.rbegin(); i != names.rend(); ++i)
|
||||
attrs2 = ATinsert(attrs2,
|
||||
makeBind(toATerm(*i), attrs.get(toATerm(*i)), makeNoPos()));
|
||||
|
||||
return makeAttrs(attrs2);
|
||||
/* Does this `with' have an enclosing `with'? If so, record its
|
||||
level so that `lookupVar' can look up variables in the previous
|
||||
`with' if this one doesn't contain the desired attribute. */
|
||||
const StaticEnv * curEnv;
|
||||
unsigned int level;
|
||||
prevWith = 0;
|
||||
for (curEnv = &env, level = 1; curEnv; curEnv = curEnv->up, level++)
|
||||
if (curEnv->isWith) {
|
||||
prevWith = level;
|
||||
break;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
attrs->bindVars(env);
|
||||
StaticEnv newEnv(true, &env);
|
||||
body->bindVars(newEnv);
|
||||
}
|
||||
|
||||
|
||||
Expr canonicaliseExpr(Expr e)
|
||||
void ExprIf::bindVars(const StaticEnv & env)
|
||||
{
|
||||
Canonicalise canonicalise;
|
||||
return bottomupRewrite(canonicalise, e);
|
||||
cond->bindVars(env);
|
||||
then->bindVars(env);
|
||||
else_->bindVars(env);
|
||||
}
|
||||
|
||||
|
||||
Expr makeBool(bool b)
|
||||
void ExprAssert::bindVars(const StaticEnv & env)
|
||||
{
|
||||
return b ? eTrue : eFalse;
|
||||
cond->bindVars(env);
|
||||
body->bindVars(env);
|
||||
}
|
||||
|
||||
|
||||
bool matchStr(Expr e, string & s, PathSet & context)
|
||||
void ExprOpNot::bindVars(const StaticEnv & env)
|
||||
{
|
||||
ATermList l;
|
||||
ATerm s_;
|
||||
|
||||
if (!matchStr(e, s_, l)) return false;
|
||||
|
||||
s = aterm2String(s_);
|
||||
|
||||
for (ATermIterator i(l); i; ++i)
|
||||
context.insert(aterm2String(*i));
|
||||
|
||||
return true;
|
||||
e->bindVars(env);
|
||||
}
|
||||
|
||||
|
||||
Expr makeStr(const string & s, const PathSet & context)
|
||||
void ExprConcatStrings::bindVars(const StaticEnv & env)
|
||||
{
|
||||
return makeStr(toATerm(s), toATermList(context));
|
||||
foreach (vector<Expr *>::iterator, i, *es)
|
||||
(*i)->bindVars(env);
|
||||
}
|
||||
|
||||
|
||||
string showType(Expr e)
|
||||
{
|
||||
ATerm t1, t2, t3;
|
||||
ATermList l1;
|
||||
ATermBlob b1;
|
||||
int i1;
|
||||
if (matchStr(e, t1, l1)) return "a string";
|
||||
if (matchPath(e, t1)) return "a path";
|
||||
if (matchNull(e)) return "null";
|
||||
if (matchInt(e, i1)) return "an integer";
|
||||
if (matchBool(e, t1)) return "a boolean";
|
||||
if (matchFunction(e, l1, t1, t2)) return "a function";
|
||||
if (matchFunction1(e, t1, t2, t3)) return "a function";
|
||||
if (matchAttrs(e, l1)) return "an attribute set";
|
||||
if (matchList(e, l1)) return "a list";
|
||||
if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function";
|
||||
return "an unknown type";
|
||||
}
|
||||
|
||||
|
||||
string showValue(Expr e)
|
||||
{
|
||||
PathSet context;
|
||||
string s;
|
||||
ATerm s2;
|
||||
int i;
|
||||
if (matchStr(e, s, context)) {
|
||||
string u;
|
||||
for (string::iterator i = s.begin(); i != s.end(); ++i)
|
||||
if (*i == '\"' || *i == '\\') u += "\\" + *i;
|
||||
else if (*i == '\n') u += "\\n";
|
||||
else if (*i == '\r') u += "\\r";
|
||||
else if (*i == '\t') u += "\\t";
|
||||
else u += *i;
|
||||
return "\"" + u + "\"";
|
||||
}
|
||||
if (matchPath(e, s2)) return aterm2String(s2);
|
||||
if (matchNull(e)) return "null";
|
||||
if (matchInt(e, i)) return (format("%1%") % i).str();
|
||||
if (e == eTrue) return "true";
|
||||
if (e == eFalse) return "false";
|
||||
/* !!! incomplete */
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,120 +3,268 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "aterm-map.hh"
|
||||
#include "types.hh"
|
||||
#include "symbol-table.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
MakeError(EvalError, Error)
|
||||
MakeError(ParseError, Error)
|
||||
MakeError(AssertionError, EvalError)
|
||||
MakeError(ThrownError, AssertionError)
|
||||
MakeError(Abort, EvalError)
|
||||
MakeError(TypeError, EvalError)
|
||||
|
||||
|
||||
/* Nix expressions are represented as ATerms. The maximal sharing
|
||||
property of the ATerm library allows us to implement caching of
|
||||
normals forms efficiently. */
|
||||
typedef ATerm Expr;
|
||||
/* Position objects. */
|
||||
|
||||
typedef ATerm DefaultValue;
|
||||
typedef ATerm ValidValues;
|
||||
|
||||
typedef ATerm Pos;
|
||||
|
||||
|
||||
/* A STL vector of ATerms. Should be used with great care since it's
|
||||
stored on the heap, and the elements are therefore not roots to the
|
||||
ATerm garbage collector. */
|
||||
typedef vector<ATerm> ATermVector;
|
||||
|
||||
|
||||
/* A substitution is a linked list of ATermMaps that map names to
|
||||
identifiers. We use a list of ATermMaps rather than a single to
|
||||
make it easy to grow or shrink a substitution when entering a
|
||||
scope. */
|
||||
struct Substitution
|
||||
struct Pos
|
||||
{
|
||||
ATermMap * map;
|
||||
const Substitution * prev;
|
||||
string file;
|
||||
unsigned int line, column;
|
||||
Pos() : line(0), column(0) { };
|
||||
Pos(const string & file, unsigned int line, unsigned int column)
|
||||
: file(file), line(line), column(column) { };
|
||||
};
|
||||
|
||||
Substitution(const Substitution * prev, ATermMap * map)
|
||||
{
|
||||
this->prev = prev;
|
||||
this->map = map;
|
||||
}
|
||||
extern Pos noPos;
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Pos & pos);
|
||||
|
||||
|
||||
struct Env;
|
||||
struct Value;
|
||||
struct EvalState;
|
||||
struct StaticEnv;
|
||||
|
||||
|
||||
/* Abstract syntax of Nix expressions. */
|
||||
|
||||
struct Expr
|
||||
{
|
||||
virtual void show(std::ostream & str);
|
||||
virtual void bindVars(const StaticEnv & env);
|
||||
virtual void eval(EvalState & state, Env & env, Value & v);
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, Expr & e);
|
||||
|
||||
#define COMMON_METHODS \
|
||||
void show(std::ostream & str); \
|
||||
void eval(EvalState & state, Env & env, Value & v); \
|
||||
void bindVars(const StaticEnv & env);
|
||||
|
||||
struct ExprInt : Expr
|
||||
{
|
||||
int n;
|
||||
ExprInt(int n) : n(n) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprString : Expr
|
||||
{
|
||||
string s;
|
||||
ExprString(const string & s) : s(s) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
/* Temporary class used during parsing of indented strings. */
|
||||
struct ExprIndStr : Expr
|
||||
{
|
||||
string s;
|
||||
ExprIndStr(const string & s) : s(s) { };
|
||||
};
|
||||
|
||||
struct ExprPath : Expr
|
||||
{
|
||||
string s;
|
||||
ExprPath(const string & s) : s(s) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct VarRef
|
||||
{
|
||||
Symbol name;
|
||||
|
||||
/* Whether the variable comes from an environment (e.g. a rec, let
|
||||
or function argument) or from a "with". */
|
||||
bool fromWith;
|
||||
|
||||
Expr lookup(Expr name) const
|
||||
{
|
||||
Expr x;
|
||||
for (const Substitution * s(this); s; s = s->prev)
|
||||
if ((x = s->map->get(name))) return x;
|
||||
return 0;
|
||||
}
|
||||
/* 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.*/
|
||||
unsigned int level;
|
||||
unsigned int displ;
|
||||
|
||||
VarRef(const Symbol & name) : name(name) { };
|
||||
void bind(const StaticEnv & env);
|
||||
};
|
||||
|
||||
|
||||
/* Show a position. */
|
||||
string showPos(ATerm pos);
|
||||
|
||||
/* Generic bottomup traversal over ATerms. The traversal first
|
||||
recursively descends into subterms, and then applies the given term
|
||||
function to the resulting term. */
|
||||
struct TermFun
|
||||
struct ExprVar : Expr
|
||||
{
|
||||
virtual ~TermFun() { }
|
||||
virtual ATerm operator () (ATerm e) = 0;
|
||||
VarRef info;
|
||||
ExprVar(const Symbol & name) : info(name) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprSelect : Expr
|
||||
{
|
||||
Expr * e;
|
||||
Symbol name;
|
||||
ExprSelect(Expr * e, const Symbol & name) : e(e), name(name) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprOpHasAttr : Expr
|
||||
{
|
||||
Expr * e;
|
||||
Symbol name;
|
||||
ExprOpHasAttr(Expr * e, const Symbol & name) : e(e), name(name) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprAttrs : Expr
|
||||
{
|
||||
bool recursive;
|
||||
typedef std::pair<Expr *, Pos> Attr;
|
||||
typedef std::pair<VarRef, Pos> Inherited;
|
||||
typedef std::map<Symbol, Attr> Attrs;
|
||||
Attrs attrs;
|
||||
list<Inherited> inherited;
|
||||
std::map<Symbol, Pos> attrNames; // used during parsing
|
||||
ExprAttrs() : recursive(false) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprList : Expr
|
||||
{
|
||||
std::vector<Expr *> elems;
|
||||
ExprList() { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct Formal
|
||||
{
|
||||
Symbol name;
|
||||
Expr * def;
|
||||
Formal(const Symbol & name, Expr * def) : name(name), def(def) { };
|
||||
};
|
||||
|
||||
struct Formals
|
||||
{
|
||||
typedef std::list<Formal> Formals_;
|
||||
Formals_ formals;
|
||||
std::set<Symbol> argNames; // used during parsing
|
||||
bool ellipsis;
|
||||
};
|
||||
|
||||
struct ExprLambda : Expr
|
||||
{
|
||||
Pos pos;
|
||||
Symbol arg;
|
||||
bool matchAttrs;
|
||||
Formals * formals;
|
||||
Expr * body;
|
||||
ExprLambda(const Pos & pos, const Symbol & arg, bool matchAttrs, Formals * formals, Expr * body)
|
||||
: pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body)
|
||||
{
|
||||
if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
|
||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||
% arg % pos);
|
||||
};
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprLet : Expr
|
||||
{
|
||||
ExprAttrs * attrs;
|
||||
Expr * body;
|
||||
ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprWith : Expr
|
||||
{
|
||||
Pos pos;
|
||||
Expr * attrs, * body;
|
||||
unsigned int prevWith;
|
||||
ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprIf : Expr
|
||||
{
|
||||
Expr * cond, * then, * else_;
|
||||
ExprIf(Expr * cond, Expr * then, Expr * else_) : cond(cond), then(then), else_(else_) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprAssert : Expr
|
||||
{
|
||||
Pos pos;
|
||||
Expr * cond, * body;
|
||||
ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
struct ExprOpNot : Expr
|
||||
{
|
||||
Expr * e;
|
||||
ExprOpNot(Expr * e) : e(e) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
||||
#define MakeBinOp(name, s) \
|
||||
struct Expr##name : Expr \
|
||||
{ \
|
||||
Expr * e1, * e2; \
|
||||
Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
|
||||
void show(std::ostream & str) \
|
||||
{ \
|
||||
str << *e1 << " " s " " << *e2; \
|
||||
} \
|
||||
void bindVars(const StaticEnv & env) \
|
||||
{ \
|
||||
e1->bindVars(env); e2->bindVars(env); \
|
||||
} \
|
||||
void eval(EvalState & state, Env & env, Value & v); \
|
||||
};
|
||||
|
||||
MakeBinOp(App, "")
|
||||
MakeBinOp(OpEq, "==")
|
||||
MakeBinOp(OpNEq, "!=")
|
||||
MakeBinOp(OpAnd, "&&")
|
||||
MakeBinOp(OpOr, "||")
|
||||
MakeBinOp(OpImpl, "->")
|
||||
MakeBinOp(OpUpdate, "//")
|
||||
MakeBinOp(OpConcatLists, "++")
|
||||
|
||||
struct ExprConcatStrings : Expr
|
||||
{
|
||||
vector<Expr *> * es;
|
||||
ExprConcatStrings(vector<Expr *> * es) : es(es) { };
|
||||
COMMON_METHODS
|
||||
};
|
||||
ATerm bottomupRewrite(TermFun & f, ATerm e);
|
||||
|
||||
|
||||
/* Query all attributes in an attribute set expression. The
|
||||
expression must be in normal form. */
|
||||
void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false);
|
||||
|
||||
/* Query a specific attribute from an attribute set expression. The
|
||||
expression must be in normal form. */
|
||||
Expr queryAttr(Expr e, const string & name);
|
||||
Expr queryAttr(Expr e, const string & name, ATerm & pos);
|
||||
|
||||
/* Create an attribute set expression from an Attrs value. */
|
||||
Expr makeAttrs(const ATermMap & attrs);
|
||||
/* Static environments are used to map variable names onto (level,
|
||||
displacement) pairs used to obtain the value of the variable at
|
||||
runtime. */
|
||||
struct StaticEnv
|
||||
{
|
||||
bool isWith;
|
||||
const StaticEnv * up;
|
||||
typedef std::map<Symbol, unsigned int> Vars;
|
||||
Vars vars;
|
||||
StaticEnv(bool isWith, const StaticEnv * up) : isWith(isWith), up(up) { };
|
||||
};
|
||||
|
||||
|
||||
/* Perform a set of substitutions on an expression. */
|
||||
Expr substitute(const Substitution & subs, Expr e);
|
||||
|
||||
|
||||
/* Check whether all variables are defined in the given expression.
|
||||
Throw an exception if this isn't the case. */
|
||||
void checkVarDefs(const ATermMap & def, Expr e);
|
||||
|
||||
|
||||
/* Canonicalise a Nix expression by sorting attributes and removing
|
||||
location information. */
|
||||
Expr canonicaliseExpr(Expr e);
|
||||
|
||||
|
||||
/* Create an expression representing a boolean. */
|
||||
Expr makeBool(bool b);
|
||||
|
||||
|
||||
/* Manipulation of Str() nodes. Note: matchStr() does not clear
|
||||
context! */
|
||||
bool matchStr(Expr e, string & s, PathSet & context);
|
||||
|
||||
Expr makeStr(const string & s, const PathSet & context = PathSet());
|
||||
|
||||
|
||||
/* Showing types, values. */
|
||||
string showType(Expr e);
|
||||
|
||||
string showValue(Expr e);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,11 @@ namespace nix {
|
||||
|
||||
|
||||
/* Parse a Nix expression from the specified file. If `path' refers
|
||||
to a directory, the "/default.nix" is appended. */
|
||||
Expr parseExprFromFile(EvalState & state, Path path);
|
||||
to a directory, then "/default.nix" is appended. */
|
||||
Expr * parseExprFromFile(EvalState & state, Path path);
|
||||
|
||||
/* Parse a Nix expression from the specified string. */
|
||||
Expr parseExprFromString(EvalState & state, const string & s,
|
||||
const Path & basePath);
|
||||
Expr * parseExprFromString(EvalState & state, const string & s, const Path & basePath);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -20,14 +20,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "aterm.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include "nixexpr.hh"
|
||||
|
||||
#include "parser-tab.hh"
|
||||
#include "lexer-tab.hh"
|
||||
|
||||
#include "nixexpr.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
||||
|
||||
|
||||
using namespace nix;
|
||||
@@ -38,46 +37,181 @@ namespace nix {
|
||||
|
||||
struct ParseData
|
||||
{
|
||||
Expr result;
|
||||
SymbolTable & symbols;
|
||||
Expr * result;
|
||||
Path basePath;
|
||||
Path path;
|
||||
string error;
|
||||
Symbol sLetBody;
|
||||
ParseData(SymbolTable & symbols)
|
||||
: symbols(symbols)
|
||||
, sLetBody(symbols.create("<let-body>"))
|
||||
{ };
|
||||
};
|
||||
|
||||
|
||||
static Expr fixAttrs(int recursive, ATermList as)
|
||||
static string showAttrPath(const vector<Symbol> & attrPath)
|
||||
{
|
||||
ATermList bs = ATempty, cs = ATempty;
|
||||
ATermList * is = recursive ? &cs : &bs;
|
||||
for (ATermIterator i(as); i; ++i) {
|
||||
ATermList names;
|
||||
Expr src;
|
||||
ATerm pos;
|
||||
if (matchInherit(*i, src, names, pos)) {
|
||||
bool fromScope = matchScope(src);
|
||||
for (ATermIterator j(names); j; ++j) {
|
||||
Expr rhs = fromScope ? makeVar(*j) : makeSelect(src, *j);
|
||||
*is = ATinsert(*is, makeBind(*j, rhs, pos));
|
||||
}
|
||||
} else bs = ATinsert(bs, *i);
|
||||
string s;
|
||||
foreach (vector<Symbol>::const_iterator, i, attrPath) {
|
||||
if (!s.empty()) s += '.';
|
||||
s += *i;
|
||||
}
|
||||
if (recursive)
|
||||
return makeRec(bs, cs);
|
||||
else
|
||||
return makeAttrs(bs);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static void dupAttr(const vector<Symbol> & 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)
|
||||
{
|
||||
vector<Symbol> attrPath; attrPath.push_back(attr);
|
||||
throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
|
||||
% showAttrPath(attrPath) % pos % prevPos);
|
||||
}
|
||||
|
||||
|
||||
static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
|
||||
Expr * e, const Pos & pos)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
foreach (vector<Symbol>::const_iterator, i, attrPath) {
|
||||
n++;
|
||||
ExprAttrs::Attrs::iterator j = attrs->attrs.find(*i);
|
||||
if (j != attrs->attrs.end()) {
|
||||
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.first);
|
||||
if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos, j->second.second);
|
||||
attrs = attrs2;
|
||||
} else {
|
||||
if (attrs->attrNames.find(*i) != attrs->attrNames.end())
|
||||
dupAttr(attrPath, pos, attrs->attrNames[*i]);
|
||||
attrs->attrNames[*i] = pos;
|
||||
if (n == attrPath.size())
|
||||
attrs->attrs[*i] = ExprAttrs::Attr(e, pos);
|
||||
else {
|
||||
ExprAttrs * nested = new ExprAttrs;
|
||||
attrs->attrs[*i] = ExprAttrs::Attr(nested, pos);
|
||||
attrs = nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
|
||||
{
|
||||
if (formals->argNames.find(formal.name) != formals->argNames.end())
|
||||
throw ParseError(format("duplicate formal function argument `%1%' at %2%")
|
||||
% formal.name % pos);
|
||||
formals->formals.push_front(formal);
|
||||
formals->argNames.insert(formal.name);
|
||||
}
|
||||
|
||||
|
||||
static Expr * stripIndentation(vector<Expr *> & es)
|
||||
{
|
||||
if (es.empty()) return new ExprString("");
|
||||
|
||||
/* 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.) */
|
||||
bool atStartOfLine = true; /* = seen only whitespace in the current line */
|
||||
unsigned int minIndent = 1000000;
|
||||
unsigned int curIndent = 0;
|
||||
foreach (vector<Expr *>::iterator, i, es) {
|
||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
|
||||
if (!e) {
|
||||
/* Anti-quotations end the current start-of-line whitespace. */
|
||||
if (atStartOfLine) {
|
||||
atStartOfLine = false;
|
||||
if (curIndent < minIndent) minIndent = curIndent;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (unsigned int j = 0; j < e->s.size(); ++j) {
|
||||
if (atStartOfLine) {
|
||||
if (e->s[j] == ' ')
|
||||
curIndent++;
|
||||
else if (e->s[j] == '\n') {
|
||||
/* Empty line, doesn't influence minimum
|
||||
indentation. */
|
||||
curIndent = 0;
|
||||
} else {
|
||||
atStartOfLine = false;
|
||||
if (curIndent < minIndent) minIndent = curIndent;
|
||||
}
|
||||
} else if (e->s[j] == '\n') {
|
||||
atStartOfLine = true;
|
||||
curIndent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip spaces from each line. */
|
||||
vector<Expr *> * es2 = new vector<Expr *>;
|
||||
atStartOfLine = true;
|
||||
unsigned int curDropped = 0;
|
||||
unsigned int n = es.size();
|
||||
for (vector<Expr *>::iterator i = es.begin(); i != es.end(); ++i, --n) {
|
||||
ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
|
||||
if (!e) {
|
||||
atStartOfLine = false;
|
||||
curDropped = 0;
|
||||
es2->push_back(*i);
|
||||
continue;
|
||||
}
|
||||
|
||||
string s2;
|
||||
for (unsigned int j = 0; j < e->s.size(); ++j) {
|
||||
if (atStartOfLine) {
|
||||
if (e->s[j] == ' ') {
|
||||
if (curDropped++ >= minIndent)
|
||||
s2 += e->s[j];
|
||||
}
|
||||
else if (e->s[j] == '\n') {
|
||||
curDropped = 0;
|
||||
s2 += e->s[j];
|
||||
} else {
|
||||
atStartOfLine = false;
|
||||
curDropped = 0;
|
||||
s2 += e->s[j];
|
||||
}
|
||||
} else {
|
||||
s2 += e->s[j];
|
||||
if (e->s[j] == '\n') atStartOfLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the last line if it is empty and consists only of
|
||||
spaces. */
|
||||
if (n == 1) {
|
||||
string::size_type p = s2.find_last_of('\n');
|
||||
if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos)
|
||||
s2 = string(s2, 0, p + 1);
|
||||
}
|
||||
|
||||
es2->push_back(new ExprString(s2));
|
||||
}
|
||||
|
||||
return new ExprConcatStrings(es2);
|
||||
}
|
||||
|
||||
|
||||
void backToString(yyscan_t scanner);
|
||||
void backToIndString(yyscan_t scanner);
|
||||
|
||||
|
||||
static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
|
||||
|
||||
static Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
|
||||
{
|
||||
return makePos(toATerm(data->path),
|
||||
loc->first_line, loc->first_column);
|
||||
return Pos(data->path, loc.first_line, loc.first_column);
|
||||
}
|
||||
|
||||
#define CUR_POS makeCurPos(yylocp, data)
|
||||
#define CUR_POS makeCurPos(*yylocp, data)
|
||||
|
||||
|
||||
}
|
||||
@@ -85,46 +219,47 @@ static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
|
||||
|
||||
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
|
||||
{
|
||||
data->error = (format("%1%, at `%2%':%3%:%4%")
|
||||
% error % data->path % loc->first_line % loc->first_column).str();
|
||||
data->error = (format("%1%, at %2%")
|
||||
% error % makeCurPos(*loc, data)).str();
|
||||
}
|
||||
|
||||
|
||||
/* Make sure that the parse stack is scanned by the ATerm garbage
|
||||
collector. */
|
||||
static void * mallocAndProtect(size_t size)
|
||||
{
|
||||
void * p = malloc(size);
|
||||
if (p) ATprotectMemory(p, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void freeAndUnprotect(void * p)
|
||||
{
|
||||
ATunprotectMemory(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
#define YYMALLOC mallocAndProtect
|
||||
#define YYFREE freeAndUnprotect
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
ATerm t;
|
||||
ATermList ts;
|
||||
nix::Expr * e;
|
||||
nix::ExprList * list;
|
||||
nix::ExprAttrs * attrs;
|
||||
nix::Formals * formals;
|
||||
nix::Formal * formal;
|
||||
int n;
|
||||
char * id; // !!! -> Symbol
|
||||
char * path;
|
||||
char * uri;
|
||||
std::vector<nix::Symbol> * ids;
|
||||
std::vector<nix::Expr *> * string_parts;
|
||||
}
|
||||
|
||||
%type <t> start expr expr_function expr_if expr_op
|
||||
%type <t> expr_app expr_select expr_simple bind inheritsrc formal
|
||||
%type <ts> binds ids expr_list formals string_parts
|
||||
%token <t> ID INT STR PATH URI
|
||||
%type <e> start expr expr_function expr_if expr_op
|
||||
%type <e> expr_app expr_select expr_simple
|
||||
%type <list> expr_list
|
||||
%type <attrs> binds
|
||||
%type <formals> formals
|
||||
%type <formal> formal
|
||||
%type <ids> ids attrpath
|
||||
%type <string_parts> string_parts ind_string_parts
|
||||
%token <id> ID ATTRPATH
|
||||
%token <e> STR IND_STR
|
||||
%token <n> INT
|
||||
%token <path> PATH
|
||||
%token <uri> URI
|
||||
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
|
||||
%token DOLLAR_CURLY /* == ${ */
|
||||
%token IND_STRING_OPEN IND_STRING_CLOSE
|
||||
%token ELLIPSIS
|
||||
|
||||
%nonassoc IMPL
|
||||
%left OR
|
||||
@@ -144,197 +279,172 @@ start: expr { data->result = $1; };
|
||||
expr: expr_function;
|
||||
|
||||
expr_function
|
||||
: '{' formals '}' ':' expr_function
|
||||
{ $$ = makeFunction($2, $5, CUR_POS); }
|
||||
| ID ':' expr_function
|
||||
{ $$ = makeFunction1($1, $3, CUR_POS); }
|
||||
: ID ':' expr_function
|
||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create($1), false, 0, $3); }
|
||||
| '{' formals '}' ':' expr_function
|
||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create(""), true, $2, $5); }
|
||||
| '{' formals '}' '@' ID ':' expr_function
|
||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create($5), true, $2, $7); }
|
||||
| ID '@' '{' formals '}' ':' expr_function
|
||||
{ $$ = new ExprLambda(CUR_POS, data->symbols.create($1), true, $4, $7); }
|
||||
| ASSERT expr ';' expr_function
|
||||
{ $$ = makeAssert($2, $4, CUR_POS); }
|
||||
{ $$ = new ExprAssert(CUR_POS, $2, $4); }
|
||||
| WITH expr ';' expr_function
|
||||
{ $$ = makeWith($2, $4, CUR_POS); }
|
||||
{ $$ = new ExprWith(CUR_POS, $2, $4); }
|
||||
| LET binds IN expr_function
|
||||
{ $$ = makeSelect(fixAttrs(1, ATinsert($2, makeBind(toATerm("<let-body>"), $4, CUR_POS))), toATerm("<let-body>")); }
|
||||
{ $$ = new ExprLet($2, $4); }
|
||||
| expr_if
|
||||
;
|
||||
|
||||
expr_if
|
||||
: IF expr THEN expr ELSE expr
|
||||
{ $$ = makeIf($2, $4, $6); }
|
||||
: IF expr THEN expr ELSE expr { $$ = new ExprIf($2, $4, $6); }
|
||||
| expr_op
|
||||
;
|
||||
|
||||
expr_op
|
||||
: '!' expr_op %prec NEG { $$ = makeOpNot($2); }
|
||||
| expr_op EQ expr_op { $$ = makeOpEq($1, $3); }
|
||||
| expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); }
|
||||
| expr_op AND expr_op { $$ = makeOpAnd($1, $3); }
|
||||
| expr_op OR expr_op { $$ = makeOpOr($1, $3); }
|
||||
| expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); }
|
||||
| expr_op UPDATE expr_op { $$ = makeOpUpdate($1, $3); }
|
||||
| expr_op '~' expr_op { $$ = makeSubPath($1, $3); }
|
||||
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
|
||||
| expr_op '+' expr_op { $$ = makeOpPlus($1, $3); }
|
||||
| expr_op CONCAT expr_op { $$ = makeOpConcat($1, $3); }
|
||||
: '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
|
||||
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||
| expr_op NEQ expr_op { $$ = new ExprOpNEq($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); }
|
||||
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); }
|
||||
| expr_op '?' ID { $$ = new ExprOpHasAttr($1, data->symbols.create($3)); }
|
||||
| expr_op '+' expr_op
|
||||
{ vector<Expr *> * l = new vector<Expr *>;
|
||||
l->push_back($1);
|
||||
l->push_back($3);
|
||||
$$ = new ExprConcatStrings(l);
|
||||
}
|
||||
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
||||
| expr_app
|
||||
;
|
||||
|
||||
expr_app
|
||||
: expr_app expr_select
|
||||
{ $$ = makeCall($1, $2); }
|
||||
{ $$ = new ExprApp($1, $2); }
|
||||
| expr_select { $$ = $1; }
|
||||
;
|
||||
|
||||
expr_select
|
||||
: expr_select '.' ID
|
||||
{ $$ = makeSelect($1, $3); }
|
||||
{ $$ = new ExprSelect($1, data->symbols.create($3)); }
|
||||
| expr_simple { $$ = $1; }
|
||||
;
|
||||
|
||||
expr_simple
|
||||
: ID { $$ = makeVar($1); }
|
||||
| INT { $$ = makeInt(ATgetInt((ATermInt) $1)); }
|
||||
: ID { $$ = new ExprVar(data->symbols.create($1)); }
|
||||
| INT { $$ = new ExprInt($1); }
|
||||
| '"' string_parts '"' {
|
||||
/* For efficiency, and to simplify parse trees a bit. */
|
||||
if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
|
||||
else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
|
||||
else $$ = makeConcatStrings(ATreverse($2));
|
||||
if ($2->empty()) $$ = new ExprString("");
|
||||
else if ($2->size() == 1) $$ = $2->front();
|
||||
else $$ = new ExprConcatStrings($2);
|
||||
}
|
||||
| PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); }
|
||||
| URI { $$ = makeStr($1, ATempty); }
|
||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||
$$ = stripIndentation(*$2);
|
||||
}
|
||||
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
|
||||
| URI { $$ = new ExprString($1); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
/* Let expressions `let {..., body = ...}' are just desugared
|
||||
into `(rec {..., body = ...}).body'. */
|
||||
| LET '{' binds '}'
|
||||
{ $$ = makeSelect(fixAttrs(1, $3), toATerm("body")); }
|
||||
{ $3->recursive = true; $$ = new ExprSelect($3, data->symbols.create("body")); }
|
||||
| REC '{' binds '}'
|
||||
{ $$ = fixAttrs(1, $3); }
|
||||
{ $3->recursive = true; $$ = $3; }
|
||||
| '{' binds '}'
|
||||
{ $$ = fixAttrs(0, $2); }
|
||||
| '[' expr_list ']' { $$ = makeList($2); }
|
||||
{ $$ = $2; }
|
||||
| '[' expr_list ']' { $$ = $2; }
|
||||
;
|
||||
|
||||
string_parts
|
||||
: string_parts STR { $$ = ATinsert($1, $2); }
|
||||
| string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = ATinsert($1, $3); }
|
||||
| { $$ = ATempty; }
|
||||
: string_parts STR { $$ = $1; $1->push_back($2); }
|
||||
| string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
|
||||
| { $$ = new vector<Expr *>; }
|
||||
;
|
||||
|
||||
ind_string_parts
|
||||
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
|
||||
| ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = $1; $1->push_back($3); }
|
||||
| { $$ = new vector<Expr *>; }
|
||||
;
|
||||
|
||||
binds
|
||||
: binds bind { $$ = ATinsert($1, $2); }
|
||||
| { $$ = ATempty; }
|
||||
: binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
|
||||
| binds INHERIT ids ';'
|
||||
{ $$ = $1;
|
||||
foreach (vector<Symbol>::iterator, i, *$3) {
|
||||
if ($$->attrNames.find(*i) != $$->attrNames.end())
|
||||
dupAttr(*i, makeCurPos(@3, data), $$->attrNames[*i]);
|
||||
Pos pos = makeCurPos(@3, data);
|
||||
$$->inherited.push_back(ExprAttrs::Inherited(*i, pos));
|
||||
$$->attrNames[*i] = pos;
|
||||
}
|
||||
}
|
||||
| binds INHERIT '(' expr ')' ids ';'
|
||||
{ $$ = $1;
|
||||
/* !!! Should ensure sharing of the expression in $4. */
|
||||
foreach (vector<Symbol>::iterator, i, *$6) {
|
||||
if ($$->attrNames.find(*i) != $$->attrNames.end())
|
||||
dupAttr(*i, makeCurPos(@6, data), $$->attrNames[*i]);
|
||||
$$->attrs[*i] = ExprAttrs::Attr(new ExprSelect($4, *i), makeCurPos(@6, data));
|
||||
$$->attrNames[*i] = makeCurPos(@6, data);
|
||||
}}
|
||||
|
||||
| { $$ = new ExprAttrs; }
|
||||
;
|
||||
|
||||
bind
|
||||
: ID '=' expr ';'
|
||||
{ $$ = makeBind($1, $3, CUR_POS); }
|
||||
| INHERIT inheritsrc ids ';'
|
||||
{ $$ = makeInherit($2, $3, CUR_POS); }
|
||||
ids
|
||||
: ids ID { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! dangerous */ }
|
||||
| { $$ = new vector<Symbol>; }
|
||||
;
|
||||
|
||||
inheritsrc
|
||||
: '(' expr ')' { $$ = $2; }
|
||||
| { $$ = makeScope(); }
|
||||
attrpath
|
||||
: attrpath '.' ID { $$ = $1; $1->push_back(data->symbols.create($3)); }
|
||||
| ID { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
|
||||
;
|
||||
|
||||
ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };
|
||||
|
||||
expr_list
|
||||
: expr_select expr_list { $$ = ATinsert($2, $1); }
|
||||
/* yes, this is right-recursive, but it doesn't matter since
|
||||
otherwise we would need ATreverse which requires unbounded
|
||||
stack space */
|
||||
| { $$ = ATempty; }
|
||||
: expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ }
|
||||
| { $$ = new ExprList; }
|
||||
;
|
||||
|
||||
formals
|
||||
: formal ',' formals { $$ = ATinsert($3, $1); } /* idem - right recursive */
|
||||
| formal { $$ = ATinsert(ATempty, $1); }
|
||||
| { $$ = ATempty; }
|
||||
: formal ',' formals
|
||||
{ $$ = $3; addFormal(CUR_POS, $$, *$1); }
|
||||
| formal
|
||||
{ $$ = new Formals; addFormal(CUR_POS, $$, *$1); $$->ellipsis = false; }
|
||||
|
|
||||
{ $$ = new Formals; $$->ellipsis = false; }
|
||||
| ELLIPSIS
|
||||
{ $$ = new Formals; $$->ellipsis = true; }
|
||||
;
|
||||
|
||||
formal
|
||||
: ID { $$ = makeFormal($1, makeUnrestrictedValues(), makeNoDefaultValue()); }
|
||||
| ID ':' '[' expr_list ']' { $$ = makeFormal($1, makeValidValues($4), makeNoDefaultValue()); }
|
||||
| ID '?' expr { $$ = makeFormal($1, makeUnrestrictedValues(), makeDefaultValue($3)); }
|
||||
: ID { $$ = new Formal(data->symbols.create($1), 0); }
|
||||
| ID '?' expr { $$ = new Formal(data->symbols.create($1), $3); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <eval.hh>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
static void checkAttrs(ATermMap & names, ATermList bnds)
|
||||
{
|
||||
for (ATermIterator i(bnds); i; ++i) {
|
||||
ATerm name;
|
||||
Expr e;
|
||||
ATerm pos;
|
||||
if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
|
||||
if (names.get(name))
|
||||
throw EvalError(format("duplicate attribute `%1%' at %2%")
|
||||
% aterm2String(name) % showPos(pos));
|
||||
names.set(name, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void checkAttrSets(ATerm e)
|
||||
{
|
||||
ATermList formals;
|
||||
ATerm body, pos;
|
||||
if (matchFunction(e, formals, body, pos)) {
|
||||
ATermMap names(ATgetLength(formals));
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
ATerm name;
|
||||
ATerm d1, d2;
|
||||
if (!matchFormal(*i, name, d1, d2)) abort();
|
||||
if (names.get(name))
|
||||
throw EvalError(format("duplicate formal function argument `%1%' at %2%")
|
||||
% aterm2String(name) % showPos(pos));
|
||||
names.set(name, name);
|
||||
}
|
||||
}
|
||||
|
||||
ATermList bnds;
|
||||
if (matchAttrs(e, bnds)) {
|
||||
ATermMap names(ATgetLength(bnds));
|
||||
checkAttrs(names, bnds);
|
||||
}
|
||||
|
||||
ATermList rbnds, nrbnds;
|
||||
if (matchRec(e, rbnds, nrbnds)) {
|
||||
ATermMap names(ATgetLength(rbnds) + ATgetLength(nrbnds));
|
||||
checkAttrs(names, rbnds);
|
||||
checkAttrs(names, nrbnds);
|
||||
}
|
||||
|
||||
if (ATgetType(e) == AT_APPL) {
|
||||
int arity = ATgetArity(ATgetAFun(e));
|
||||
for (int i = 0; i < arity; ++i)
|
||||
checkAttrSets(ATgetArgument(e, i));
|
||||
}
|
||||
|
||||
else if (ATgetType(e) == AT_LIST)
|
||||
for (ATermIterator i((ATermList) e); i; ++i)
|
||||
checkAttrSets(*i);
|
||||
}
|
||||
|
||||
|
||||
static Expr parse(EvalState & state,
|
||||
const char * text, const Path & path,
|
||||
const Path & basePath)
|
||||
static Expr * parse(EvalState & state, const char * text,
|
||||
const Path & path, const Path & basePath)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
ParseData data;
|
||||
ParseData data(state.symbols);
|
||||
data.basePath = basePath;
|
||||
data.path = path;
|
||||
|
||||
@@ -343,30 +453,22 @@ static Expr parse(EvalState & state,
|
||||
int res = yyparse(scanner, &data);
|
||||
yylex_destroy(scanner);
|
||||
|
||||
if (res) throw EvalError(data.error);
|
||||
if (res) throw ParseError(data.error);
|
||||
|
||||
try {
|
||||
checkVarDefs(state.primOps, data.result);
|
||||
data.result->bindVars(state.staticBaseEnv);
|
||||
} catch (Error & e) {
|
||||
throw EvalError(format("%1%, in `%2%'") % e.msg() % path);
|
||||
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
|
||||
}
|
||||
|
||||
checkAttrSets(data.result);
|
||||
|
||||
return data.result;
|
||||
}
|
||||
|
||||
|
||||
Expr parseExprFromFile(EvalState & state, Path path)
|
||||
Expr * parseExprFromFile(EvalState & state, Path path)
|
||||
{
|
||||
assert(path[0] == '/');
|
||||
|
||||
#if 0
|
||||
/* Perhaps this is already an imploded parse tree? */
|
||||
Expr e = ATreadFromNamedFile(path.c_str());
|
||||
if (e) return e;
|
||||
#endif
|
||||
|
||||
/* If `path' is a symlink, follow it. This is so that relative
|
||||
path references work. */
|
||||
struct stat st;
|
||||
@@ -388,7 +490,7 @@ Expr parseExprFromFile(EvalState & state, Path path)
|
||||
}
|
||||
|
||||
|
||||
Expr parseExprFromString(EvalState & state,
|
||||
Expr * parseExprFromString(EvalState & state,
|
||||
const string & s, const Path & basePath)
|
||||
{
|
||||
return parse(state, s.c_str(), "(string)", basePath);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
81
src/libexpr/symbol-table.hh
Normal file
81
src/libexpr/symbol-table.hh
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef __SYMBOL_TABLE_H
|
||||
#define __SYMBOL_TABLE_H
|
||||
|
||||
#include <map>
|
||||
#include <tr1/unordered_set>
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
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. */
|
||||
|
||||
class Symbol
|
||||
{
|
||||
private:
|
||||
const string * s; // pointer into SymbolTable
|
||||
Symbol(const string * s) : s(s) { };
|
||||
friend class SymbolTable;
|
||||
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
operator const string & () const
|
||||
{
|
||||
return *s;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return s->empty();
|
||||
}
|
||||
|
||||
friend std::ostream & operator << (std::ostream & str, const Symbol & sym);
|
||||
};
|
||||
|
||||
inline std::ostream & operator << (std::ostream & str, const Symbol & sym)
|
||||
{
|
||||
str << *sym.s;
|
||||
return str;
|
||||
}
|
||||
|
||||
class SymbolTable
|
||||
{
|
||||
private:
|
||||
typedef std::tr1::unordered_set<string> Symbols;
|
||||
Symbols symbols;
|
||||
|
||||
public:
|
||||
Symbol create(const string & s)
|
||||
{
|
||||
std::pair<Symbols::iterator, bool> res = symbols.insert(s);
|
||||
return Symbol(&*res.first);
|
||||
}
|
||||
|
||||
unsigned int size() const
|
||||
{
|
||||
return symbols.size();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__SYMBOL_TABLE_H */
|
||||
161
src/libexpr/value-to-xml.cc
Normal file
161
src/libexpr/value-to-xml.cc
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "value-to-xml.hh"
|
||||
#include "xml-writer.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
static XMLAttrs singletonAttrs(const string & name, const string & value)
|
||||
{
|
||||
XMLAttrs attrs;
|
||||
attrs[name] = value;
|
||||
return attrs;
|
||||
}
|
||||
|
||||
|
||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen);
|
||||
|
||||
|
||||
static void posToXML(XMLAttrs & xmlAttrs, const Pos & pos)
|
||||
{
|
||||
xmlAttrs["path"] = pos.file;
|
||||
xmlAttrs["line"] = (format("%1%") % pos.line).str();
|
||||
xmlAttrs["column"] = (format("%1%") % pos.column).str();
|
||||
}
|
||||
|
||||
|
||||
static void showAttrs(EvalState & state, bool strict, bool location,
|
||||
Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
||||
{
|
||||
StringSet names;
|
||||
|
||||
foreach (Bindings::iterator, i, attrs)
|
||||
names.insert(i->first);
|
||||
|
||||
foreach (StringSet::iterator, i, names) {
|
||||
Attr & a(attrs[state.symbols.create(*i)]);
|
||||
|
||||
XMLAttrs xmlAttrs;
|
||||
xmlAttrs["name"] = *i;
|
||||
if (location && a.pos != &noPos) posToXML(xmlAttrs, *a.pos);
|
||||
|
||||
XMLOpenElement _(doc, "attr", xmlAttrs);
|
||||
printValueAsXML(state, strict, location,
|
||||
a.value, doc, context, drvsSeen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
if (strict) state.forceValue(v);
|
||||
|
||||
switch (v.type) {
|
||||
|
||||
case tInt:
|
||||
doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str()));
|
||||
break;
|
||||
|
||||
case tBool:
|
||||
doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false"));
|
||||
break;
|
||||
|
||||
case tString:
|
||||
/* !!! show the context? */
|
||||
doc.writeEmptyElement("string", singletonAttrs("value", v.string.s));
|
||||
break;
|
||||
|
||||
case tPath:
|
||||
doc.writeEmptyElement("path", singletonAttrs("value", v.path));
|
||||
break;
|
||||
|
||||
case tNull:
|
||||
doc.writeEmptyElement("null");
|
||||
break;
|
||||
|
||||
case tAttrs:
|
||||
if (state.isDerivation(v)) {
|
||||
XMLAttrs xmlAttrs;
|
||||
|
||||
Bindings::iterator a = v.attrs->find(state.symbols.create("derivation"));
|
||||
|
||||
Path drvPath;
|
||||
a = v.attrs->find(state.sDrvPath);
|
||||
if (a != v.attrs->end()) {
|
||||
if (strict) state.forceValue(a->second.value);
|
||||
if (a->second.value.type == tString)
|
||||
xmlAttrs["drvPath"] = drvPath = a->second.value.string.s;
|
||||
}
|
||||
|
||||
a = v.attrs->find(state.sOutPath);
|
||||
if (a != v.attrs->end()) {
|
||||
if (strict) state.forceValue(a->second.value);
|
||||
if (a->second.value.type == tString)
|
||||
xmlAttrs["outPath"] = a->second.value.string.s;
|
||||
}
|
||||
|
||||
XMLOpenElement _(doc, "derivation", xmlAttrs);
|
||||
|
||||
if (drvPath != "" && drvsSeen.find(drvPath) == drvsSeen.end()) {
|
||||
drvsSeen.insert(drvPath);
|
||||
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
||||
} else
|
||||
doc.writeEmptyElement("repeated");
|
||||
}
|
||||
|
||||
else {
|
||||
XMLOpenElement _(doc, "attrs");
|
||||
showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case tList: {
|
||||
XMLOpenElement _(doc, "list");
|
||||
for (unsigned int n = 0; n < v.list.length; ++n)
|
||||
printValueAsXML(state, strict, location, *v.list.elems[n], doc, context, drvsSeen);
|
||||
break;
|
||||
}
|
||||
|
||||
case tLambda: {
|
||||
XMLAttrs xmlAttrs;
|
||||
if (location) posToXML(xmlAttrs, v.lambda.fun->pos);
|
||||
XMLOpenElement _(doc, "function", xmlAttrs);
|
||||
|
||||
if (v.lambda.fun->matchAttrs) {
|
||||
XMLAttrs attrs;
|
||||
if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg;
|
||||
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
||||
XMLOpenElement _(doc, "attrspat", attrs);
|
||||
foreach (Formals::Formals_::iterator, i, v.lambda.fun->formals->formals)
|
||||
doc.writeEmptyElement("attr", singletonAttrs("name", i->name));
|
||||
} else
|
||||
doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
doc.writeEmptyElement("unevaluated");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, std::ostream & out, PathSet & context)
|
||||
{
|
||||
XMLWriter doc(true, out);
|
||||
XMLOpenElement root(doc, "expr");
|
||||
PathSet drvsSeen;
|
||||
printValueAsXML(state, strict, location, v, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
17
src/libexpr/value-to-xml.hh
Normal file
17
src/libexpr/value-to-xml.hh
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __VALUE_TO_XML_H
|
||||
#define __VALUE_TO_XML_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "nixexpr.hh"
|
||||
#include "eval.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||
Value & v, std::ostream & out, PathSet & context);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__VALUE_TO_XML_H */
|
||||
@@ -1,6 +1,10 @@
|
||||
pkglib_LTLIBRARIES = libmain.la
|
||||
|
||||
libmain_la_SOURCES = shared.cc shared.hh
|
||||
libmain_la_SOURCES = shared.cc
|
||||
|
||||
libmain_la_LIBADD = ../libstore/libstore.la
|
||||
|
||||
pkginclude_HEADERS = shared.hh
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
-DNIX_STORE_DIR=\"$(storedir)\" \
|
||||
@@ -11,5 +15,5 @@ AM_CXXFLAGS = \
|
||||
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
|
||||
-DNIX_BIN_DIR=\"$(bindir)\" \
|
||||
-DNIX_VERSION=\"$(VERSION)\" \
|
||||
-I$(srcdir)/.. ${aterm_include} -I$(srcdir)/../libutil \
|
||||
-I$(srcdir)/.. -I$(srcdir)/../libutil \
|
||||
-I$(srcdir)/../libstore
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "util.hh"
|
||||
#include "misc.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
@@ -12,8 +13,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <aterm2.h>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -49,6 +48,34 @@ void printGCWarning()
|
||||
}
|
||||
|
||||
|
||||
void printMissing(const PathSet & paths)
|
||||
{
|
||||
unsigned long long downloadSize;
|
||||
PathSet willBuild, willSubstitute, unknown;
|
||||
queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize);
|
||||
|
||||
if (!willBuild.empty()) {
|
||||
printMsg(lvlInfo, format("the following derivations will be built:"));
|
||||
foreach (PathSet::iterator, i, willBuild)
|
||||
printMsg(lvlInfo, format(" %1%") % *i);
|
||||
}
|
||||
|
||||
if (!willSubstitute.empty()) {
|
||||
printMsg(lvlInfo, format("the following paths will be downloaded/copied (%.2f MiB):") %
|
||||
(downloadSize / (1024.0 * 1024.0)));
|
||||
foreach (PathSet::iterator, i, willSubstitute)
|
||||
printMsg(lvlInfo, format(" %1%") % *i);
|
||||
}
|
||||
|
||||
if (!unknown.empty()) {
|
||||
printMsg(lvlInfo, format("don't know how to build the following paths%1%:")
|
||||
% (readOnlyMode ? " (may be caused by read-only store access)" : ""));
|
||||
foreach (PathSet::iterator, i, unknown)
|
||||
printMsg(lvlInfo, format(" %1%") % *i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void setLogType(string lt)
|
||||
{
|
||||
if (lt == "pretty") logType = ltPretty;
|
||||
@@ -58,30 +85,6 @@ static void setLogType(string lt)
|
||||
}
|
||||
|
||||
|
||||
static unsigned int getIntArg(const string & opt,
|
||||
Strings::iterator & i, const Strings::iterator & end)
|
||||
{
|
||||
++i;
|
||||
if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
|
||||
int n;
|
||||
if (!string2Int(*i, n) || n < 0)
|
||||
throw UsageError(format("`%1%' requires a non-negative integer") % opt);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
struct RemoveTempRoots
|
||||
{
|
||||
~RemoveTempRoots()
|
||||
{
|
||||
removeTempRoots();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void initDerivationsHelpers();
|
||||
|
||||
|
||||
static void closeStore()
|
||||
{
|
||||
try {
|
||||
@@ -99,6 +102,15 @@ static void closeStore()
|
||||
}
|
||||
|
||||
|
||||
RemoveTempRoots::~RemoveTempRoots()
|
||||
{
|
||||
removeTempRoots();
|
||||
}
|
||||
|
||||
|
||||
static bool showTrace = false;
|
||||
|
||||
|
||||
/* Initialize and reorder arguments, then call the actual argument
|
||||
processor. */
|
||||
static void initAndRun(int argc, char * * argv)
|
||||
@@ -114,9 +126,10 @@ static void initAndRun(int argc, char * * argv)
|
||||
nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
|
||||
|
||||
string subs = getEnv("NIX_SUBSTITUTERS", "default");
|
||||
if (subs == "default")
|
||||
substituters.push_back(nixLibexecDir + "/nix/download-using-manifests.pl");
|
||||
else
|
||||
if (subs == "default") {
|
||||
substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl");
|
||||
substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl");
|
||||
} else
|
||||
substituters = tokenizeString(subs, ":");
|
||||
|
||||
/* Get some settings from the configuration file. */
|
||||
@@ -125,23 +138,29 @@ static void initAndRun(int argc, char * * argv)
|
||||
maxSilentTime = queryIntSetting("build-max-silent-time", 0);
|
||||
|
||||
/* Catch SIGINT. */
|
||||
struct sigaction act, oact;
|
||||
struct sigaction act;
|
||||
act.sa_handler = sigintHandler;
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
if (sigaction(SIGINT, &act, &oact))
|
||||
if (sigaction(SIGINT, &act, 0))
|
||||
throw SysError("installing handler for SIGINT");
|
||||
if (sigaction(SIGTERM, &act, &oact))
|
||||
if (sigaction(SIGTERM, &act, 0))
|
||||
throw SysError("installing handler for SIGTERM");
|
||||
if (sigaction(SIGHUP, &act, &oact))
|
||||
if (sigaction(SIGHUP, &act, 0))
|
||||
throw SysError("installing handler for SIGHUP");
|
||||
|
||||
/* Ignore SIGPIPE. */
|
||||
act.sa_handler = SIG_IGN;
|
||||
act.sa_flags = 0;
|
||||
if (sigaction(SIGPIPE, &act, &oact))
|
||||
if (sigaction(SIGPIPE, &act, 0))
|
||||
throw SysError("ignoring SIGPIPE");
|
||||
|
||||
/* Reset SIGCHLD to its default. */
|
||||
act.sa_handler = SIG_DFL;
|
||||
act.sa_flags = 0;
|
||||
if (sigaction(SIGCHLD, &act, 0))
|
||||
throw SysError("resetting SIGCHLD");
|
||||
|
||||
/* 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
|
||||
@@ -152,9 +171,6 @@ static void initAndRun(int argc, char * * argv)
|
||||
string lt = getEnv("NIX_LOG_TYPE");
|
||||
if (lt != "") setLogType(lt);
|
||||
|
||||
/* ATerm stuff. !!! find a better place to put this */
|
||||
initDerivationsHelpers();
|
||||
|
||||
/* Put the arguments in a vector. */
|
||||
Strings args, remaining;
|
||||
while (argc--) args.push_back(*argv++);
|
||||
@@ -165,7 +181,7 @@ static void initAndRun(int argc, char * * argv)
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
string arg = *i;
|
||||
if (string(arg, 0, 4) == "-at-") ;
|
||||
else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') {
|
||||
else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-' && !isdigit(arg[1])) {
|
||||
for (unsigned int j = 1; j < arg.length(); j++)
|
||||
if (isalpha(arg[j]))
|
||||
remaining.push_back((string) "-" + arg[j]);
|
||||
@@ -192,6 +208,8 @@ static void initAndRun(int argc, char * * argv)
|
||||
; /* !!! obsolete - remove eventually */
|
||||
else if (arg == "--no-build-output" || arg == "-Q")
|
||||
buildVerbosity = lvlVomit;
|
||||
else if (arg == "--print-build-trace")
|
||||
printBuildTrace = true;
|
||||
else if (arg == "--help") {
|
||||
printHelp();
|
||||
return;
|
||||
@@ -207,17 +225,28 @@ static void initAndRun(int argc, char * * argv)
|
||||
else if (arg == "--fallback")
|
||||
tryFallback = true;
|
||||
else if (arg == "--max-jobs" || arg == "-j")
|
||||
maxBuildJobs = getIntArg(arg, i, args.end());
|
||||
maxBuildJobs = getIntArg<unsigned int>(arg, i, args.end());
|
||||
else if (arg == "--readonly-mode")
|
||||
readOnlyMode = true;
|
||||
else if (arg == "--max-silent-time")
|
||||
maxSilentTime = getIntArg(arg, i, args.end());
|
||||
maxSilentTime = getIntArg<unsigned int>(arg, i, args.end());
|
||||
else if (arg == "--no-build-hook")
|
||||
useBuildHook = false;
|
||||
else if (arg == "--show-trace")
|
||||
showTrace = true;
|
||||
else if (arg == "--option") {
|
||||
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
||||
string name = *i;
|
||||
++i; if (i == args.end()) throw UsageError("`--option' requires two arguments");
|
||||
string value = *i;
|
||||
overrideSetting(name, tokenizeString(value));
|
||||
}
|
||||
else remaining.push_back(arg);
|
||||
}
|
||||
|
||||
/* Automatically clean up the temporary roots file when we
|
||||
exit. */
|
||||
RemoveTempRoots removeTempRoots; /* unused variable - don't remove */
|
||||
RemoveTempRoots removeTempRoots __attribute__((unused));
|
||||
|
||||
/* Make sure that the database gets closed properly, even if
|
||||
terminate() is called (which happens sometimes due to bugs in
|
||||
@@ -296,10 +325,6 @@ int main(int argc, char * * argv)
|
||||
if (argc == 0) abort();
|
||||
setuidInit();
|
||||
|
||||
/* ATerm setup. */
|
||||
ATerm bottomOfStack;
|
||||
ATinit(argc, argv, &bottomOfStack);
|
||||
|
||||
/* Turn on buffering for cerr. */
|
||||
#if HAVE_PUBSETBUF
|
||||
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
|
||||
@@ -327,7 +352,9 @@ int main(int argc, char * * argv)
|
||||
% e.what() % programId);
|
||||
return 1;
|
||||
} catch (BaseError & e) {
|
||||
printMsg(lvlError, format("error: %1%") % e.msg());
|
||||
printMsg(lvlError, format("error: %1%%2%") % (showTrace ? e.prefix() : "") % e.msg());
|
||||
if (e.prefix() != "" && !showTrace)
|
||||
printMsg(lvlError, "(use `--show-trace' to show detailed location information)");
|
||||
return 1;
|
||||
} catch (std::exception & e) {
|
||||
printMsg(lvlError, format("error: %1%") % e.what());
|
||||
|
||||
@@ -22,16 +22,34 @@ extern std::string programId;
|
||||
|
||||
namespace nix {
|
||||
|
||||
MakeError(UsageError, nix::Error);
|
||||
|
||||
/* Ugh. No better place to put this. */
|
||||
Path makeRootName(const Path & gcRoot, int & counter);
|
||||
void printGCWarning();
|
||||
|
||||
void printMissing(const PathSet & paths);
|
||||
|
||||
template<class N> N getIntArg(const string & opt,
|
||||
Strings::iterator & i, const Strings::iterator & end)
|
||||
{
|
||||
++i;
|
||||
if (i == end) throw UsageError(format("`%1%' requires an argument") % opt);
|
||||
N n;
|
||||
if (!string2Int(*i, n))
|
||||
throw UsageError(format("`%1%' requires an integer argument") % opt);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Whether we're running setuid. */
|
||||
extern bool setuidMode;
|
||||
|
||||
extern volatile ::sig_atomic_t blockInt;
|
||||
|
||||
MakeError(UsageError, nix::Error);
|
||||
struct RemoveTempRoots
|
||||
{
|
||||
~RemoveTempRoots();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
pkglib_LTLIBRARIES = libstore.la
|
||||
|
||||
libstore_la_SOURCES = \
|
||||
store-api.cc local-store.cc remote-store.cc derivations.cc build.cc misc.cc \
|
||||
globals.cc db.cc references.cc pathlocks.cc gc.cc
|
||||
store-api.cc local-store.cc remote-store.cc derivations.cc build.cc misc.cc \
|
||||
globals.cc references.cc pathlocks.cc gc.cc \
|
||||
optimise-store.cc
|
||||
|
||||
pkginclude_HEADERS = \
|
||||
store-api.hh local-store.hh remote-store.hh derivations.hh misc.hh \
|
||||
globals.hh db.hh references.hh pathlocks.hh \
|
||||
worker-protocol.hh
|
||||
store-api.hh local-store.hh remote-store.hh derivations.hh misc.hh \
|
||||
globals.hh references.hh pathlocks.hh \
|
||||
worker-protocol.hh
|
||||
|
||||
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la
|
||||
|
||||
BUILT_SOURCES = derivations-ast.cc derivations-ast.hh
|
||||
|
||||
EXTRA_DIST = derivations-ast.def derivations-ast.cc
|
||||
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@
|
||||
|
||||
AM_CXXFLAGS = -Wall \
|
||||
-I$(srcdir)/.. ${bdb_include} ${aterm_include} -I$(srcdir)/../libutil
|
||||
|
||||
derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
|
||||
$(perl) $(srcdir)/../aterm-helper.pl derivations-ast.hh derivations-ast.cc < $(srcdir)/derivations-ast.def
|
||||
-I$(srcdir)/.. -I$(srcdir)/../libutil
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user