Compare commits
383 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af66436f9 | ||
|
|
b6659d4425 | ||
|
|
ab649814fc | ||
|
|
bffb03eae1 | ||
|
|
2bf4fcb7cd | ||
|
|
a34a198006 | ||
|
|
55b07d65b1 | ||
|
|
4e11da960c | ||
|
|
1164d6a389 | ||
|
|
c28742f633 | ||
|
|
7e0dcc5dcb | ||
|
|
c0dceea9f0 | ||
|
|
588356c30a | ||
|
|
1747d649c5 | ||
|
|
53e31381fa | ||
|
|
2d84c9e50c | ||
|
|
a699c6b330 | ||
|
|
84d00db70b | ||
|
|
138973a6d5 | ||
|
|
d8e9dc2775 | ||
|
|
ef37776094 | ||
|
|
60a32fcbf3 | ||
|
|
0ee803935e | ||
|
|
65ba1f3008 | ||
|
|
16410fc714 | ||
|
|
7d82fd16e9 | ||
|
|
8b31968c61 | ||
|
|
67022b7cca | ||
|
|
a94ea0fd61 | ||
|
|
ca3d96222a | ||
|
|
13b632ca57 | ||
|
|
dacf2e0e87 | ||
|
|
00602dd20c | ||
|
|
546ca6e8bc | ||
|
|
854e155b2c | ||
|
|
8e9c7d9338 | ||
|
|
3800f55b54 | ||
|
|
d69dd855d5 | ||
|
|
43d93e5e64 | ||
|
|
d0458acb7c | ||
|
|
86f0fd8341 | ||
|
|
4c32f38047 | ||
|
|
f435abcdb6 | ||
|
|
51cff21c92 | ||
|
|
315cd18337 | ||
|
|
e80c7bda4c | ||
|
|
ed55982085 | ||
|
|
35e239af33 | ||
|
|
89ab441fd2 | ||
|
|
68cb244c90 | ||
|
|
094c69ad19 | ||
|
|
ec7b0afb08 | ||
|
|
30cf65af26 | ||
|
|
627afcc1aa | ||
|
|
2e7539bd27 | ||
|
|
bdcce95a39 | ||
|
|
53a6b9aaa5 | ||
|
|
05297240ea | ||
|
|
53c907ca09 | ||
|
|
5a9cfdeb6e | ||
|
|
4089bd5f19 | ||
|
|
7424d72098 | ||
|
|
13f321e397 | ||
|
|
696f1fd5e2 | ||
|
|
af8c5697be | ||
|
|
bd25de8d88 | ||
|
|
5e0716bbbb | ||
|
|
7d91f62b71 | ||
|
|
4fb9070fbd | ||
|
|
83ec65edf5 | ||
|
|
856251df03 | ||
|
|
0fc5accd86 | ||
|
|
dc4395b737 | ||
|
|
a07ba681cc | ||
|
|
45bb1ae6a5 | ||
|
|
e3034da88b | ||
|
|
00f39f88f7 | ||
|
|
7f2140d17f | ||
|
|
b46db4dea7 | ||
|
|
c0bd494865 | ||
|
|
b6974f2ae6 | ||
|
|
6392da5f90 | ||
|
|
e33a1e4e74 | ||
|
|
f3dabd6206 | ||
|
|
7bfed0c104 | ||
|
|
96a62bb7e6 | ||
|
|
36b79c7135 | ||
|
|
ba437f451e | ||
|
|
b378df6484 | ||
|
|
fdc2686460 | ||
|
|
b7654ab716 | ||
|
|
9257f16c85 | ||
|
|
bc2fbabc12 | ||
|
|
afb445957d | ||
|
|
9f00b42f38 | ||
|
|
cce4156232 | ||
|
|
ca5fc7c582 | ||
|
|
cc7d4c8bd7 | ||
|
|
40161d0be1 | ||
|
|
0a4a3a1b68 | ||
|
|
4f483aad0f | ||
|
|
eb1f179eac | ||
|
|
9d7438db9f | ||
|
|
c65c296ce0 | ||
|
|
ad2b815b5e | ||
|
|
1c3ec86c39 | ||
|
|
c370c9f535 | ||
|
|
7eb2f61797 | ||
|
|
b32691da2b | ||
|
|
04dd3fdf34 | ||
|
|
22473597ec | ||
|
|
b9fe3f00c1 | ||
|
|
729933062b | ||
|
|
1c0b052243 | ||
|
|
3d22bd50b3 | ||
|
|
c0dcfed3c3 | ||
|
|
6351b7e728 | ||
|
|
51fad07fbd | ||
|
|
0e41b191bf | ||
|
|
a4fda31ad5 | ||
|
|
235c91dd7f | ||
|
|
5164a77aab | ||
|
|
b1cc9e9a45 | ||
|
|
bdecf3bdbc | ||
|
|
5e59387d40 | ||
|
|
df43c1e5b9 | ||
|
|
184443d18d | ||
|
|
bc0af4449a | ||
|
|
76f5c8ba07 | ||
|
|
b909d57f5d | ||
|
|
fe04276aef | ||
|
|
95ce7e04b7 | ||
|
|
267ccc589d | ||
|
|
fd2b8271e4 | ||
|
|
255bf5f04b | ||
|
|
01062b0563 | ||
|
|
79d5604780 | ||
|
|
7166ad8eba | ||
|
|
bcf9d3ab2f | ||
|
|
9c46444641 | ||
|
|
986a50ac78 | ||
|
|
25117fd165 | ||
|
|
653e557e81 | ||
|
|
cbd0d39583 | ||
|
|
fbd1b78a9d | ||
|
|
0a303ea2c0 | ||
|
|
c9e78a973a | ||
|
|
97eb8c32a0 | ||
|
|
86b053dd80 | ||
|
|
73995157e3 | ||
|
|
09b8b7efbc | ||
|
|
802d7f40bd | ||
|
|
5cac336820 | ||
|
|
3fc0b0da58 | ||
|
|
8a7874d77d | ||
|
|
4c63f18dcc | ||
|
|
b712f0f019 | ||
|
|
1a793c60ce | ||
|
|
ae7990cc88 | ||
|
|
4caca58ff7 | ||
|
|
17b506c0c7 | ||
|
|
efd31139df | ||
|
|
d303b389a9 | ||
|
|
7edd2e2cd2 | ||
|
|
f3584ff535 | ||
|
|
803cb6e3b9 | ||
|
|
a8ea4cbcc8 | ||
|
|
8ab229ddf2 | ||
|
|
b2b6cf3fc8 | ||
|
|
eb2dd4815c | ||
|
|
917e06bf63 | ||
|
|
df0283ae86 | ||
|
|
30394a4f3f | ||
|
|
db1973d012 | ||
|
|
b4a040e52b | ||
|
|
2ea3bebc23 | ||
|
|
044b6482c1 | ||
|
|
adce01a8d0 | ||
|
|
363e307fd3 | ||
|
|
ddde8e2f32 | ||
|
|
27bb0ac7d2 | ||
|
|
fa2be32034 | ||
|
|
4c5e6d1a2f | ||
|
|
024a8ed382 | ||
|
|
7f6161ab3a | ||
|
|
0db450024d | ||
|
|
9da367b7d5 | ||
|
|
881feb9698 | ||
|
|
65f195f4c7 | ||
|
|
bdadb98de8 | ||
|
|
0f5da8a83c | ||
|
|
dc7d594776 | ||
|
|
43c4d18c6a | ||
|
|
46e0919ced | ||
|
|
6c9fdb17fb | ||
|
|
b824a1daee | ||
|
|
3390c1be76 | ||
|
|
8181a1c3bb | ||
|
|
46605fb4f5 | ||
|
|
52d03276dd | ||
|
|
451dbf687f | ||
|
|
f52de527c7 | ||
|
|
b618fa6eb6 | ||
|
|
c558b1583c | ||
|
|
18e6096105 | ||
|
|
7349bd0176 | ||
|
|
7dedbd896a | ||
|
|
84a84afb0e | ||
|
|
fac63d6416 | ||
|
|
bae75ca5a1 | ||
|
|
36d9258c0d | ||
|
|
7bc30e1ca8 | ||
|
|
71ceb1c161 | ||
|
|
e4b0666f8e | ||
|
|
63f3ce6d9a | ||
|
|
8f67b35886 | ||
|
|
8659edc098 | ||
|
|
e418976107 | ||
|
|
4e329f173f | ||
|
|
afe23b5f38 | ||
|
|
f25f900045 | ||
|
|
215505bb46 | ||
|
|
f23dcdd603 | ||
|
|
05879db628 | ||
|
|
5011588459 | ||
|
|
792878af91 | ||
|
|
11158028be | ||
|
|
1b7840b949 | ||
|
|
69c8b5b8a7 | ||
|
|
1f3722bd4a | ||
|
|
50bdec410a | ||
|
|
4c63f9fe04 | ||
|
|
57969b95b3 | ||
|
|
cafaceb707 | ||
|
|
1073b1780a | ||
|
|
a3e6415ba8 | ||
|
|
b438d37558 | ||
|
|
3130f1f0fa | ||
|
|
7ace29dae7 | ||
|
|
1a7e88bbd9 | ||
|
|
5e6699188f | ||
|
|
b17677462c | ||
|
|
5f681988f2 | ||
|
|
fa33303146 | ||
|
|
06c4929958 | ||
|
|
9dbfe242e3 | ||
|
|
d3fe6ab024 | ||
|
|
096194ab29 | ||
|
|
6833e8bbe8 | ||
|
|
e24d0201c2 | ||
|
|
2819eb36a4 | ||
|
|
4ca01065c3 | ||
|
|
d03f0d4117 | ||
|
|
c3286ec020 | ||
|
|
a82d80ddeb | ||
|
|
f76fdb6d42 | ||
|
|
ec23ecc64d | ||
|
|
a0a43c3206 | ||
|
|
6a07ff1ec0 | ||
|
|
7d8cf316ee | ||
|
|
a45c498e4e | ||
|
|
813a7c65c9 | ||
|
|
6a8e60913a | ||
|
|
79875c5e42 | ||
|
|
62ab131412 | ||
|
|
f07ac41656 | ||
|
|
173d328351 | ||
|
|
ef281b93c2 | ||
|
|
a14d491f09 | ||
|
|
6e5ec1029a | ||
|
|
751f6d2157 | ||
|
|
9f0efa6611 | ||
|
|
2b558843a2 | ||
|
|
44cad9630f | ||
|
|
6f0d050324 | ||
|
|
4c1c37d0b6 | ||
|
|
8d1854c3f1 | ||
|
|
99655245ae | ||
|
|
62b0497c0f | ||
|
|
c808e6252f | ||
|
|
fd4a9db91f | ||
|
|
fc1c20d11b | ||
|
|
a9c4f66cfb | ||
|
|
29cf434a35 | ||
|
|
8623256f48 | ||
|
|
d27a73b1a9 | ||
|
|
74033a844f | ||
|
|
0d40f6d7bb | ||
|
|
7751160e9f | ||
|
|
40c3529909 | ||
|
|
0130ef88ea | ||
|
|
4740baf3a6 | ||
|
|
f5f0cf423f | ||
|
|
052b6fb149 | ||
|
|
1e16d20655 | ||
|
|
9322b399f3 | ||
|
|
f4279bcde0 | ||
|
|
35247c4c9f | ||
|
|
84d6459bd5 | ||
|
|
a9f9241054 | ||
|
|
3ed9e4ad9b | ||
|
|
4251f94b32 | ||
|
|
8c76df93e6 | ||
|
|
363f40022f | ||
|
|
7951c3c546 | ||
|
|
714fa24cfb | ||
|
|
e25fad691a | ||
|
|
30bf547f4f | ||
|
|
536595b072 | ||
|
|
9c9cdb06d0 | ||
|
|
626f8ee42f | ||
|
|
8ba5d32769 | ||
|
|
fcd9900d74 | ||
|
|
a824d58b56 | ||
|
|
ceb982a1be | ||
|
|
b0d8e05be1 | ||
|
|
0565b5f2b3 | ||
|
|
aac547a8b3 | ||
|
|
0263279071 | ||
|
|
a711689368 | ||
|
|
765bdfe542 | ||
|
|
40b3f64b55 | ||
|
|
9adc074dc3 | ||
|
|
9cf1948993 | ||
|
|
6ecb840fd1 | ||
|
|
e2ef5e07fd | ||
|
|
5f0b9de6d8 | ||
|
|
fe15f991e3 | ||
|
|
80b742dd52 | ||
|
|
92417600a1 | ||
|
|
71e867c5f5 | ||
|
|
c6a97e3b74 | ||
|
|
a76efaeb3f | ||
|
|
d941186289 | ||
|
|
0541ddc7e3 | ||
|
|
471749ca7e | ||
|
|
17d18b1a9c | ||
|
|
0ddaee756e | ||
|
|
bce9ff7ece | ||
|
|
745e354b19 | ||
|
|
f459a5bb3a | ||
|
|
e2a70b7ec0 | ||
|
|
e40d4a5604 | ||
|
|
e790404318 | ||
|
|
983c5e3fce | ||
|
|
7e85a2af5f | ||
|
|
b3f916995a | ||
|
|
005eecfc4d | ||
|
|
8478cd260f | ||
|
|
8d17265ac4 | ||
|
|
ae6fb27f18 | ||
|
|
99b0ea7c67 | ||
|
|
dd300fb48d | ||
|
|
1d694eef4c | ||
|
|
7a4497d98c | ||
|
|
17f4883bfe | ||
|
|
9bd93f7606 | ||
|
|
b3d3700e11 | ||
|
|
6a67556f71 | ||
|
|
daa8f85fcd | ||
|
|
24737f279e | ||
|
|
4bd5cdb90b | ||
|
|
58ff6939f4 | ||
|
|
3059df0f1e | ||
|
|
822dba2210 | ||
|
|
dfc042a0c1 | ||
|
|
9e30694f98 | ||
|
|
be1961c9f8 | ||
|
|
cba913c521 | ||
|
|
cf705eaf78 | ||
|
|
7de5fe2fc2 | ||
|
|
46b631b6c4 | ||
|
|
d7efd76394 | ||
|
|
4c9aa821b9 | ||
|
|
142863a89d | ||
|
|
37c8a664f3 | ||
|
|
e4af398681 | ||
|
|
2a535689fe | ||
|
|
7d4567f2cc | ||
|
|
b4e012ab4d | ||
|
|
0c4c5c2020 | ||
|
|
bd0c40e1e9 | ||
|
|
7bada48b36 |
20
Makefile.am
20
Makefile.am
@@ -20,10 +20,11 @@ install-data-local: init-state
|
||||
fi
|
||||
|
||||
if INIT_STATE
|
||||
if SETUID_HACK
|
||||
INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
|
||||
GROUP_WRITABLE = -m 775
|
||||
endif
|
||||
|
||||
# For setuid operation, you can enable the following:
|
||||
# INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
|
||||
# GROUP_WRITABLE = -m 775
|
||||
|
||||
init-state:
|
||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix
|
||||
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/db
|
||||
@@ -34,19 +35,26 @@ init-state:
|
||||
$(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
|
||||
rm -f $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
|
||||
ln -s $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
|
||||
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) $(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
|
||||
|
||||
init-ext3cow-header-hack:
|
||||
@echo "Symlinking ext3cow header file into src"
|
||||
ln -sf $(ext3cowheader) src/libext3cow/
|
||||
|
||||
svn-revision:
|
||||
svnversion . > svn-revision
|
||||
|
||||
all: init-ext3cow-header-hack
|
||||
|
||||
all-local: NEWS
|
||||
|
||||
NEWS: doc/manual/NEWS.txt
|
||||
|
||||
3
TODO
Normal file
3
TODO
Normal file
@@ -0,0 +1,3 @@
|
||||
- runtimeStateArgs now must be set to someting (or it will see it as a hardcoded path)
|
||||
- import and export of state paths
|
||||
-
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh -e
|
||||
mkdir -p config
|
||||
libtoolize --copy
|
||||
libtoolize --force --copy
|
||||
aclocal
|
||||
autoheader
|
||||
automake --add-missing --copy
|
||||
|
||||
88
configure.ac
88
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT(nix, 0.10)
|
||||
AC_INIT(nix, 0.12)
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
|
||||
@@ -9,14 +9,14 @@ STABLE=0
|
||||
|
||||
# Put the revision number in the version.
|
||||
if test "$STABLE" != "1"; then
|
||||
if REVISION=`test -d $srcdir/.svn && svnversion $srcdir 2> /dev/null`; 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, ["$(echo $VERSION)"], [version])
|
||||
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [version])
|
||||
|
||||
AC_PREFIX_DEFAULT(/nix)
|
||||
|
||||
@@ -32,6 +32,9 @@ case $machine_name in
|
||||
i*86)
|
||||
machine_name=i686
|
||||
;;
|
||||
x86_64)
|
||||
machine_name=x86_64
|
||||
;;
|
||||
ppc)
|
||||
machine_name=powerpc
|
||||
;;
|
||||
@@ -96,9 +99,19 @@ static char buf[1024];]],
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
|
||||
# Check for chroot support (requires chroot() and bind mounts).
|
||||
AC_CHECK_FUNCS([chroot])
|
||||
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++)
|
||||
|
||||
|
||||
@@ -111,7 +124,7 @@ fi
|
||||
])
|
||||
|
||||
NEED_PROG(curl, curl)
|
||||
NEED_PROG(shell, sh)
|
||||
NEED_PROG(shell, bash)
|
||||
NEED_PROG(patch, patch)
|
||||
AC_PATH_PROG(xmllint, xmllint, false)
|
||||
AC_PATH_PROG(xsltproc, xsltproc, false)
|
||||
@@ -122,8 +135,22 @@ AC_PATH_PROG(bison, bison, false)
|
||||
NEED_PROG(perl, perl)
|
||||
NEED_PROG(tar, tar)
|
||||
AC_PATH_PROG(dot, dot)
|
||||
|
||||
AC_PATH_PROG(dblatex, dblatex)
|
||||
|
||||
AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PATH
|
||||
AC_SUBST(openssl_prog)
|
||||
AC_DEFINE_UNQUOTED(OPENSSL_PATH, ["$openssl_prog"], [Path of the OpenSSL binary])
|
||||
|
||||
# Test that Perl has the open/fork feature (Perl 5.8.0 and beyond).
|
||||
AC_MSG_CHECKING([whether Perl is recent enough])
|
||||
if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or die;'; then
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR([Your Perl version is too old. Nix requires Perl 5.8.0 or newer.])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)
|
||||
|
||||
NEED_PROG(cat, cat)
|
||||
NEED_PROG(tr, tr)
|
||||
AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
|
||||
[path of cat, mkdir, etc.]),
|
||||
coreutils=$withval, coreutils=$(dirname $cat))
|
||||
@@ -149,6 +176,11 @@ AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
|
||||
storedir=$withval, storedir='${prefix}/store')
|
||||
AC_SUBST(storedir)
|
||||
|
||||
AC_ARG_WITH(store-state-dir, AC_HELP_STRING([--with-store-state-dir=PATH],
|
||||
[path of the Nix state store]),
|
||||
storestatedir=$withval, storestatedir='${prefix}/state')
|
||||
AC_SUBST(storestatedir)
|
||||
|
||||
AC_ARG_WITH(bdb, AC_HELP_STRING([--with-bdb=PATH],
|
||||
[prefix of Berkeley DB]),
|
||||
bdb=$withval, bdb=)
|
||||
@@ -163,6 +195,18 @@ fi
|
||||
AC_SUBST(bdb_lib)
|
||||
AC_SUBST(bdb_include)
|
||||
|
||||
AC_ARG_WITH(ext3cow-header, AC_HELP_STRING([--with-ext3cow-header=PATH],
|
||||
[path of the ext3cow header ext3cow_fs.h]),
|
||||
ext3cowheader=$withval, ext3cowheader=)
|
||||
AC_SUBST(ext3cowheader)
|
||||
AC_CHECK_HEADER(${ext3cowheader})
|
||||
|
||||
NEED_PROG(rsync, rsync)
|
||||
AC_ARG_WITH(rsync, AC_HELP_STRING([--with-rsync=PATH],
|
||||
[path to the rsync binary.]),
|
||||
rsync=$withval)
|
||||
AC_SUBST(rsync)
|
||||
|
||||
AC_ARG_WITH(aterm, AC_HELP_STRING([--with-aterm=PATH],
|
||||
[prefix of CWI ATerm library]),
|
||||
aterm=$withval, aterm=)
|
||||
@@ -226,33 +270,13 @@ AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
|
||||
|
||||
|
||||
# Setuid installations.
|
||||
AC_ARG_ENABLE(setuid, AC_HELP_STRING([--enable-setuid],
|
||||
[install Nix setuid]),
|
||||
setuid_hack=$enableval, setuid_hack=no)
|
||||
AM_CONDITIONAL(SETUID_HACK, test "$setuid_hack" = "yes")
|
||||
if test "$setuid_hack" = "yes"; then
|
||||
AC_DEFINE(SETUID_HACK, 1, [whether to install Nix setuid])
|
||||
fi
|
||||
AC_CHECK_FUNCS([setresuid setreuid lchown])
|
||||
|
||||
AC_CHECK_FUNC(setresuid, [HAVE_SETRESUID=1], [HAVE_SETRESUID=])
|
||||
AM_CONDITIONAL(HAVE_SETRESUID, test "$HAVE_SETRESUID" = "1")
|
||||
if test "$HAVE_SETRESUID" = "1"; then
|
||||
AC_DEFINE(HAVE_SETRESUID, 1, [whether we have setresuid()])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(nix-user, AC_HELP_STRING([--with-nix-user=USER],
|
||||
[user for Nix setuid binaries]),
|
||||
NIX_USER=$withval, NIX_USER=nix)
|
||||
AC_SUBST(NIX_USER)
|
||||
AC_DEFINE_UNQUOTED(NIX_USER, ["$NIX_USER"], [Nix user])
|
||||
|
||||
AC_ARG_WITH(nix-group, AC_HELP_STRING([--with-nix-group=USER],
|
||||
[group for Nix setuid binaries]),
|
||||
NIX_GROUP=$withval, NIX_GROUP=nix)
|
||||
AC_SUBST(NIX_GROUP)
|
||||
AC_DEFINE_UNQUOTED(NIX_GROUP, ["$NIX_GROUP"], [Nix group])
|
||||
# Nice to have, but not essential.
|
||||
AC_CHECK_FUNCS([strsignal])
|
||||
|
||||
|
||||
|
||||
# This is needed if ATerm, Berkeley DB or bzip2 are static libraries,
|
||||
# and the Nix libraries are dynamic.
|
||||
if test "$(uname)" = "Darwin"; then
|
||||
@@ -270,11 +294,15 @@ AC_CONFIG_FILES([Makefile
|
||||
src/libutil/Makefile
|
||||
src/libstore/Makefile
|
||||
src/libmain/Makefile
|
||||
src/libext3cow/Makefile
|
||||
src/nix-store/Makefile
|
||||
src/nix-state/Makefile
|
||||
src/nix-hash/Makefile
|
||||
src/libexpr/Makefile
|
||||
src/nix-instantiate/Makefile
|
||||
src/nix-env/Makefile
|
||||
src/nix-worker/Makefile
|
||||
src/nix-setuid-helper/Makefile
|
||||
src/nix-log2xml/Makefile
|
||||
src/bsdiff-4.3/Makefile
|
||||
scripts/Makefile
|
||||
|
||||
@@ -3,22 +3,39 @@
|
||||
use strict;
|
||||
use Cwd;
|
||||
use IO::Handle;
|
||||
use Fcntl;
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
|
||||
my $out = $ENV{"out"};
|
||||
mkdir "$out", 0755 || die "error creating $out";
|
||||
|
||||
sub readlink_or_StateWrapper;
|
||||
|
||||
my $symlinks = 0;
|
||||
my %path_state_identifier = ();
|
||||
|
||||
my %priorities;
|
||||
|
||||
my $nixBinDir = $ENV{"nixBinDir"};
|
||||
my $nixStore = $ENV{"nixStore"};
|
||||
|
||||
# For each activated package, create symlinks.
|
||||
|
||||
sub createLinks {
|
||||
my $srcDir = shift;
|
||||
|
||||
#Lookup each $stateIdentifiers in $path_state_identifier
|
||||
#we strip $srcDir to its rootdir e.g. /nix/store/......./
|
||||
my @srcDirParts = split /\// , substr($srcDir, length ($nixStore), length ($srcDir));
|
||||
my $srcDirRoot = $nixStore . "/" . $srcDirParts[1];
|
||||
# print "srcDirRoot $srcDirRoot \n";
|
||||
|
||||
my $dstDir = shift;
|
||||
my $ignoreCollisions = shift;
|
||||
my $priority = shift;
|
||||
my $pkgStateIdentifier = $path_state_identifier{$srcDirRoot}; # We have to look it up each time since recursion can change the $srcDir, but not the identifier
|
||||
|
||||
#print "createLinks $srcDir to $dstDir with iden $pkgStateIdentifier \n";
|
||||
|
||||
my @srcFiles = glob("$srcDir/*");
|
||||
|
||||
@@ -27,22 +44,23 @@ sub createLinks {
|
||||
$baseName =~ s/^.*\///g; # strip directory
|
||||
my $dstFile = "$dstDir/$baseName";
|
||||
|
||||
# Urgh, hacky...
|
||||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
||||
# Urgh, hacky...
|
||||
if ($srcFile =~ /\/propagated-build-inputs$/ ||
|
||||
$srcFile =~ /\/nix-support$/ ||
|
||||
$srcFile =~ /\/perllocal.pod$/ ||
|
||||
$srcFile =~ /\/info\/dir$/ ||
|
||||
$srcFile =~ /\/log$/)
|
||||
{
|
||||
# Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
elsif (-d $srcFile) {
|
||||
|
||||
lstat $dstFile;
|
||||
|
||||
#go recursive on directorys
|
||||
if (-d _) {
|
||||
createLinks($srcFile, $dstFile, $ignoreCollisions);
|
||||
createLinks($srcFile, $dstFile, $priority);
|
||||
}
|
||||
|
||||
elsif (-l _) {
|
||||
@@ -51,31 +69,85 @@ sub createLinks {
|
||||
die "collission between directory `$srcFile' and non-directory `$target'";
|
||||
}
|
||||
unlink $dstFile or die "error unlinking `$dstFile': $!";
|
||||
mkdir $dstFile, 0755 ||
|
||||
die "error creating directory `$dstFile': $!";
|
||||
createLinks($target, $dstFile, $ignoreCollisions);
|
||||
createLinks($srcFile, $dstFile, $ignoreCollisions);
|
||||
mkdir $dstFile, 0755 || die "error creating directory `$dstFile': $!";
|
||||
createLinks($target, $dstFile, $priorities{$dstFile});
|
||||
createLinks($srcFile, $dstFile, $priority);
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
#print "1ST DIR LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
|
||||
|
||||
symlink($srcFile, $dstFile) ||
|
||||
die "error creating link `$dstFile': $!";
|
||||
$priorities{$dstFile} = $priority;
|
||||
$symlinks++;
|
||||
}
|
||||
}
|
||||
|
||||
elsif (-l $dstFile) {
|
||||
if (!$ignoreCollisions) {
|
||||
my $target = readlink $dstFile;
|
||||
die "collission between `$srcFile' and `$target'";
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
symlink($srcFile, $dstFile) ||
|
||||
die "error creating link `$dstFile': $!";
|
||||
$symlinks++;
|
||||
}
|
||||
|
||||
# print "ELSE LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
|
||||
|
||||
# if we have a state component with a identifier different then ""
|
||||
if($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier ne ""){
|
||||
|
||||
my @pathparts = split /\// , $srcFile;
|
||||
my $parentDir = $pathparts[scalar(@pathparts) - 2];
|
||||
|
||||
if( $parentDir eq "bin" || $parentDir eq "sbin"){ #hacky....
|
||||
|
||||
print "STATELINK $srcFile to $dstFile - $pkgStateIdentifier \n";
|
||||
|
||||
my $new_dstFile;
|
||||
my $new_stateIdentifier;
|
||||
if($pkgStateIdentifier eq "__EMTPY__"){
|
||||
$new_dstFile = $dstFile;
|
||||
$new_stateIdentifier = "";
|
||||
}
|
||||
else{
|
||||
$new_dstFile = "$dstFile-$pkgStateIdentifier";
|
||||
$new_stateIdentifier = $pkgStateIdentifier;
|
||||
}
|
||||
|
||||
# We also check with -e if the wrapperscript-file exists, and if is it a symlink (with -l)
|
||||
if (-l $new_dstFile || -e $new_dstFile) {
|
||||
my $target = readlink_or_StateWrapper $new_dstFile;
|
||||
die "(state) collission between `$srcFile' and `$target' (over $new_dstFile)";
|
||||
}
|
||||
|
||||
sysopen (DSTFILEHANDLE, $new_dstFile, O_RDWR|O_EXCL|O_CREAT, 0755);
|
||||
printf DSTFILEHANDLE "#! @shell@ \n";
|
||||
printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n";
|
||||
close (DSTFILEHANDLE);
|
||||
}
|
||||
|
||||
}
|
||||
elsif($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier eq ""){ #TODO we now dont create symlinks for state packages with a empty identifier
|
||||
#TODO but we must do it if there is no normal non-state pacakge
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
if (-l $dstFile || -e $dstFile) {
|
||||
my $target = readlink_or_StateWrapper $dstFile;
|
||||
my $prevPriority = $priorities{$dstFile};
|
||||
die ( "Collission between `$srcFile' and `$target'. "
|
||||
. "Suggested solution: use `nix-env --set-flag "
|
||||
. "priority NUMBER PKGNAME' to change the priority of "
|
||||
. "one of the conflicting packages.\n" )
|
||||
if $prevPriority == $priority;
|
||||
next if $prevPriority < $priority;
|
||||
unlink $dstFile or die;
|
||||
}
|
||||
|
||||
# print "2ND LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
|
||||
symlink($srcFile, $dstFile) ||
|
||||
die "error creating link `$dstFile': $!";
|
||||
$priorities{$dstFile} = $priority;
|
||||
$symlinks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,13 +158,13 @@ my %postponed;
|
||||
sub addPkg;
|
||||
sub addPkg {
|
||||
my $pkgDir = shift;
|
||||
my $ignoreCollisions = shift;
|
||||
my $priority = shift;
|
||||
|
||||
return if (defined $done{$pkgDir});
|
||||
$done{$pkgDir} = 1;
|
||||
|
||||
# print "symlinking $pkgDir\n";
|
||||
createLinks("$pkgDir", "$out", $ignoreCollisions);
|
||||
createLinks("$pkgDir", "$out", $priority);
|
||||
|
||||
my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
|
||||
if (-e $propagatedFN) {
|
||||
@@ -106,12 +178,56 @@ sub addPkg {
|
||||
}
|
||||
}
|
||||
|
||||
sub readlink_or_StateWrapper {
|
||||
|
||||
# Symlink to the packages that have been installed explicitly by the user.
|
||||
my @args = split ' ', $ENV{"derivations"};
|
||||
my $src = shift;
|
||||
my $target;
|
||||
|
||||
foreach my $pkgDir (sort @args) {
|
||||
addPkg($pkgDir, 0);
|
||||
if (-l $src)
|
||||
{ $target = readlink $src; }
|
||||
else{
|
||||
open(DAT, $src) || die("Could not open file!");
|
||||
my @raw_data=<DAT>;
|
||||
close(DAT);
|
||||
$target = $raw_data[1];
|
||||
}
|
||||
return $target
|
||||
}
|
||||
|
||||
my @stateIdentifiers = split ' ', $ENV{"stateIdentifiers"};
|
||||
my $si_counter = 0;
|
||||
|
||||
# Convert the stuff we get from the environment back into a coherent
|
||||
# data type.
|
||||
my @paths = split ' ', $ENV{"paths"};
|
||||
my @active = split ' ', $ENV{"active"};
|
||||
my @priority = split ' ', $ENV{"priority"};
|
||||
|
||||
die if scalar @paths != scalar @active;
|
||||
die if scalar @paths != scalar @priority;
|
||||
|
||||
my %pkgs;
|
||||
|
||||
for (my $n = 0; $n < scalar @paths; $n++) {
|
||||
$pkgs{$paths[$n]} =
|
||||
{ active => $active[$n]
|
||||
, priority => $priority[$n]
|
||||
, stateidentifier => $stateIdentifiers[$n]
|
||||
};
|
||||
|
||||
$path_state_identifier{$paths[$n]} = $stateIdentifiers[$n];
|
||||
}
|
||||
|
||||
# Symlink to the packages that have been installed explicitly by the
|
||||
# user.
|
||||
foreach my $pkg (sort (keys %pkgs)) {
|
||||
|
||||
#print "SP: $pkg \n";
|
||||
#print "SI: $pkgs{$pkg}->{stateidentifier} \n";
|
||||
#print "PR: $pkgs{$pkg}->{priority} \n";
|
||||
|
||||
addPkg($pkg, $pkgs{$pkg}->{priority}) if $pkgs{$pkg}->{active} ne "false";
|
||||
$si_counter++;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,16 +235,17 @@ foreach my $pkgDir (sort @args) {
|
||||
# installed by the user (i.e., package X declares that it want Y
|
||||
# installed as well). We do these later because they have a lower
|
||||
# priority in case of collisions.
|
||||
my $priorityCounter = 1000; # don't care about collisions
|
||||
while (scalar(keys %postponed) > 0) {
|
||||
|
||||
my @pkgDirs = keys %postponed;
|
||||
%postponed = ();
|
||||
foreach my $pkgDir (sort @pkgDirs) {
|
||||
addPkg($pkgDir, 1);
|
||||
addPkg($pkgDir, $priorityCounter++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print STDERR "created $symlinks symlinks in user environment\n";
|
||||
|
||||
|
||||
symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
{system, derivations, manifest}:
|
||||
{system, derivations, stateIdentifiers, manifest, nixBinDir, nixStore}:
|
||||
|
||||
derivation {
|
||||
name = "user-environment";
|
||||
system = system;
|
||||
builder = ./builder.pl;
|
||||
derivations = derivations;
|
||||
|
||||
stateIdentifiers = stateIdentifiers;
|
||||
manifest = manifest;
|
||||
inherit nixBinDir nixStore;
|
||||
|
||||
# !!! grmbl, need structured data for passing this in a clean way.
|
||||
paths = derivations;
|
||||
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
|
||||
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,23 @@
|
||||
@coreutils@/mkdir $out/tmp
|
||||
cd $out/tmp
|
||||
|
||||
expr=$out/default.nix
|
||||
echo '[' > $expr
|
||||
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 -
|
||||
|
||||
nr=0
|
||||
for i in $inputs; do
|
||||
echo "unpacking $i"
|
||||
@bunzip2@ < $i | @tar@ xf -
|
||||
@coreutils@/mv * ../$nr # !!! hacky
|
||||
echo "(import ./$nr)" >> $expr
|
||||
nr=$(($nr + 1))
|
||||
nr=1
|
||||
attrName=$(echo $channelName | @tr@ -- '- ' '__')
|
||||
dirName=$attrName
|
||||
while test -e ../$dirName; do
|
||||
nr=$((nr+1))
|
||||
dirName=$attrName-$nr
|
||||
done
|
||||
|
||||
@coreutils@/mv * ../$dirName # !!! hacky
|
||||
done
|
||||
|
||||
echo ']' >> $expr
|
||||
|
||||
cd ..
|
||||
@coreutils@/rmdir tmp
|
||||
|
||||
21
createRelease.sh
Executable file
21
createRelease.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
dir1=releases
|
||||
dir2=nix-state
|
||||
mkdir -p $dir1
|
||||
cd $dir1
|
||||
rm -rf $dir2
|
||||
mkdir -p $dir2
|
||||
cd $dir2
|
||||
svn co https://svn.cs.uu.nl:12443/repos/trace/nix/branches/state ./
|
||||
revision=`svn info | grep ^Revision | sed 's/Revision: //g'`
|
||||
cd ..
|
||||
date=`date +%Y%m%d`
|
||||
tarfile=snix-${date}-rev${revision}.tar.gz
|
||||
tar -cvf $tarfile \
|
||||
--preserve-permissions \
|
||||
--atime-preserve \
|
||||
--gzip \
|
||||
--verbose \
|
||||
--no-ignore-command-error \
|
||||
$dir2/
|
||||
@@ -1 +1 @@
|
||||
SUBDIRS = manual
|
||||
SUBDIRS =
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
To produce a `stable' release from the trunk:
|
||||
|
||||
-1. Update the release notes; make sure that the release date is
|
||||
correct.
|
||||
|
||||
0. Make sure that the trunk builds in the release supervisor.
|
||||
|
||||
1. Branch the trunk, e.g., `svn cp .../trunk
|
||||
@@ -22,8 +25,8 @@ To produce a `stable' release from the trunk:
|
||||
branch (e.g., `.../branches/0.5') should be created from the
|
||||
original revision of the trunk (since maintenance releases should
|
||||
also be tested first; hence, we cannot have `STABLE=1'). The same
|
||||
procedure can then be followed to produce maintenance release; just
|
||||
substitute `.../branches/VERSION' for the trunk.
|
||||
procedure can then be followed to produce maintenance releases;
|
||||
just substitute `.../branches/VERSION' for the trunk.
|
||||
|
||||
7. Switch back to the trunk.
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ 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-install-package.1 nix-hash.1 nix-copy-closure.1
|
||||
|
||||
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) \
|
||||
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
|
||||
@@ -31,7 +31,7 @@ MANUAL_SRCS = manual.xml introduction.xml installation.xml \
|
||||
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/stdin; \
|
||||
$(XMLLINT) --xinclude $< | $(jing) $(docbookrng)/docbook.rng /dev/fd/0; \
|
||||
else \
|
||||
echo "Not validating."; \
|
||||
fi
|
||||
@@ -47,6 +47,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) manual.xml; \
|
||||
else \
|
||||
echo "Please install dblatex and rerun configure."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
NEWS_OPTS = \
|
||||
--stringparam generate.toc "article nop" \
|
||||
|
||||
1
doc/manual/NEWS.txt
Normal file
1
doc/manual/NEWS.txt
Normal file
@@ -0,0 +1 @@
|
||||
New state nix version by wouter ...
|
||||
@@ -15,18 +15,6 @@ generation 43 is created which is a descendant of 39, not 42. So a
|
||||
rollback from 43 ought to go back to 39. This is not currently
|
||||
implemented; generations form a linear sequence.</para></listitem>
|
||||
|
||||
<listitem><para><emphasis>Build management.</emphasis> In principle it
|
||||
is already possible to do build management using Nix (by writing
|
||||
builders that perform appropriate build steps), but the Nix expression
|
||||
language is not yet powerful enough to make this pleasant (?). The
|
||||
language should be extended with features from the <link
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/maak/'>Maak build
|
||||
manager</link>. Another interesting idea is to write a
|
||||
<command>make</command> implementation that uses Nix as a back-end to
|
||||
support <link
|
||||
xlink:href='http://www.research.att.com/~bs/bs_faq.html#legacy'>legacy</link>
|
||||
build files.</para></listitem>
|
||||
|
||||
<listitem><para>For security, <command>nix-push</command> manifests
|
||||
should be digitally signed, and <command>nix-pull</command> should
|
||||
verify the signatures. The actual NAR archives in the cache do not
|
||||
|
||||
@@ -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
|
||||
|
||||
760
doc/manual/builtins.xml
Normal file
760
doc/manual/builtins.xml
Normal file
@@ -0,0 +1,760 @@
|
||||
<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.
|
||||
However, in that case you should not write
|
||||
|
||||
<programlisting>
|
||||
if builtins ? getEnv then __getEnv "PATH" else ""</programlisting>
|
||||
|
||||
This Nix expression will trigger an “undefined variable” error on
|
||||
older Nix versions since <function>__getEnv</function> doesn’t
|
||||
exist. <literal>builtins.getEnv</literal>, on the other hand, is
|
||||
safe since <literal>builtins</literal> always exists and attribute
|
||||
selection is lazy, so it’s only performed if the test
|
||||
succeeds.</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.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.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>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.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.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>
|
||||
@@ -118,6 +118,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
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
<variablelist>
|
||||
|
||||
|
||||
<varlistentry><term><envar>NIX_ROOT</envar></term>
|
||||
|
||||
<listitem><para>If <envar>NIX_ROOT</envar> is set, the Nix command
|
||||
will on startup perform a <function>chroot()</function> to the
|
||||
specified directory. This is useful in certain bootstrapping
|
||||
situations (e.g., when installing a Nix installation onto a hard
|
||||
disk from CD-ROM).</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry><term><envar>NIX_IGNORE_SYMLINK_STORE</envar></term>
|
||||
|
||||
<listitem>
|
||||
@@ -274,6 +263,17 @@ $ 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>
|
||||
|
||||
|
||||
</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>
|
||||
|
||||
|
||||
@@ -6,12 +6,44 @@
|
||||
<title>Installation</title>
|
||||
|
||||
|
||||
<section><title>Supported platforms</title>
|
||||
|
||||
<para>Nix is currently supported on the following platforms:
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para>Linux (particularly on x86, x86_64, and
|
||||
PowerPC).</para></listitem>
|
||||
|
||||
<listitem><para>Mac OS X, both on Intel and
|
||||
PowerPC.</para></listitem>
|
||||
|
||||
<listitem><para>FreeBSD (only tested on Intel).</para></listitem>
|
||||
|
||||
<listitem><para>Windows through <link
|
||||
xlink:href="http://www.cygwin.com/">Cygwin</link>.</para>
|
||||
|
||||
<warning><para>On Cygwin, Nix <emphasis>must</emphasis> be installed
|
||||
on an NTFS partition. It will not work correctly on a FAT
|
||||
partition.</para></warning>
|
||||
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Nix is pretty portable, so it should work on most other Unix
|
||||
platforms as well.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<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://nix.cs.uu.nl/">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
|
||||
@@ -57,25 +89,28 @@ repository.</para>
|
||||
<para>To build the parser, very <emphasis>recent</emphasis> versions
|
||||
of Bison and Flex are required. (This is because Nix needs GLR
|
||||
support in Bison and reentrancy support in Flex.) For Bison, you need
|
||||
version 1.875c or higher (1.875 does <emphasis>not</emphasis> work),
|
||||
which can be obtained from the <link
|
||||
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP server</link>.
|
||||
For Flex, you need version 2.5.31, which is available on <link
|
||||
xlink:href="http://lex.sourceforge.net/">SourceForge</link>. Slightly
|
||||
older versions may also work, but ancient versions like the ubiquitous
|
||||
2.5.4a won't. Note that these are only required if you modify the
|
||||
parser or when you are building from the Subversion repository.</para>
|
||||
version 2.3 or higher (1.875 does <emphasis>not</emphasis> work),
|
||||
which can be obtained from
|
||||
the <link xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP
|
||||
server</link>. For Flex, you need version 2.5.33, which is available
|
||||
on <link xlink:href="http://lex.sourceforge.net/">SourceForge</link>.
|
||||
Slightly older versions may also work, but ancient versions like the
|
||||
ubiquitous 2.5.4a won't. Note that these are only required if you
|
||||
modify the parser or when you are building from the 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 Sleepycat's Berkeley DB, CWI's ATerm library and the
|
||||
bzip2 compressor (including the bzip2 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
|
||||
<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
|
||||
you can use <command>configure</command>'s
|
||||
<option>--with-bdb</option>, <option>--with-aterm</option> and
|
||||
<option>--with-bzip2</option> options to point to their respective
|
||||
locations. Note that Berkeley DB <emphasis>must</emphasis> be version
|
||||
4.4; other versions may not have compatible database formats.</para>
|
||||
4.5; other versions may not have compatible database formats.</para>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -84,19 +119,21 @@ 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>
|
||||
$ autoreconf -i</screen>
|
||||
$ ./bootstrap</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>The installation path can be specified by passing the
|
||||
<option>--prefix=<replaceable>prefix</replaceable></option> to
|
||||
@@ -123,28 +160,32 @@ options.</para>
|
||||
|
||||
<section><title>Installing from RPMs</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>RPM packages of Nix can be downloaded from <link
|
||||
xlink:href="http://nix.cs.uu.nl/" />. 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>
|
||||
<command>rpm -U</command>. For example,
|
||||
|
||||
<screen>
|
||||
$ rpm -U nix-0.5pre664-1.i386.rpm</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<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>
|
||||
auxiliary data:
|
||||
|
||||
<screen>
|
||||
$ rm -rf /nix/store
|
||||
$ rm -rf /nix/var</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@@ -152,8 +193,8 @@ $ rm -rf /nix/var</screen>
|
||||
|
||||
<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-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" />.
|
||||
You can also do a <link linkend="sec-one-click">one-click
|
||||
installation</link> by clicking on the package links at <link
|
||||
@@ -162,54 +203,252 @@ xlink:href="http://nix.cs.uu.nl/dist/nix/" />.</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Permissions</title>
|
||||
<section><title>Security</title>
|
||||
|
||||
<para>All Nix operations must be performed under the user ID that owns
|
||||
the Nix store and database
|
||||
(<filename><replaceable>prefix</replaceable>/store</filename> and
|
||||
<filename><replaceable>prefix</replaceable>/var/nix/db</filename>,
|
||||
respectively). When installed from the RPM packages, these
|
||||
directories are owned by <systemitem class="username">root</systemitem>.</para>
|
||||
<para>Nix has two basic security models. First, it can be used in
|
||||
“single-user mode”, which is similar to what most other package
|
||||
management tools do: there is a single user (typically <systemitem
|
||||
class="username">root</systemitem>) who performs all package
|
||||
management operations. All other users can then use the installed
|
||||
packages, but they cannot perform package management operations
|
||||
themselves.</para>
|
||||
|
||||
<section><title>Setuid installation</title>
|
||||
<para>Alternatively, you can configure Nix in “multi-user mode”. In
|
||||
this model, all users can perform package management operations — for
|
||||
instance, every user can install software without requiring root
|
||||
privileges. Nix ensures that this is secure. For instance, it’s not
|
||||
possible for one user to overwrite a package used by another user with
|
||||
a Trojan horse.</para>
|
||||
|
||||
<para>As a somewhat <emphasis>ad hoc</emphasis> hack, you can also
|
||||
install the Nix binaries <quote>setuid</quote> so that a Nix store can
|
||||
be shared among several users. To do this, configure Nix with the
|
||||
<emphasis>--enable-setuid</emphasis> option. Nix will be installed as
|
||||
owned by a user and group specified by the
|
||||
<option>--with-nix-user=</option><parameter>user</parameter> and
|
||||
<option>--with-nix-group=</option><parameter>group</parameter>
|
||||
options. E.g.,
|
||||
|
||||
<screen>
|
||||
$ ./configure --enable-setuid --with-nix-user=my_nix_user --with-nix-group=my_nix_group</screen>
|
||||
<section><title>Single-user mode</title>
|
||||
|
||||
<para>In single-user mode, all Nix operations that access the database
|
||||
in <filename><replaceable>prefix</replaceable>/var/nix/db</filename>
|
||||
or modify the Nix store in
|
||||
<filename><replaceable>prefix</replaceable>/store</filename> must be
|
||||
performed under the user ID that owns those directories. This is
|
||||
typically <systemitem class="username">root</systemitem>. (If you
|
||||
install from RPM packages, that’s in fact the default ownership.)
|
||||
However, on single-user machines, it is often convenient to
|
||||
<command>chown</command> those directories to your normal user account
|
||||
so that you don’t have to <command>su</command> to <systemitem
|
||||
class="username">root</systemitem> all the time.</para>
|
||||
|
||||
The user and group default to <literal>nix</literal>. You should make
|
||||
sure that both the user and the group exist. Any <quote>real</quote>
|
||||
users that you want to allow access should be added to the Nix
|
||||
</section>
|
||||
|
||||
|
||||
<section xml:id="ssec-multi-user"><title>Multi-user mode</title>
|
||||
|
||||
<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>
|
||||
|
||||
<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 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>
|
||||
|
||||
<warning><para>A setuid installation should only by used if the users
|
||||
in the Nix group are mutually trusted, since any user in that group
|
||||
has the ability to change anything in the Nix store or database. For
|
||||
instance, they could install a trojan horse in executables used by
|
||||
other users.</para></warning>
|
||||
<para>Here is the corresponding part of
|
||||
<filename>/etc/passwd</filename>:
|
||||
|
||||
<warning><para>On some platforms, the Nix binaries will be installed
|
||||
as setuid <literal>root</literal>. They drop root privileges
|
||||
immediately after startup and switch to the Nix user. The reason for
|
||||
this is that both the real and effective user must be set to the Nix
|
||||
user, and POSIX has no system call to do this. This is not the case
|
||||
on systems that have the <function>setresuid()</function> system call
|
||||
(such as Linux and FreeBSD), so on those systems the binaries are
|
||||
simply owned by the Nix user.</para></warning>
|
||||
<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><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 Nix daemon 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>
|
||||
|
||||
<para>To use Nix, some environment variables should be set. In
|
||||
|
||||
@@ -1,135 +1,304 @@
|
||||
<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://nix.cs.uu.nl/nixos/">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 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>. The project is 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.</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
|
||||
</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.cs.uu.nl/~eelco/pubs/immdsd-icse2004-final.pdf'>Imposing
|
||||
a Memory Management Discipline on Software Deployment</citetitle>
|
||||
discusses the hashing mechanism used to ensure reliable dependency
|
||||
@@ -141,10 +310,27 @@ 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
|
||||
Upgrading in a Purely Functional Component Deployment Model
|
||||
</citetitle> is about transparent patch deployment in Nix. Finally,
|
||||
the SCM-12 paper <citetitle
|
||||
</citetitle> is about transparent patch deployment in Nix. The SCM-12
|
||||
paper <citetitle
|
||||
xlink:href='http://www.cs.uu.nl/~eelco/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.cs.uu.nl/~eelco/pubs/hotos-final.pdf">Purely
|
||||
Functional System Configuration Management</citetitle>. The Nix
|
||||
homepage has <link
|
||||
xlink:href="http://nix.cs.uu.nl/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://nix.cs.uu.nl/"/>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -13,14 +13,21 @@
|
||||
<firstname>Eelco</firstname>
|
||||
<surname>Dolstra</surname>
|
||||
</personname>
|
||||
<affiliation>
|
||||
<orgname>Utrecht University</orgname>
|
||||
<orgdiv>Faculty of Science, Department of Information and Computing Sciences</orgdiv>
|
||||
</affiliation>
|
||||
</author>
|
||||
|
||||
<copyright>
|
||||
<year>2004</year>
|
||||
<year>2005</year>
|
||||
<year>2006</year>
|
||||
<year>2007</year>
|
||||
<holder>Eelco Dolstra</holder>
|
||||
</copyright>
|
||||
|
||||
<date>September 2007</date>
|
||||
|
||||
</info>
|
||||
|
||||
@@ -49,7 +56,7 @@
|
||||
<title>nix-instantiate</title>
|
||||
<xi:include href="nix-instantiate.xml" />
|
||||
</section>
|
||||
<section>
|
||||
<section xml:id="sec-nix-store">
|
||||
<title>nix-store</title>
|
||||
<xi:include href="nix-store.xml" />
|
||||
</section>
|
||||
@@ -65,10 +72,14 @@
|
||||
<title>nix-channel</title>
|
||||
<xi:include href="nix-channel.xml" />
|
||||
</section>
|
||||
<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" />
|
||||
@@ -77,15 +88,15 @@
|
||||
<title>nix-install-package</title>
|
||||
<xi:include href="nix-install-package.xml" />
|
||||
</section>
|
||||
<section>
|
||||
<section xml:id="sec-nix-pack-closure">
|
||||
<title>nix-pack-closure</title>
|
||||
<xi:include href="nix-pack-closure.xml" />
|
||||
</section>
|
||||
<section>
|
||||
<section xml:id="sec-nix-prefetch-url">
|
||||
<title>nix-prefetch-url</title>
|
||||
<xi:include href="nix-prefetch-url.xml" />
|
||||
</section>
|
||||
<section>
|
||||
<section xml:id="sec-nix-pull">
|
||||
<title>nix-pull</title>
|
||||
<xi:include href="nix-pull.xml" />
|
||||
</section>
|
||||
@@ -93,7 +104,7 @@
|
||||
<title>nix-push</title>
|
||||
<xi:include href="nix-push.xml" />
|
||||
</section>
|
||||
<section>
|
||||
<section xml:id="sec-nix-unpack-closure">
|
||||
<title>nix-unpack-closure</title>
|
||||
<xi:include href="nix-unpack-closure.xml" />
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-build</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-build</refname>
|
||||
@@ -9,8 +17,9 @@
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-build</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
|
||||
<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,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-channel</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-channel</refname>
|
||||
<refpurpose>manage Nix channels</refpurpose>
|
||||
@@ -54,11 +62,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,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-collect-garbage</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-collect-garbage</refname>
|
||||
<refpurpose>delete unreachable store paths</refpurpose>
|
||||
|
||||
151
doc/manual/nix-copy-closure.xml
Normal file
151
doc/manual/nix-copy-closure.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<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-copy-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-copy-closure</refname>
|
||||
<refpurpose>copy a closure to or from a remote machine via SSH</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-copy-closure</command>
|
||||
<group>
|
||||
<arg choice='plain'><option>--to</option></arg>
|
||||
<arg choice='plain'><option>--from</option></arg>
|
||||
</group>
|
||||
<arg><option>--sign</option></arg>
|
||||
<arg><option>--gzip</option></arg>
|
||||
<arg choice='plain'>
|
||||
<arg><replaceable>user@</replaceable></arg><replaceable>machine</replaceable>
|
||||
</arg>
|
||||
<arg choice='plain'><replaceable>paths</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para><command>nix-copy-closure</command> gives you an easy and
|
||||
efficient way to exchange software between machines. Given one or
|
||||
more Nix store paths <replaceable>paths</replaceable> on the local
|
||||
machine, <command>nix-copy-closure</command> computes the closure of
|
||||
those paths (i.e. all their dependencies in the Nix store), and copies
|
||||
all paths in the closure to the remote machine via the
|
||||
<command>ssh</command> (Secure Shell) command. With the
|
||||
<option>--from</option>, the direction is reversed:
|
||||
the closure of <replaceable>paths</replaceable> on a remote machine is
|
||||
copied to the Nix store on the local machine.</para>
|
||||
|
||||
<para>This command is efficient because it only sends the store paths
|
||||
that are missing on the target machine.</para>
|
||||
|
||||
<para>Since <command>nix-copy-closure</command> calls
|
||||
<command>ssh</command>, you may be asked to type in the appropriate
|
||||
password or passphrase. In fact, you may be asked
|
||||
<emphasis>twice</emphasis> because <command>nix-copy-closure</command>
|
||||
currently connects twice to the remote machine, first to get the set
|
||||
of paths missing on the target machine, and second to send the dump of
|
||||
those paths. If this bothers you, use
|
||||
<command>ssh-agent</command>.</para>
|
||||
|
||||
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><option>--to</option></term>
|
||||
|
||||
<listitem><para>Copy the closure of
|
||||
<replaceable>paths</replaceable> from the local Nix store to the
|
||||
Nix store on <replaceable>machine</replaceable>. This is the
|
||||
default.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--from</option></term>
|
||||
|
||||
<listitem><para>Copy the closure of
|
||||
<replaceable>paths</replaceable> from the Nix store on
|
||||
<replaceable>machine</replaceable> to the local Nix
|
||||
store.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--sign</option></term>
|
||||
|
||||
<listitem><para>Let the sending machine cryptographically sign the
|
||||
dump of each path with the key in
|
||||
<filename>/nix/etc/nix/signing-key.sec</filename>. If the user on
|
||||
the target machine does not have direct access to the Nix store
|
||||
(i.e., if the target machine has a multi-user Nix installation),
|
||||
then the target machine will check the dump against
|
||||
<filename>/nix/etc/nix/signing-key.pub</filename> before unpacking
|
||||
it in its Nix store. This allows secure sharing of store paths
|
||||
between untrusted users on two machines, provided that there is a
|
||||
trust relation between the Nix installations on both machines
|
||||
(namely, they have matching public/secret keys).</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><option>--gzip</option></term>
|
||||
|
||||
<listitem><para>Compress the dump of each path with
|
||||
<command>gzip</command> before sending it.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Environment variables</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><envar>NIX_SSHOPTS</envar></term>
|
||||
|
||||
<listitem><para>Additional options to be passed to
|
||||
<command>ssh</command> on the command line.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
|
||||
<para>Copy Firefox with all its dependencies to a remote machine:
|
||||
|
||||
<screen>
|
||||
$ nix-copy-closure alice@itchy.labs $(type -tP firefox)</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>Copy Subversion from a remote machine and then install it into a
|
||||
user environment:
|
||||
|
||||
<screen>
|
||||
$ nix-copy-closure --from alice@itchy.labs \
|
||||
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||
$ nix-env -i /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
</refentry>
|
||||
@@ -1,6 +1,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-env</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-env</refname>
|
||||
<refpurpose>manipulate or query Nix user environments</refpurpose>
|
||||
@@ -9,15 +17,9 @@
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-env</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
|
||||
<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>
|
||||
@@ -37,9 +39,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>
|
||||
@@ -50,7 +49,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
|
||||
@@ -142,14 +141,34 @@ linkend="sec-common-options" />.</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><filename>~/.nix-defexpr</filename></term>
|
||||
|
||||
<listitem><para>The default Nix expression used by the
|
||||
<option>--install</option>, <option>--upgrade</option>, and
|
||||
<option>--query --available</option> operations to obtain
|
||||
derivations. It is generally a symbolic link to some other
|
||||
location set using the <option>--import</option> operation. The
|
||||
|
||||
<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></listitem>
|
||||
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>
|
||||
|
||||
@@ -182,6 +201,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>
|
||||
@@ -213,11 +233,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>
|
||||
@@ -264,6 +294,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>
|
||||
|
||||
@@ -379,7 +418,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>
|
||||
|
||||
@@ -389,6 +428,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>
|
||||
@@ -463,6 +503,9 @@ installed.</para>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>For the other flags, see <option
|
||||
linkend="rsec-nix-env-install">--install</option>.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
@@ -572,6 +615,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>
|
||||
@@ -584,13 +732,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>
|
||||
@@ -599,8 +748,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>
|
||||
@@ -614,6 +763,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>
|
||||
|
||||
@@ -690,6 +861,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>
|
||||
|
||||
@@ -709,8 +890,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
|
||||
@@ -733,35 +914,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>
|
||||
@@ -802,6 +983,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>
|
||||
@@ -1061,43 +1250,4 @@ error: no generation older than the current (91) exists</screen>
|
||||
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--import</option></title>
|
||||
|
||||
<refsection><title>Synopsis</title>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>nix-env</command>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--import</option></arg>
|
||||
<arg choice='plain'><option>-I</option></arg>
|
||||
</group>
|
||||
<arg choice='req'><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>This operation makes <replaceable>path</replaceable> the default
|
||||
active Nix expression for the user. That is, the symlink
|
||||
<filename>~/.nix-userenv</filename> is made to point to
|
||||
<replaceable>path</replaceable>.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
|
||||
<screen>
|
||||
$ nix-env -I ~/nixpkgs-0.5/</screen>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-hash</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-hash</refname>
|
||||
<refpurpose>compute the cryptographic hash of a path</refpurpose>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-install-package</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-install-package</refname>
|
||||
<refpurpose>install a Nix Package file</refpurpose>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-instantiate</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-instantiate</refname>
|
||||
<refpurpose>instantiate store derivations from Nix expressions</refpurpose>
|
||||
@@ -9,7 +17,7 @@
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-instantiate</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
|
||||
<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'>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<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>
|
||||
@@ -58,6 +66,16 @@ $ 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>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
<refentry>
|
||||
<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-prefetch-url</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-prefetch-url</refname>
|
||||
<refpurpose>copy a file from a URL into the store and print its MD5 hash</refpurpose>
|
||||
@@ -38,7 +47,7 @@ avoided.</para>
|
||||
<para>The environment variable <envar>NIX_HASH_ALGO</envar> specifies
|
||||
which hash algorithm to use. It can be either <literal>md5</literal>,
|
||||
<literal>sha1</literal>, or <literal>sha256</literal>. The default is
|
||||
<literal>md5</literal>.</para>
|
||||
<literal>sha256</literal>.</para>
|
||||
|
||||
<para>If <replaceable>hash</replaceable> is specified, then a download
|
||||
is not performed if the Nix store already contains a file with the
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-pull</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-pull</refname>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-push</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-push</refname>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>nix-store</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Nix</refmiscinfo>
|
||||
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>nix-store</refname>
|
||||
@@ -9,7 +17,7 @@
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
|
||||
<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>--add-root</option> <replaceable>path</replaceable></arg>
|
||||
<arg><option>--indirect</option></arg>
|
||||
<arg choice='plain'><replaceable>operation</replaceable></arg>
|
||||
@@ -651,37 +659,7 @@ $ gv graph.ps</screen>
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<!--
|
||||
<refsection><title>Operation <option>-XXX-substitute</option></title>
|
||||
|
||||
<refsection><title>Synopsis</title>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>nix-store</command>
|
||||
<arg choice='plain'><option>-XXX-substitute</option></arg>
|
||||
<arg choice='plain'
|
||||
rep='repeat'><replaceable>srcpath</replaceable> <replaceable>subpath</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The operation <option>-XXX-substitute</option> registers that the
|
||||
store path <replaceable>srcpath</replaceable> can be built by
|
||||
realising the derivation expression in
|
||||
<replaceable>subpath</replaceable>. This is used to implement binary
|
||||
deployment.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
</refsection>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!--######################################################################-->
|
||||
|
||||
<refsection><title>Operation <option>--verify</option></title>
|
||||
<refsection xml:id='refsec-nix-store-verify'><title>Operation <option>--verify</option></title>
|
||||
|
||||
<refsection>
|
||||
<title>Synopsis</title>
|
||||
@@ -801,4 +779,178 @@ 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>
|
||||
|
||||
|
||||
<!-- TODO: export, import operations -->
|
||||
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<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>
|
||||
@@ -22,6 +30,12 @@ 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>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nop>
|
||||
<nop xmlns="http://docbook.org/ns/docbook">
|
||||
|
||||
<arg><option>--help</option></arg>
|
||||
<arg><option>--version</option></arg>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
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,10 +30,10 @@ 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
|
||||
@@ -41,7 +41,7 @@ the latest version from <link
|
||||
xlink:href='http://nix.cs.uu.nl/dist/nix' />.</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 know 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,7 +112,7 @@ 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
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -11,7 +11,7 @@ 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
|
||||
xlink:href='http://nix.cs.uu.nl/'/>. Build source
|
||||
distributions using the regular sequence:
|
||||
|
||||
<screen>
|
||||
@@ -22,8 +22,9 @@ $ 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
|
||||
impossible to use pre-built binaries from the Nixpkgs channel and
|
||||
other channels. 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
|
||||
file).</para></listitem>
|
||||
@@ -40,14 +41,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 +60,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,8 +93,8 @@ $ 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
|
||||
@@ -107,7 +108,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 +125,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.-->
|
||||
|
||||
|
||||
@@ -1,10 +1,297 @@
|
||||
<article xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:id="sec-relnotes">
|
||||
|
||||
<title>Nix Release Notes</title>
|
||||
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section xml:id="ssec-relnotes-0.12"><title>Release 0.12 (TBA)</title>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para><command>nix-store --dump-db / --load-db</command>.</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>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 via
|
||||
<command>ssh</command>.</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><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><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><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><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. 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>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><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>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>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section><title>Release 0.10.1 (October 11, 2006)</title>
|
||||
|
||||
<para>This release fixes two somewhat obscure bugs that occur when
|
||||
evaluating Nix expressions that are stored inside the Nix store
|
||||
(<literal>NIX-67</literal>). These do not affect most users.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section><title>Release 0.10 (October 6, 2006)</title>
|
||||
|
||||
@@ -46,6 +46,11 @@ h3 /* subsections */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
<title>Troubleshooting</title>
|
||||
|
||||
|
||||
<para>This section provides solutions for some common problems.</para>
|
||||
<para>This section provides solutions for some common problems. See
|
||||
the <link xlink:href="https://bugs.cs.uu.nl/browse/NIX">Nix
|
||||
bug tracker</link> for a list of currently known issues.</para>
|
||||
|
||||
|
||||
<section><title>Berkeley DB: <quote>Cannot allocate memory</quote></title>
|
||||
@@ -33,6 +35,91 @@ $ rm __db.00*</screen>
|
||||
</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>
|
||||
|
||||
|
||||
<section><title>Berkeley DB out of locks</title>
|
||||
|
||||
<para>It is possible, especially in <command>nix-store
|
||||
--verify</command> or when running the garbage collector, to run out
|
||||
of Berkeley DB locks, like this:
|
||||
|
||||
<screen>
|
||||
$ nix-store --verify
|
||||
checking path existence
|
||||
checking path realisability
|
||||
checking the derivers table
|
||||
checking the references table
|
||||
Berkeley DB error: Lock table is out of available object entries
|
||||
error: Db::get: Cannot allocate memory</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>A workaround is to increase the number of locks that Berkeley DB
|
||||
allocates. (The real solution would be for Nix to not use so many
|
||||
locks.) This can be done by putting the following in the file
|
||||
<filename>/nix/var/nix/db/<link
|
||||
xlink:href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/env/db_config.html">DB_CONFIG</link></filename>:
|
||||
|
||||
<programlisting>
|
||||
set_lk_max_locks 100000
|
||||
set_lk_max_lockers 100000
|
||||
set_lk_max_objects 100000
|
||||
</programlisting>
|
||||
|
||||
(Increase these numbers if necessary.) Then make sure that there are
|
||||
no running Nix processes and delete the Berkeley DB environment:
|
||||
|
||||
<screen>
|
||||
$ rm /nix/var/nix/db/__db.*</screen>
|
||||
|
||||
The Berkeley DB environment is automatically recreated with the new
|
||||
limits when you run any Nix command.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Collisions in <command>nix-env</command></title>
|
||||
|
||||
<para>Symptom: when installing or upgrading, you get an error message such as
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
24
doc/signing.txt
Normal file
24
doc/signing.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
Generate a private key:
|
||||
|
||||
$ (umask 277 && openssl genrsa -out /nix/etc/nix/signing-key.sec 2048)
|
||||
|
||||
The private key should be kept secret (only readable to the Nix daemon
|
||||
user).
|
||||
|
||||
|
||||
Generate the corresponding public key:
|
||||
|
||||
$ openssl rsa -in /nix/etc/nix/signing-key.sec -pubout > /nix/etc/nix/signing-key.pub
|
||||
|
||||
The public key should be copied to all machines to which you want to
|
||||
export store paths.
|
||||
|
||||
|
||||
Signing:
|
||||
|
||||
$ nix-hash --type sha256 --flat svn.nar | openssl rsautl -sign -inkey mykey.sec > svn.nar.sign
|
||||
|
||||
|
||||
Verifying a signature:
|
||||
|
||||
$ test "$(nix-hash --type sha256 --flat svn.nar)" = "$(openssl rsautl -verify -inkey mykey.pub -pubin -in svn.nar.sign)"
|
||||
30
externals/Makefile.am
vendored
30
externals/Makefile.am
vendored
@@ -1,11 +1,11 @@
|
||||
# Berkeley DB
|
||||
|
||||
DB = db-4.4.20.NC
|
||||
DB = db-4.5.20
|
||||
|
||||
$(DB).tar.gz:
|
||||
@echo "Nix requires Berkeley DB to build."
|
||||
@echo "Please download version 4.4.20 from"
|
||||
@echo " http://downloads.sleepycat.com/db-4.4.20.NC.tar.gz"
|
||||
@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
|
||||
|
||||
@@ -35,19 +35,17 @@ endif
|
||||
|
||||
# CWI ATerm
|
||||
|
||||
ATERM = aterm-2.4.2
|
||||
ATERM = aterm-2.4.2-fixes-r2
|
||||
|
||||
$(ATERM).tar.gz:
|
||||
$(ATERM).tar.bz2:
|
||||
@echo "Nix requires the CWI ATerm library to build."
|
||||
@echo "Please download version 2.4.2 from"
|
||||
@echo " http://www.cwi.nl/projects/MetaEnv/aterm/aterm-2.4.2.tar.gz"
|
||||
@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.gz
|
||||
gunzip < $(srcdir)/$(ATERM).tar.gz | tar xvf -
|
||||
(cd $(ATERM) && $(patch) -p1) < $(srcdir)/aterm-aliasing.patch
|
||||
# (cd $(ATERM) && $(patch) -p1) < $(srcdir)/aterm-64-bit.patch
|
||||
$(ATERM): $(ATERM).tar.bz2
|
||||
bunzip2 < $(srcdir)/$(ATERM).tar.bz2 | tar xvf -
|
||||
|
||||
have-aterm:
|
||||
$(MAKE) $(ATERM)
|
||||
@@ -69,12 +67,12 @@ endif
|
||||
|
||||
# bzip2
|
||||
|
||||
BZIP2 = bzip2-1.0.3
|
||||
BZIP2 = bzip2-1.0.4
|
||||
|
||||
$(BZIP2).tar.gz:
|
||||
@echo "Nix requires bzip2 to build."
|
||||
@echo "Please download version 1.0.3 from"
|
||||
@echo " http://www.bzip.org/1.0.3/bzip2-1.0.3.tar.gz"
|
||||
@echo "Please download version 1.0.4 from"
|
||||
@echo " http://www.bzip.org/1.0.4/bzip2-1.0.4.tar.gz"
|
||||
@echo "and place it in the externals/ directory."
|
||||
false
|
||||
|
||||
@@ -103,8 +101,8 @@ endif
|
||||
|
||||
all: build-db build-aterm build-bzip2
|
||||
|
||||
EXTRA_DIST = $(DB).tar.gz $(ATERM).tar.gz $(BZIP2).tar.gz \
|
||||
bdb-cygwin.patch aterm-aliasing.patch aterm-64-bit.patch
|
||||
EXTRA_DIST = $(DB).tar.gz $(ATERM).tar.bz2 $(BZIP2).tar.gz \
|
||||
bdb-cygwin.patch
|
||||
|
||||
ext-clean:
|
||||
$(RM) -f have-db build-db have-aterm build-aterm
|
||||
|
||||
661
externals/aterm-64-bit.patch
vendored
661
externals/aterm-64-bit.patch
vendored
@@ -1,661 +0,0 @@
|
||||
diff -rc aterm-2.4.2-orig/aterm/bafio.c aterm-2.4.2/aterm/bafio.c
|
||||
*** aterm-2.4.2-orig/aterm/bafio.c 2004-02-02 12:24:34.000000000 +0100
|
||||
--- aterm-2.4.2/aterm/bafio.c 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 222,227 ****
|
||||
--- 222,229 ----
|
||||
}
|
||||
}
|
||||
|
||||
+ if (val) return -1;
|
||||
+
|
||||
/* Ok */
|
||||
return 0;
|
||||
}
|
||||
***************
|
||||
*** 544,551 ****
|
||||
* terms have been sorted by symbol.
|
||||
*/
|
||||
|
||||
! void gather_top_symbols(sym_entry *cur_entry, int cur_arg,
|
||||
! int total_top_symbols)
|
||||
{
|
||||
int index;
|
||||
unsigned int hnr;
|
||||
--- 546,553 ----
|
||||
* terms have been sorted by symbol.
|
||||
*/
|
||||
|
||||
! static void gather_top_symbols(sym_entry *cur_entry, int cur_arg,
|
||||
! int total_top_symbols)
|
||||
{
|
||||
int index;
|
||||
unsigned int hnr;
|
||||
***************
|
||||
*** 899,905 ****
|
||||
} else {
|
||||
switch(ATgetType(t)) {
|
||||
case AT_INT:
|
||||
! if(writeBits(ATgetInt((ATermInt)t), HEADER_BITS, writer) < 0) {
|
||||
return ATfalse;
|
||||
}
|
||||
#if 0
|
||||
--- 901,908 ----
|
||||
} else {
|
||||
switch(ATgetType(t)) {
|
||||
case AT_INT:
|
||||
! /* If ATerm integers are > 32 bits, then this can fail. */
|
||||
! if(writeBits(ATgetInt((ATermInt)t), INT_SIZE_IN_BAF, writer) < 0) {
|
||||
return ATfalse;
|
||||
}
|
||||
#if 0
|
||||
***************
|
||||
*** 1033,1039 ****
|
||||
/*}}} */
|
||||
/*{{{ ATbool write_baf(ATerm t, byte_writer *writer) */
|
||||
|
||||
! ATbool
|
||||
write_baf(ATerm t, byte_writer *writer)
|
||||
{
|
||||
int nr_unique_terms = 0;
|
||||
--- 1036,1042 ----
|
||||
/*}}} */
|
||||
/*{{{ ATbool write_baf(ATerm t, byte_writer *writer) */
|
||||
|
||||
! static ATbool
|
||||
write_baf(ATerm t, byte_writer *writer)
|
||||
{
|
||||
int nr_unique_terms = 0;
|
||||
***************
|
||||
*** 1233,1239 ****
|
||||
* Read a single symbol from file.
|
||||
*/
|
||||
|
||||
! Symbol read_symbol(byte_reader *reader)
|
||||
{
|
||||
unsigned int arity, quoted;
|
||||
int len;
|
||||
--- 1236,1242 ----
|
||||
* Read a single symbol from file.
|
||||
*/
|
||||
|
||||
! static Symbol read_symbol(byte_reader *reader)
|
||||
{
|
||||
unsigned int arity, quoted;
|
||||
int len;
|
||||
***************
|
||||
*** 1260,1266 ****
|
||||
* Read all symbols from file.
|
||||
*/
|
||||
|
||||
! ATbool read_all_symbols(byte_reader *reader)
|
||||
{
|
||||
unsigned int val;
|
||||
int i, j, k, arity;
|
||||
--- 1263,1269 ----
|
||||
* Read all symbols from file.
|
||||
*/
|
||||
|
||||
! static ATbool read_all_symbols(byte_reader *reader)
|
||||
{
|
||||
unsigned int val;
|
||||
int i, j, k, arity;
|
||||
***************
|
||||
*** 1280,1293 ****
|
||||
/*}}} */
|
||||
/*{{{ Read term count and allocate space */
|
||||
|
||||
! if(readInt(&val, reader) < 0)
|
||||
return ATfalse;
|
||||
read_symbols[i].nr_terms = val;
|
||||
read_symbols[i].term_width = bit_width(val);
|
||||
! if(val == 0)
|
||||
! read_symbols[i].terms = NULL;
|
||||
! else
|
||||
! read_symbols[i].terms = (ATerm *)calloc(val, sizeof(ATerm));
|
||||
if(!read_symbols[i].terms)
|
||||
ATerror("read_symbols: could not allocate space for %d terms.\n", val);
|
||||
ATprotectArray(read_symbols[i].terms, val);
|
||||
--- 1283,1293 ----
|
||||
/*}}} */
|
||||
/*{{{ Read term count and allocate space */
|
||||
|
||||
! if(readInt(&val, reader) < 0 || val == 0)
|
||||
return ATfalse;
|
||||
read_symbols[i].nr_terms = val;
|
||||
read_symbols[i].term_width = bit_width(val);
|
||||
! read_symbols[i].terms = (ATerm *)calloc(val, sizeof(ATerm));
|
||||
if(!read_symbols[i].terms)
|
||||
ATerror("read_symbols: could not allocate space for %d terms.\n", val);
|
||||
ATprotectArray(read_symbols[i].terms, val);
|
||||
***************
|
||||
*** 1351,1357 ****
|
||||
/*}}} */
|
||||
/*{{{ ATerm read_term(sym_read_entry *sym, byte_reader *reader) */
|
||||
|
||||
! ATerm read_term(sym_read_entry *sym, byte_reader *reader)
|
||||
{
|
||||
unsigned int val;
|
||||
int i, arity = sym->arity;
|
||||
--- 1351,1357 ----
|
||||
/*}}} */
|
||||
/*{{{ ATerm read_term(sym_read_entry *sym, byte_reader *reader) */
|
||||
|
||||
! static ATerm read_term(sym_read_entry *sym, byte_reader *reader)
|
||||
{
|
||||
unsigned int val;
|
||||
int i, arity = sym->arity;
|
||||
***************
|
||||
*** 1365,1370 ****
|
||||
--- 1365,1371 ----
|
||||
ATprotectArray(args, arity);
|
||||
if(!args)
|
||||
ATerror("could not allocate space for %d arguments.\n", arity);
|
||||
+ /* !!! leaks memory on the "return NULL" paths */
|
||||
}
|
||||
|
||||
/*ATfprintf(stderr, "reading term over symbol %y\n", sym->sym);*/
|
||||
***************
|
||||
*** 1372,1377 ****
|
||||
--- 1373,1380 ----
|
||||
/*ATfprintf(stderr, " reading argument %d (%d)", i, sym->sym_width[i]);*/
|
||||
if(readBits(&val, sym->sym_width[i], reader) < 0)
|
||||
return NULL;
|
||||
+ if(val >= sym->nr_topsyms[i])
|
||||
+ return NULL;
|
||||
arg_sym = &read_symbols[sym->topsyms[i][val]];
|
||||
/* ATfprintf(stderr, "argument %d, symbol index = %d, symbol = %y\n",
|
||||
i, val, arg_sym->sym);*/
|
||||
***************
|
||||
*** 1381,1386 ****
|
||||
--- 1384,1391 ----
|
||||
if(readBits(&val, arg_sym->term_width, reader) < 0)
|
||||
return NULL;
|
||||
/* ATfprintf(stderr, "arg term index = %d\n", val);*/
|
||||
+ if(val >= arg_sym->nr_terms)
|
||||
+ return NULL;
|
||||
if(!arg_sym->terms[val]) {
|
||||
arg_sym->terms[val] = read_term(arg_sym, reader);
|
||||
if(!arg_sym->terms[val])
|
||||
***************
|
||||
*** 1396,1402 ****
|
||||
case AS_INT:
|
||||
/*{{{ Read an integer */
|
||||
|
||||
! if(readBits(&val, HEADER_BITS, reader) < 0)
|
||||
return NULL;
|
||||
|
||||
result = (ATerm)ATmakeInt((int)val);
|
||||
--- 1401,1407 ----
|
||||
case AS_INT:
|
||||
/*{{{ Read an integer */
|
||||
|
||||
! if(readBits(&val, INT_SIZE_IN_BAF, reader) < 0)
|
||||
return NULL;
|
||||
|
||||
result = (ATerm)ATmakeInt((int)val);
|
||||
***************
|
||||
*** 1494,1502 ****
|
||||
for(i=0; i<nr_unique_symbols; i++) {
|
||||
sym_read_entry *entry = &read_symbols[i];
|
||||
|
||||
! ATunprotectArray(entry->terms);
|
||||
! if(entry->terms)
|
||||
free(entry->terms);
|
||||
if(entry->nr_topsyms)
|
||||
free(entry->nr_topsyms);
|
||||
if(entry->sym_width)
|
||||
--- 1499,1508 ----
|
||||
for(i=0; i<nr_unique_symbols; i++) {
|
||||
sym_read_entry *entry = &read_symbols[i];
|
||||
|
||||
! if(entry->terms) {
|
||||
! ATunprotectArray(entry->terms);
|
||||
free(entry->terms);
|
||||
+ }
|
||||
if(entry->nr_topsyms)
|
||||
free(entry->nr_topsyms);
|
||||
if(entry->sym_width)
|
||||
Only in aterm-2.4.2/aterm: config.h.in
|
||||
diff -rc aterm-2.4.2-orig/aterm/encoding.h aterm-2.4.2/aterm/encoding.h
|
||||
*** aterm-2.4.2-orig/aterm/encoding.h 2004-06-01 10:29:02.000000000 +0200
|
||||
--- aterm-2.4.2/aterm/encoding.h 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 10,15 ****
|
||||
--- 10,17 ----
|
||||
{
|
||||
#endif/* __cplusplus */
|
||||
|
||||
+ #include "config.h"
|
||||
+
|
||||
/*
|
||||
|--------------------------------|
|
||||
|info|type |arity|quoted|mark|age|
|
||||
***************
|
||||
*** 31,37 ****
|
||||
#define SHIFT_REMOVE_MARK_AGE 3
|
||||
#define MASK_AGE_MARK (MASK_AGE|MASK_MARK)
|
||||
|
||||
! #if AT_64BIT
|
||||
#define SHIFT_LENGTH 34
|
||||
#define HEADER_BITS 64
|
||||
typedef unsigned long header_type;
|
||||
--- 33,39 ----
|
||||
#define SHIFT_REMOVE_MARK_AGE 3
|
||||
#define MASK_AGE_MARK (MASK_AGE|MASK_MARK)
|
||||
|
||||
! #ifdef AT_64BIT
|
||||
#define SHIFT_LENGTH 34
|
||||
#define HEADER_BITS 64
|
||||
typedef unsigned long header_type;
|
||||
***************
|
||||
*** 137,142 ****
|
||||
--- 139,150 ----
|
||||
#define AT_TABLE_SIZE(table_class) (1<<(table_class))
|
||||
#define AT_TABLE_MASK(table_class) (AT_TABLE_SIZE(table_class)-1)
|
||||
|
||||
+
|
||||
+ /* Integers in BAF are always exactly 32 bits. The size must be fixed so that
|
||||
+ * BAF terms can be exchanged between platforms. */
|
||||
+ #define INT_SIZE_IN_BAF 32
|
||||
+
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif/* __cplusplus */
|
||||
diff -rc aterm-2.4.2-orig/aterm/gc.c aterm-2.4.2/aterm/gc.c
|
||||
*** aterm-2.4.2-orig/aterm/gc.c 2004-06-01 10:29:02.000000000 +0200
|
||||
--- aterm-2.4.2/aterm/gc.c 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 154,166 ****
|
||||
}
|
||||
|
||||
#ifdef AT_64BIT
|
||||
! odd_term = *((ATerm *)((MachineWord)cur)+4);
|
||||
real_term = AT_isInsideValidTerm(odd_term);
|
||||
if (real_term != NULL) {
|
||||
AT_markTerm(odd_term);
|
||||
}
|
||||
|
||||
! odd_sym = *((AFun *)((MachineWord)cur)+4);
|
||||
if (AT_isValidSymbol(odd_sym)) {
|
||||
/*fprintf(stderr,"mark_memory: AT_markSymbol(%d)\n",odd_sym);*/
|
||||
AT_markSymbol(odd_sym);
|
||||
--- 154,166 ----
|
||||
}
|
||||
|
||||
#ifdef AT_64BIT
|
||||
! odd_term = *((ATerm *)(((MachineWord)cur)+4));
|
||||
real_term = AT_isInsideValidTerm(odd_term);
|
||||
if (real_term != NULL) {
|
||||
AT_markTerm(odd_term);
|
||||
}
|
||||
|
||||
! odd_sym = *((AFun *)(((MachineWord)cur)+4));
|
||||
if (AT_isValidSymbol(odd_sym)) {
|
||||
/*fprintf(stderr,"mark_memory: AT_markSymbol(%d)\n",odd_sym);*/
|
||||
AT_markSymbol(odd_sym);
|
||||
***************
|
||||
*** 198,210 ****
|
||||
}
|
||||
|
||||
#ifdef AT_64BIT
|
||||
! odd_term = *((ATerm *)((MachineWord)cur)+4);
|
||||
real_term = AT_isInsideValidTerm(odd_term);
|
||||
if (real_term != NULL) {
|
||||
AT_markTerm_young(odd_term);
|
||||
}
|
||||
|
||||
! odd_sym = *((AFun *)((MachineWord)cur)+4);
|
||||
if (AT_isValidSymbol(odd_sym)) {
|
||||
/*fprintf(stderr,"mark_memory_young: AT_markSymbol_young(%d)\n",odd_sym);*/
|
||||
AT_markSymbol_young(odd_sym);
|
||||
--- 198,210 ----
|
||||
}
|
||||
|
||||
#ifdef AT_64BIT
|
||||
! odd_term = *((ATerm *)(((MachineWord)cur)+4));
|
||||
real_term = AT_isInsideValidTerm(odd_term);
|
||||
if (real_term != NULL) {
|
||||
AT_markTerm_young(odd_term);
|
||||
}
|
||||
|
||||
! odd_sym = *((AFun *)(((MachineWord)cur)+4));
|
||||
if (AT_isValidSymbol(odd_sym)) {
|
||||
/*fprintf(stderr,"mark_memory_young: AT_markSymbol_young(%d)\n",odd_sym);*/
|
||||
AT_markSymbol_young(odd_sym);
|
||||
***************
|
||||
*** 225,235 ****
|
||||
ATerm *start, *stop;
|
||||
ProtEntry *prot;
|
||||
|
||||
- #ifdef AT_64BIT
|
||||
- ATerm oddTerm;
|
||||
- AFun oddSym;
|
||||
- #endif
|
||||
-
|
||||
#ifdef WIN32
|
||||
|
||||
unsigned int r_eax, r_ebx, r_ecx, r_edx, \
|
||||
--- 225,230 ----
|
||||
***************
|
||||
*** 287,293 ****
|
||||
/* Traverse possible register variables */
|
||||
sigsetjmp(env,0);
|
||||
|
||||
! start = (ATerm *)env;
|
||||
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
|
||||
mark_memory(start, stop);
|
||||
#endif
|
||||
--- 282,288 ----
|
||||
/* Traverse possible register variables */
|
||||
sigsetjmp(env,0);
|
||||
|
||||
! start = (ATerm *)env; /* !!! illegal aliasing */
|
||||
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
|
||||
mark_memory(start, stop);
|
||||
#endif
|
||||
***************
|
||||
*** 338,348 ****
|
||||
ATerm *start, *stop;
|
||||
ProtEntry *prot;
|
||||
|
||||
- #ifdef AT_64BIT
|
||||
- ATerm oddTerm;
|
||||
- AFun oddSym;
|
||||
- #endif
|
||||
-
|
||||
#ifdef WIN32
|
||||
|
||||
unsigned int r_eax, r_ebx, r_ecx, r_edx, \
|
||||
--- 333,338 ----
|
||||
***************
|
||||
*** 400,406 ****
|
||||
/* Traverse possible register variables */
|
||||
sigsetjmp(env,0);
|
||||
|
||||
! start = (ATerm *)env;
|
||||
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
|
||||
mark_memory_young(start, stop);
|
||||
#endif
|
||||
--- 390,396 ----
|
||||
/* Traverse possible register variables */
|
||||
sigsetjmp(env,0);
|
||||
|
||||
! start = (ATerm *)env; /* !!! illegal aliasing */
|
||||
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
|
||||
mark_memory_young(start, stop);
|
||||
#endif
|
||||
***************
|
||||
*** 1047,1053 ****
|
||||
/*fprintf(stderr,"minor_sweep_phase_young: ensure empty freelist[%d]\n",size);*/
|
||||
for(data = at_freelist[size] ; data ; data=data->next) {
|
||||
if(!EQUAL_HEADER(data->header,FREE_HEADER)) {
|
||||
! fprintf(stderr,"data = %x header = %x\n",(unsigned int)data,data->header);
|
||||
}
|
||||
assert(EQUAL_HEADER(data->header,FREE_HEADER));
|
||||
assert(ATgetType(data) == AT_FREE);
|
||||
--- 1037,1043 ----
|
||||
/*fprintf(stderr,"minor_sweep_phase_young: ensure empty freelist[%d]\n",size);*/
|
||||
for(data = at_freelist[size] ; data ; data=data->next) {
|
||||
if(!EQUAL_HEADER(data->header,FREE_HEADER)) {
|
||||
! fprintf(stderr,"data = %p header = %x\n",data,(unsigned int) data->header);
|
||||
}
|
||||
assert(EQUAL_HEADER(data->header,FREE_HEADER));
|
||||
assert(ATgetType(data) == AT_FREE);
|
||||
diff -rc aterm-2.4.2-orig/aterm/Makefile.am aterm-2.4.2/aterm/Makefile.am
|
||||
*** aterm-2.4.2-orig/aterm/Makefile.am 2005-08-03 11:45:19.000000000 +0200
|
||||
--- aterm-2.4.2/aterm/Makefile.am 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 37,43 ****
|
||||
aterm2.h \
|
||||
atypes.h \
|
||||
deprecated.h \
|
||||
! encoding.h
|
||||
|
||||
PRIVATE_INCL = \
|
||||
_afun.h \
|
||||
--- 37,44 ----
|
||||
aterm2.h \
|
||||
atypes.h \
|
||||
deprecated.h \
|
||||
! encoding.h \
|
||||
! config.h
|
||||
|
||||
PRIVATE_INCL = \
|
||||
_afun.h \
|
||||
diff -rc aterm-2.4.2-orig/aterm/md5.h aterm-2.4.2/aterm/md5.h
|
||||
*** aterm-2.4.2-orig/aterm/md5.h 2003-09-02 15:32:46.000000000 +0200
|
||||
--- aterm-2.4.2/aterm/md5.h 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 24,29 ****
|
||||
--- 24,31 ----
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
+ #include <stdint.h>
|
||||
+
|
||||
/* GLOBAL.H - RSAREF types and constants
|
||||
*/
|
||||
|
||||
***************
|
||||
*** 46,55 ****
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
! typedef unsigned short int UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
! typedef unsigned long int UINT4;
|
||||
|
||||
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||
--- 48,57 ----
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
! typedef uint16_t UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
! typedef uint32_t UINT4;
|
||||
|
||||
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||
diff -rc aterm-2.4.2-orig/aterm/memory.c aterm-2.4.2/aterm/memory.c
|
||||
*** aterm-2.4.2-orig/aterm/memory.c 2005-10-11 13:19:25.000000000 +0200
|
||||
--- aterm-2.4.2/aterm/memory.c 2006-09-22 13:39:16.000000000 +0200
|
||||
***************
|
||||
*** 96,102 ****
|
||||
#define HASHNUMBER4(t) hash_number(t,4)
|
||||
#define HASHINT(val) (tmp[0]=(MachineWord)(AT_INT<<SHIFT_TYPE),\
|
||||
tmp[1]=(MachineWord)0,\
|
||||
! tmp[2]=(MachineWord)val,\
|
||||
hash_number(tmp,3))
|
||||
|
||||
#else
|
||||
--- 96,102 ----
|
||||
#define HASHNUMBER4(t) hash_number(t,4)
|
||||
#define HASHINT(val) (tmp[0]=(MachineWord)(AT_INT<<SHIFT_TYPE),\
|
||||
tmp[1]=(MachineWord)0,\
|
||||
! tmp[2]=(MachineWord)((unsigned int) val),\
|
||||
hash_number(tmp,3))
|
||||
|
||||
#else
|
||||
***************
|
||||
*** 127,133 ****
|
||||
((MachineWord*)t)[2]),((MachineWord*)t)[3]))
|
||||
|
||||
#define HASHINT(val) \
|
||||
! FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
|
||||
|
||||
|
||||
#endif /* HASHPEM */
|
||||
--- 127,133 ----
|
||||
((MachineWord*)t)[2]),((MachineWord*)t)[3]))
|
||||
|
||||
#define HASHINT(val) \
|
||||
! FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), (unsigned int) val))
|
||||
|
||||
|
||||
#endif /* HASHPEM */
|
||||
***************
|
||||
*** 708,714 ****
|
||||
at_blocks[size] = newblock;
|
||||
top_at_blocks[size] = newblock->data;
|
||||
assert(at_blocks[size] != NULL);
|
||||
! assert(((int)top_at_blocks[size] % MAX(sizeof(double), sizeof(void *))) == 0);
|
||||
|
||||
/* [pem: Feb 14 02] TODO: fast allocation */
|
||||
assert(at_freelist[size] == NULL);
|
||||
--- 708,714 ----
|
||||
at_blocks[size] = newblock;
|
||||
top_at_blocks[size] = newblock->data;
|
||||
assert(at_blocks[size] != NULL);
|
||||
! assert(((long)top_at_blocks[size] % MAX(sizeof(double), sizeof(void *))) == 0);
|
||||
|
||||
/* [pem: Feb 14 02] TODO: fast allocation */
|
||||
assert(at_freelist[size] == NULL);
|
||||
***************
|
||||
*** 1009,1018 ****
|
||||
do {
|
||||
if(!cur) {
|
||||
/*printf("freeterm = %d\n",t);*/
|
||||
! fprintf(stderr,"### cannot find term %x in hashtable at pos %d header = %x\n", (unsigned int)t, hnr, t->header);
|
||||
!
|
||||
! ATabort("### cannot find term %n at %p in hashtable at pos %d"
|
||||
! ", header = %d\n", t, t, hnr, t->header);
|
||||
}
|
||||
if (cur == t) {
|
||||
if(prev)
|
||||
--- 1009,1016 ----
|
||||
do {
|
||||
if(!cur) {
|
||||
/*printf("freeterm = %d\n",t);*/
|
||||
! ATabort("### cannot find term %p in hashtable at pos %d"
|
||||
! ", header = %x\n", t, hnr, t->header);
|
||||
}
|
||||
if (cur == t) {
|
||||
if(prev)
|
||||
***************
|
||||
*** 1728,1733 ****
|
||||
--- 1726,1733 ----
|
||||
hashtable[hnr] = cur;
|
||||
}
|
||||
|
||||
+ assert((hnr & table_mask) == (hash_number(cur, TERM_SIZE_INT) & table_mask));
|
||||
+
|
||||
return (ATermInt)cur;
|
||||
}
|
||||
|
||||
diff -rc aterm-2.4.2-orig/aterm.m4 aterm-2.4.2/aterm.m4
|
||||
*** aterm-2.4.2-orig/aterm.m4 2005-08-03 11:45:19.000000000 +0200
|
||||
--- aterm-2.4.2/aterm.m4 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 8,15 ****
|
||||
[AS_HELP_STRING([--with-sharing],[create libraries that do term sharing @<:@yes@:>@])],
|
||||
[if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT([no])
|
||||
! AC_DEFINE([NO_SHARING])
|
||||
! AC_DEFINE([WITH_STATS])
|
||||
else
|
||||
if test "$withval" != "yes"; then
|
||||
AC_MSG_RESULT([unknown value specified for --with-sharing.])
|
||||
--- 8,15 ----
|
||||
[AS_HELP_STRING([--with-sharing],[create libraries that do term sharing @<:@yes@:>@])],
|
||||
[if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT([no])
|
||||
! AC_DEFINE([NO_SHARING], [], [Whether terms are shared.])
|
||||
! AC_DEFINE([WITH_STATS], [], [Whether to keep statistics.])
|
||||
else
|
||||
if test "$withval" != "yes"; then
|
||||
AC_MSG_RESULT([unknown value specified for --with-sharing.])
|
||||
***************
|
||||
*** 73,78 ****
|
||||
--- 73,102 ----
|
||||
AC_SUBST([OPTIMIZECFLAGS])
|
||||
])
|
||||
|
||||
+ # ATERM_64_BIT
|
||||
+ # ------------
|
||||
+ # Enable 64-bit mode if pointers are 8 bytes large.
|
||||
+ AC_DEFUN([ATERM_64_BIT], [
|
||||
+ AC_CHECK_SIZEOF(void *)
|
||||
+ AC_CHECK_SIZEOF(int)
|
||||
+ AC_CHECK_SIZEOF(long)
|
||||
+
|
||||
+ AC_MSG_CHECKING([what kind of platform this is])
|
||||
+
|
||||
+ AC_SUBST([AT_64BIT], [0])
|
||||
+ if test "$ac_cv_sizeof_void_p" = "8" -a "$ac_cv_sizeof_int" = "4" -a "$ac_cv_sizeof_long" = "8"; then
|
||||
+ AC_MSG_RESULT([LP64])
|
||||
+ AC_SUBST([AT_64BIT], [1])
|
||||
+ elif test "$ac_cv_sizeof_void_p" = "8" -a "$ac_cv_sizeof_int" = "8" -a "$ac_cv_sizeof_long" = "8"; then
|
||||
+ AC_MSG_RESULT([ILP64 - warning, untested])
|
||||
+ AC_SUBST([AT_64BIT], [1])
|
||||
+ elif test "$ac_cv_sizeof_void_p" = "4" -a "$ac_cv_sizeof_int" = "4" -a "$ac_cv_sizeof_long" = "4"; then
|
||||
+ AC_MSG_RESULT([32 bits])
|
||||
+ else
|
||||
+ AC_MSG_RESULT([something weird - warning, untested])
|
||||
+ fi
|
||||
+ ])
|
||||
+
|
||||
# XT_SVN_REVISION
|
||||
# ---------------
|
||||
AC_DEFUN([XT_SVN_REVISION],
|
||||
diff -rc aterm-2.4.2-orig/configure.ac aterm-2.4.2/configure.ac
|
||||
*** aterm-2.4.2-orig/configure.ac 2005-08-03 11:45:19.000000000 +0200
|
||||
--- aterm-2.4.2/configure.ac 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 30,35 ****
|
||||
--- 30,38 ----
|
||||
# Add a configuration option to allow users to control sharing.
|
||||
ATERM_WITH_SHARING
|
||||
|
||||
+ # Enable 64-bit mode if pointers are 8 bytes large.
|
||||
+ ATERM_64_BIT
|
||||
+
|
||||
CURDATE=`date`
|
||||
AC_SUBST([CURDATE])
|
||||
|
||||
***************
|
||||
*** 45,49 ****
|
||||
--- 48,53 ----
|
||||
doc/spec/Makefile
|
||||
aterm.spec
|
||||
aterm.pc
|
||||
+ aterm/config.h
|
||||
])
|
||||
AC_OUTPUT
|
||||
diff -rc aterm-2.4.2-orig/utils/dicttoc.c aterm-2.4.2/utils/dicttoc.c
|
||||
*** aterm-2.4.2-orig/utils/dicttoc.c 2003-10-07 13:57:40.000000000 +0200
|
||||
--- aterm-2.4.2/utils/dicttoc.c 2006-09-22 13:39:07.000000000 +0200
|
||||
***************
|
||||
*** 69,74 ****
|
||||
--- 69,75 ----
|
||||
fprintf(file, "#ifndef __%s_H\n", code_prefix);
|
||||
fprintf(file, "#define __%s_H\n\n", code_prefix);
|
||||
fprintf(file, "#include <aterm2.h>\n\n");
|
||||
+ fprintf(file, "#include <assert.h>\n\n");
|
||||
|
||||
while (!ATisEmpty(afuns)) {
|
||||
ATerm afun, alias, pair = ATgetFirst(afuns);
|
||||
***************
|
||||
*** 244,251 ****
|
||||
ATfprintf(file, "{\n");
|
||||
ATfprintf(file, " ATermList afuns, terms;\n\n");
|
||||
|
||||
! ATfprintf(file, " _%s = ATreadFromBinaryString(_%s_baf, _%s_LEN);\n\n",
|
||||
code_prefix, code_prefix, code_prefix);
|
||||
ATfprintf(file, " ATprotect(&_%s);\n\n", code_prefix);
|
||||
|
||||
ATfprintf(file, " afuns = (ATermList)ATelementAt((ATermList)_%s, 0);\n\n", code_prefix);
|
||||
--- 245,253 ----
|
||||
ATfprintf(file, "{\n");
|
||||
ATfprintf(file, " ATermList afuns, terms;\n\n");
|
||||
|
||||
! ATfprintf(file, " _%s = ATreadFromBinaryString(_%s_baf, _%s_LEN);\n",
|
||||
code_prefix, code_prefix, code_prefix);
|
||||
+ ATfprintf(file, " assert(_%s);\n\n", code_prefix);
|
||||
ATfprintf(file, " ATprotect(&_%s);\n\n", code_prefix);
|
||||
|
||||
ATfprintf(file, " afuns = (ATermList)ATelementAt((ATermList)_%s, 0);\n\n", code_prefix);
|
||||
224
externals/aterm-aliasing.patch
vendored
224
externals/aterm-aliasing.patch
vendored
@@ -1,224 +0,0 @@
|
||||
diff -rc aterm-1142707243.10633/aterm/aterm.c aterm/aterm/aterm.c
|
||||
*** aterm-1142707243.10633/aterm/aterm.c 2006-02-08 11:35:28.000000000 +0100
|
||||
--- aterm/aterm/aterm.c 2006-04-25 17:10:52.000000000 +0200
|
||||
***************
|
||||
*** 193,198 ****
|
||||
--- 193,199 ----
|
||||
/* that have char == 2 bytes, and sizeof(header_type) == 2 */
|
||||
assert(sizeof(header_type) == sizeof(ATerm *));
|
||||
assert(sizeof(header_type) >= 4);
|
||||
+ assert(sizeof(ATerm) == sizeof(MachineWord));
|
||||
|
||||
/*}}} */
|
||||
/*{{{ Initialize buffer */
|
||||
diff -rc aterm-1142707243.10633/aterm/memory.c aterm/aterm/memory.c
|
||||
*** aterm-1142707243.10633/aterm/memory.c 2006-03-09 15:02:56.000000000 +0100
|
||||
--- aterm/aterm/memory.c 2006-04-25 18:22:00.000000000 +0200
|
||||
***************
|
||||
*** 119,130 ****
|
||||
hash_number(tmp,3))
|
||||
*/
|
||||
|
||||
#define HASHNUMBER3(t)\
|
||||
! FINISH(COMBINE(START(((MachineWord*)t)[0]), ((MachineWord*)t)[2]))
|
||||
|
||||
#define HASHNUMBER4(t)\
|
||||
! FINISH(COMBINE(COMBINE(START(((MachineWord*)t)[0]), \
|
||||
! ((MachineWord*)t)[2]),((MachineWord*)t)[3]))
|
||||
|
||||
#define HASHINT(val) \
|
||||
FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
|
||||
--- 119,171 ----
|
||||
hash_number(tmp,3))
|
||||
*/
|
||||
|
||||
+ /* The ATerm library use some heavy aliasing. For instance, the
|
||||
+ various ATermXXX structures are referenced through MachineWord
|
||||
+ arrays. This is not generally allowed by the C standard --- see
|
||||
+ C99, section 6.5, clause 7. In particular, this means that you
|
||||
+ cannot assign something through an ATermXXX pointer, e.g.,
|
||||
+
|
||||
+ protoAppl->header = header;
|
||||
+
|
||||
+ and then read it through a MachineWord*, e.g.,
|
||||
+
|
||||
+ hnr = hash_number((ATerm) protoAppl, 2);
|
||||
+
|
||||
+ (hash_number walks over the term by casting it to a MachineWord*).
|
||||
+
|
||||
+ However, the same clause of the C standard also specifies that you
|
||||
+ *can* read the memory location through a union type that contains
|
||||
+ both the original type (e.g. ATermAppl) and the type used to read
|
||||
+ the memory location (e.g. MachineWord). That's what we do
|
||||
+ below: we have a union of all the types that occur in the various
|
||||
+ ATerm types. We then read the "w" element of the union. The
|
||||
+ compiler is not allowed to assume absence of aliasing with the
|
||||
+ other types in the union.
|
||||
+
|
||||
+ A better solution would be to hash the term through a character
|
||||
+ pointer (since *any* memory location can be legally read as a
|
||||
+ character), but I'm too lazy right now. Performance might also
|
||||
+ suffer if we do that. */
|
||||
+
|
||||
+ typedef union
|
||||
+ {
|
||||
+ MachineWord w;
|
||||
+ header_type header;
|
||||
+ ATerm term;
|
||||
+ ATermList list;
|
||||
+ int i;
|
||||
+ double d;
|
||||
+ void* p;
|
||||
+ } Aliaser;
|
||||
+
|
||||
+ #define GET_WORD(t, n) (((Aliaser*) (((MachineWord*) t) + n))->w)
|
||||
+
|
||||
#define HASHNUMBER3(t)\
|
||||
! FINISH(COMBINE(START(GET_WORD(t, 0)), GET_WORD(t, 2)))
|
||||
|
||||
#define HASHNUMBER4(t)\
|
||||
! FINISH(COMBINE(COMBINE(START(GET_WORD(t, 0)), \
|
||||
! GET_WORD(t, 2)), GET_WORD(t, 3)))
|
||||
|
||||
#define HASHINT(val) \
|
||||
FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
|
||||
***************
|
||||
*** 132,144 ****
|
||||
|
||||
#endif /* HASHPEM */
|
||||
|
||||
! #define PROTO_APPL_ARGS ((ATerm *) (protoTerm + ARG_OFFSET))
|
||||
|
||||
#define SET_PROTO_APPL_ARG(i, a) \
|
||||
! (PROTO_APPL_ARGS[(i)] = (a))
|
||||
|
||||
#define GET_PROTO_APPL_ARG(i) \
|
||||
! (PROTO_APPL_ARGS[(i)])
|
||||
|
||||
#define CHECK_TERM(t) \
|
||||
assert((t) != NULL \
|
||||
--- 173,185 ----
|
||||
|
||||
#endif /* HASHPEM */
|
||||
|
||||
! #define PROTO_APPL_ARGS (protoTerm + ARG_OFFSET)
|
||||
|
||||
#define SET_PROTO_APPL_ARG(i, a) \
|
||||
! (PROTO_APPL_ARGS[(i)] = (MachineWord) (a))
|
||||
|
||||
#define GET_PROTO_APPL_ARG(i) \
|
||||
! ((ATerm) PROTO_APPL_ARGS[(i)])
|
||||
|
||||
#define CHECK_TERM(t) \
|
||||
assert((t) != NULL \
|
||||
***************
|
||||
*** 323,336 ****
|
||||
#else
|
||||
static HashNumber hash_number(ATerm t, int size)
|
||||
{
|
||||
- MachineWord *words = (MachineWord *) t;
|
||||
int i;
|
||||
HashNumber hnr;
|
||||
|
||||
! hnr = START(HIDE_AGE_MARK(words[0]));
|
||||
|
||||
for (i=2; i<size; i++) {
|
||||
! hnr = COMBINE(hnr, words[i]);
|
||||
}
|
||||
|
||||
return FINISH(hnr);
|
||||
--- 364,376 ----
|
||||
#else
|
||||
static HashNumber hash_number(ATerm t, int size)
|
||||
{
|
||||
int i;
|
||||
HashNumber hnr;
|
||||
|
||||
! hnr = START(HIDE_AGE_MARK(GET_WORD(t, 0)));
|
||||
|
||||
for (i=2; i<size; i++) {
|
||||
! hnr = COMBINE(hnr, GET_WORD(t, i));
|
||||
}
|
||||
|
||||
return FINISH(hnr);
|
||||
***************
|
||||
*** 338,351 ****
|
||||
|
||||
static HashNumber hash_number_anno(ATerm t, int size, ATerm anno)
|
||||
{
|
||||
- MachineWord *words = (MachineWord *) t;
|
||||
int i;
|
||||
HashNumber hnr;
|
||||
|
||||
! hnr = START(HIDE_AGE_MARK(words[0]));
|
||||
|
||||
for (i=2; i<size; i++) {
|
||||
! hnr = COMBINE(hnr, words[i]);
|
||||
}
|
||||
hnr = COMBINE(hnr, (MachineWord)anno);
|
||||
|
||||
--- 378,390 ----
|
||||
|
||||
static HashNumber hash_number_anno(ATerm t, int size, ATerm anno)
|
||||
{
|
||||
int i;
|
||||
HashNumber hnr;
|
||||
|
||||
! hnr = START(HIDE_AGE_MARK(GET_WORD(t, 0)));
|
||||
|
||||
for (i=2; i<size; i++) {
|
||||
! hnr = COMBINE(hnr, GET_WORD(t, i));
|
||||
}
|
||||
hnr = COMBINE(hnr, (MachineWord)anno);
|
||||
|
||||
***************
|
||||
*** 1639,1645 ****
|
||||
protoAppl->header = header;
|
||||
CHECK_HEADER(protoAppl->header);
|
||||
|
||||
! if (args != PROTO_APPL_ARGS) {
|
||||
for (i=0; i<arity; i++) {
|
||||
CHECK_TERM(args[i]);
|
||||
SET_PROTO_APPL_ARG(i, args[i]);
|
||||
--- 1678,1684 ----
|
||||
protoAppl->header = header;
|
||||
CHECK_HEADER(protoAppl->header);
|
||||
|
||||
! if (args != (ATerm *) PROTO_APPL_ARGS) {
|
||||
for (i=0; i<arity; i++) {
|
||||
CHECK_TERM(args[i]);
|
||||
SET_PROTO_APPL_ARG(i, args[i]);
|
||||
***************
|
||||
*** 1680,1686 ****
|
||||
hashtable[hnr] = cur;
|
||||
}
|
||||
|
||||
! if (args != PROTO_APPL_ARGS) {
|
||||
for (i=0; i<arity; i++) {
|
||||
protected_buffer[i] = NULL;
|
||||
}
|
||||
--- 1719,1725 ----
|
||||
hashtable[hnr] = cur;
|
||||
}
|
||||
|
||||
! if (args != (ATerm *) PROTO_APPL_ARGS) {
|
||||
for (i=0; i<arity; i++) {
|
||||
protected_buffer[i] = NULL;
|
||||
}
|
||||
***************
|
||||
*** 2144,2150 ****
|
||||
}
|
||||
SET_PROTO_APPL_ARG(n, arg);
|
||||
|
||||
! result = ATmakeApplArray(sym, PROTO_APPL_ARGS);
|
||||
annos = AT_getAnnotations((ATerm)appl);
|
||||
if (annos != NULL) {
|
||||
result = (ATermAppl)AT_setAnnotations((ATerm)result, annos);
|
||||
--- 2183,2189 ----
|
||||
}
|
||||
SET_PROTO_APPL_ARG(n, arg);
|
||||
|
||||
! result = ATmakeApplArray(sym, (ATerm *) PROTO_APPL_ARGS);
|
||||
annos = AT_getAnnotations((ATerm)appl);
|
||||
if (annos != NULL) {
|
||||
result = (ATermAppl)AT_setAnnotations((ATerm)result, annos);
|
||||
17
externals/bdb-cygwin.patch
vendored
17
externals/bdb-cygwin.patch
vendored
@@ -1,21 +1,22 @@
|
||||
diff -rc db-4.4.20.NC-old/os/os_flock.c db-4.4.20.NC/os/os_flock.c
|
||||
*** db-4.4.20.NC-old/os/os_flock.c Mon Jun 20 16:59:01 2005
|
||||
--- db-4.4.20.NC/os/os_flock.c Wed Jun 7 17:01:49 2006
|
||||
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
|
||||
***************
|
||||
*** 36,41 ****
|
||||
--- 36,50 ----
|
||||
*** 30,35 ****
|
||||
--- 30,44 ----
|
||||
|
||||
DB_ASSERT(F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
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(offset < (off_t) 1 << 62);
|
||||
+ DB_ASSERT(dbenv, offset < (off_t) 1 << 62);
|
||||
+ offset += (off_t) 1 << 62;
|
||||
+ #endif
|
||||
+
|
||||
#ifdef HAVE_FCNTL
|
||||
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~
|
||||
|
||||
67
install_full.sh
Executable file
67
install_full.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
make clean # comment this out when needed !!!
|
||||
|
||||
export nixstatepath=/nixstate2/nix
|
||||
export ACLOCAL_PATH=/home/wouterdb/.nix-profile/share/aclocal
|
||||
|
||||
if [ "$1" = "full" ]; then
|
||||
nix-env-all-pkgs.sh -i gcc
|
||||
nix-env-all-pkgs.sh -i gnum4
|
||||
nix-env-all-pkgs.sh -i autoconf
|
||||
nix-env-all-pkgs.sh -i automake
|
||||
nix-env-all-pkgs.sh -i gnused
|
||||
nix-env-all-pkgs.sh -i db4
|
||||
nix-env-all-pkgs.sh -i aterm
|
||||
nix-env-all-pkgs.sh -i bzip2
|
||||
nix-env-all-pkgs.sh -i flex
|
||||
nix-env-all-pkgs.sh -i bsdiff
|
||||
nix-env-all-pkgs.sh -i libtool
|
||||
nix-env-all-pkgs.sh -i docbook5
|
||||
nix-env-all-pkgs.sh -i docbook5-xsl
|
||||
nix-env-all-pkgs.sh -i bison
|
||||
nix-env-all-pkgs.sh -i gdb #optional for debugging
|
||||
nix-env-all-pkgs.sh -i gnupatch
|
||||
nix-env-all-pkgs.sh -i gnumake
|
||||
nix-env-all-pkgs.sh -i ext3cow-tools
|
||||
nix-env-all-pkgs.sh -i e3cfsprogs
|
||||
nix-env-all-pkgs.sh -i rsync
|
||||
fi
|
||||
|
||||
if [ "$1" = "full" ] || [ "$1" = "auto" ]; then
|
||||
export AUTOCONF=autoconf
|
||||
export AUTOHEADER=autoheader
|
||||
export AUTOMAKE=automake
|
||||
autoconf
|
||||
autoreconf -f
|
||||
aclocal
|
||||
autoheader
|
||||
automake
|
||||
fi
|
||||
|
||||
./bootstrap.sh
|
||||
|
||||
./configure --with-aterm=$HOME/.nix-profile \
|
||||
--with-bzip2=$HOME/.nix-profile \
|
||||
--with-bdb=$HOME/.nix-profile \
|
||||
--with-docbook-xsl=$HOME/.nix-profile \
|
||||
--with-docbook-rng=/home/wouterdb/.nix-profile/xml/rng/docbook \
|
||||
--with-docbook-xsl=/home/wouterdb/.nix-profile/xml/xsl/docbook \
|
||||
--prefix=$nixstatepath \
|
||||
--with-store-dir=/nix/store \
|
||||
--with-store-state-dir=/nix/state \
|
||||
--with-ext3cow-header=/nix/store/2sm0h2xd1zsm5had53q1pvzmnsn8fy8k-linux-2.6.21/lib/modules/2.6.21-ck1-default/build/include/linux/ext3cow_fs.h \
|
||||
--localstatedir=/nix/var
|
||||
|
||||
#Options from the nix expr
|
||||
#--disable-init-state
|
||||
#--with-store-dir=/nix/store
|
||||
#--localstatedir=/nix/var
|
||||
#--with-aterm=/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes
|
||||
#--with-bdb=/nix/store/4yv4j1cd7i5j3mhs5wpc1kzlz1cj8n82-db4-4.5.20
|
||||
#--with-bzip2=/nix/store/dh0mdgkvhv3pwrf8zp58phpzn9rcm49r-bzip2-1.0.3
|
||||
#--disable-init-state
|
||||
|
||||
|
||||
echo "New state nix version by wouter ..." > doc/manual/NEWS.txt
|
||||
make
|
||||
16
install_install_d.sh
Executable file
16
install_install_d.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
if [ $(whoami) = "root" ]
|
||||
then
|
||||
|
||||
su - wouterdb -c "cd /home/wouterdb/dev/nix-state/; make"
|
||||
make install
|
||||
chown -R wouterdb.wouterdb /nixstate2/nix/
|
||||
|
||||
./restartDaemon.sh
|
||||
|
||||
else
|
||||
echo "You must be ROOT to run this script."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
5
install_make.sh
Executable file
5
install_make.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
make
|
||||
|
||||
|
||||
36
mergeTrunkBackIn.sh
Executable file
36
mergeTrunkBackIn.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
svn merge -r 10855:10943 https://svn.cs.uu.nl:12443/repos/trace/nix/trunk
|
||||
|
||||
#already done:
|
||||
# 8628
|
||||
# 8632
|
||||
# 8634
|
||||
# 8636
|
||||
# 8655
|
||||
# 8691
|
||||
# 8698
|
||||
# 8711
|
||||
# 8864
|
||||
# 9063
|
||||
# 9105
|
||||
# 9207
|
||||
# 9217
|
||||
# 9332
|
||||
# 9429
|
||||
# 9433
|
||||
# 9435
|
||||
# 9437
|
||||
# 9439
|
||||
# 9445
|
||||
# 9476
|
||||
# 9506
|
||||
# 9536
|
||||
# 9549
|
||||
# 9561
|
||||
# 9584
|
||||
# 9751
|
||||
# 10133
|
||||
# 10154
|
||||
# 10531
|
||||
# 10692
|
||||
# 10855
|
||||
# 10943
|
||||
35
misc/vim/syntax/nix.vim
Normal file
35
misc/vim/syntax/nix.vim
Normal file
@@ -0,0 +1,35 @@
|
||||
" 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 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 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
|
||||
114
nix.conf.example
114
nix.conf.example
@@ -78,35 +78,99 @@
|
||||
#build-max-jobs = 1
|
||||
|
||||
|
||||
### Option `build-allow-root'
|
||||
### Option `build-max-silent-time'
|
||||
#
|
||||
# This option controls Nix's behaviour when it is invoked under the
|
||||
# `root' user (or setuid-root). If `true' (default), builds are
|
||||
# performed under the `root' user. If `false', builds are performed
|
||||
# under one of the users listed in the `build-users' option (see
|
||||
# below).
|
||||
#build-allow-root = true
|
||||
|
||||
|
||||
### Option `build-users'
|
||||
# This option defines the maximum number of seconds that a builder can
|
||||
# go without producing any data on standard output or standard error.
|
||||
# This is useful (for instance in a automated build system) to catch
|
||||
# builds that are stuck in an infinite loop, or to catch remote builds
|
||||
# that are hanging due to network problems. It can be overriden using
|
||||
# the `--max-silent-time' command line switch.
|
||||
#
|
||||
# This option is only applicable if `build-allow-root' is `false' and
|
||||
# Nix is invoked under the `root' user (or setuid-root). It contains
|
||||
# a list of user names under which Nix can execute builds. Builds
|
||||
# cannot be performed by root since that would allow users to take
|
||||
# over the system 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.
|
||||
#
|
||||
# Thus this list should contain a number of `special' user accounts
|
||||
# created specifically for Nix, e.g., `nix-builder-1',
|
||||
# `nix-builder-2', and so on. The more users the better, since at
|
||||
# most a number of builds equal to the number of build users can be
|
||||
# started.
|
||||
# The value 0 means that there is no timeout. This is also the
|
||||
# default.
|
||||
#
|
||||
# Example:
|
||||
# build-users = nix-builder-1 nix-builder-2 nix-builder-3
|
||||
#build-users =
|
||||
# build-max-silent-time = 600 # = 10 minutes
|
||||
#build-max-silent-time = 0
|
||||
|
||||
|
||||
### Option `build-users-group'
|
||||
#
|
||||
# This options specifies the Unix group containing the Nix build user
|
||||
# accounts. In multi-user Nix installations, builds should not
|
||||
# be performed by the Nix account since that would allow users to
|
||||
# arbitrarily modify the Nix store and database by supplying specially
|
||||
# crafted builders; and they cannot be performed by the calling user
|
||||
# since that would allow him/her to influence the build result.
|
||||
#
|
||||
# Therefore, if this option is non-empty and specifies a valid group,
|
||||
# builds will be performed under the user accounts that are a member
|
||||
# of the group specified here (as listed in /etc/group). Those user
|
||||
# accounts should not be used for any other purpose!
|
||||
#
|
||||
# Nix will never run two builds under the same user account at the
|
||||
# same time. This is to prevent an obvious security hole: a malicious
|
||||
# user writing a Nix expression that modifies the build result of a
|
||||
# legitimate Nix expression being built by another user. Therefore it
|
||||
# is good to have as many Nix build user accounts as you can spare.
|
||||
# (Remember: uids are cheap.)
|
||||
#
|
||||
# The build users should have permission to create files in the Nix
|
||||
# store, but not delete them. Therefore, /nix/store should be owned
|
||||
# by the Nix account, its group should be the group specified here,
|
||||
# and its mode should be 1775.
|
||||
#
|
||||
# If the build users group is empty, builds will be performed under
|
||||
# the uid of the Nix process (that is, the uid of the caller if
|
||||
# $NIX_REMOTE is empty, the uid under which the Nix daemon runs if
|
||||
# $NIX_REMOTE is `daemon', or the uid that owns the setuid nix-worker
|
||||
# program if $NIX_REMOTE is `slave'). Obviously, this should not be
|
||||
# used in multi-user settings with untrusted users.
|
||||
#
|
||||
# The default is empty.
|
||||
#
|
||||
# Example:
|
||||
# build-users-group = nix-builders
|
||||
#build-users-group =
|
||||
|
||||
|
||||
### Option `build-use-chroot'
|
||||
#
|
||||
# If set to `true', builds will be performed in a chroot environment,
|
||||
# i.e., the build will be isolated from the normal file system
|
||||
# hierarchy and will only see the Nix store, the temporary build
|
||||
# directory, and the directories configured with the
|
||||
# `build-chroot-dirs' option (such as /proc and /dev). This is useful
|
||||
# to prevent undeclared dependencies on files in directories such as
|
||||
# /usr/bin.
|
||||
#
|
||||
# The use of a chroot requires that Nix is run as root (but you can
|
||||
# still use the "build users" feature to perform builds under
|
||||
# different users than root). Currently, chroot builds only work on
|
||||
# Linux because Nix uses "bind mounts" to make the Nix store and other
|
||||
# directories available inside the chroot.
|
||||
#
|
||||
# The default is `false'.
|
||||
#
|
||||
# Example:
|
||||
# build-use-chroot = true
|
||||
#build-use-chroot = false
|
||||
|
||||
|
||||
### Option `build-chroot-dirs'
|
||||
#
|
||||
# When builds are performed in a chroot environment, Nix will mount
|
||||
# (using `mount --bind' on Linux) some directories from the normal
|
||||
# file system hierarchy inside the chroot. These are the Nix store,
|
||||
# the temporary build directory (usually /tmp/nix-<pid>-<number>) and
|
||||
# the directories listed here. The default is "/dev /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 /proc
|
||||
|
||||
|
||||
### Option `system'
|
||||
|
||||
10
nix.spec.in
10
nix.spec.in
@@ -13,7 +13,7 @@ Version: @version@
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: Software Deployment
|
||||
URL: http://www.cs.uu.nl/groups/ST/Trace/Nix
|
||||
URL: http://nix.cs.uu.nl/
|
||||
Source0: %{name}-@version@.tar.bz2
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
||||
%define _prefix /nix
|
||||
@@ -26,7 +26,12 @@ Provides: perl(readmanifest)
|
||||
|
||||
%description
|
||||
|
||||
Nix is a system for software deployment.
|
||||
Nix is a purely functional package manager. It allows multiple
|
||||
versions of a package to be installed side-by-side, ensures that
|
||||
dependency specifications are complete, supports atomic upgrades and
|
||||
rollbacks, allows non-root users to install software, and has many
|
||||
other features. It is the basis of the NixOS Linux distribution, but
|
||||
it can be used equally well under other Unix systems.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
@@ -73,7 +78,6 @@ fi
|
||||
%{_prefix}/include
|
||||
%{_prefix}/var
|
||||
%{_prefix}/share
|
||||
%{_prefix}/man
|
||||
%{_prefix}/store
|
||||
%config
|
||||
%{_prefix}/etc
|
||||
|
||||
9
restartDaemon.sh
Executable file
9
restartDaemon.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#! /bin/sh
|
||||
|
||||
initctl stop nix-daemon
|
||||
killproc.sh nix-worker
|
||||
sleep 2
|
||||
|
||||
#/nixstate2/nix/bin/nix-worker --daemon > /dev/null 2>&1 &
|
||||
/nixstate2/nix/bin/nix-worker --daemon
|
||||
#gdb --args /nixstate2/nix/bin/nix-worker --daemon
|
||||
@@ -1,9 +1,11 @@
|
||||
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-pack-closure nix-unpack-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
|
||||
|
||||
nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl
|
||||
|
||||
@@ -15,6 +17,8 @@ install-exec-local: readmanifest.pm download-using-manifests.pl find-runtime-roo
|
||||
$(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix
|
||||
$(INSTALL_PROGRAM) download-using-manifests.pl $(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)$(sysconfdir)/nix
|
||||
|
||||
include ../substitute.mk
|
||||
@@ -29,4 +33,7 @@ EXTRA_DIST = nix-collect-garbage.in \
|
||||
download-using-manifests.pl.in \
|
||||
generate-patches.pl.in \
|
||||
nix-pack-closure.in nix-unpack-closure.in \
|
||||
find-runtime-roots.pl.in
|
||||
nix-copy-closure.in \
|
||||
find-runtime-roots.pl.in \
|
||||
build-remote.pl.in \
|
||||
nix-reduce-build.in
|
||||
|
||||
208
scripts/build-remote.pl.in
Executable file
208
scripts/build-remote.pl.in
Executable file
@@ -0,0 +1,208 @@
|
||||
#! @perl@ -w
|
||||
|
||||
use strict;
|
||||
use Fcntl ':flock';
|
||||
use English '-no_match_vars';
|
||||
|
||||
# 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.
|
||||
|
||||
my $loadIncreased = 0;
|
||||
|
||||
my $amWilling = shift @ARGV;
|
||||
my $localSystem = shift @ARGV;
|
||||
my $neededSystem = shift @ARGV;
|
||||
my $drvPath = shift @ARGV;
|
||||
|
||||
sub sendReply {
|
||||
my $reply = shift;
|
||||
open OUT, ">&3" or die;
|
||||
print OUT "$reply\n";
|
||||
close OUT;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
# Decline if the local system can do the build.
|
||||
decline if $amWilling && ($localSystem eq $neededSystem);
|
||||
|
||||
|
||||
# Otherwise find a willing remote machine.
|
||||
my %machines;
|
||||
my %systemTypes;
|
||||
my %sshKeys;
|
||||
my %maxJobs;
|
||||
my %curJobs;
|
||||
|
||||
|
||||
# Read the list of machines.
|
||||
open CONF, "< $conf" or die;
|
||||
|
||||
while (<CONF>) {
|
||||
chomp;
|
||||
s/\#.*$//g;
|
||||
next if /^\s*$/;
|
||||
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s*$/ or die;
|
||||
$machines{$1} = "";
|
||||
$systemTypes{$1} = $2;
|
||||
$sshKeys{$1} = $3;
|
||||
$maxJobs{$1} = $4;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
# Find a suitable system.
|
||||
my $rightType = 0;
|
||||
my $machine;
|
||||
LOOP: foreach my $cur (keys %machines) {
|
||||
if ($neededSystem eq $systemTypes{$cur}) {
|
||||
$rightType = 1;
|
||||
|
||||
# We have a machine of the right type. Try to get a lock on
|
||||
# one of the machine's lock files.
|
||||
my $slot = 0;
|
||||
while ($slot < $maxJobs{$cur}) {
|
||||
my $slotLock = "$currentLoad/$cur-$slot";
|
||||
open SLOTLOCK, ">>$slotLock" or die;
|
||||
if (flock(SLOTLOCK, LOCK_EX | LOCK_NB)) {
|
||||
$machine = $cur;
|
||||
last LOOP;
|
||||
}
|
||||
close SLOTLOCK;
|
||||
$slot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close MAINLOCK;
|
||||
|
||||
|
||||
# Didn't find one?
|
||||
if (!defined $machine) {
|
||||
if ($rightType) {
|
||||
sendReply "postpone";
|
||||
exit 0;
|
||||
} else {
|
||||
decline;
|
||||
}
|
||||
}
|
||||
|
||||
# Yes we did, accept.
|
||||
sendReply "accept";
|
||||
open IN, "<&4" or die;
|
||||
my $x = <IN>;
|
||||
chomp $x;
|
||||
#print "got $x\n";
|
||||
close IN;
|
||||
|
||||
if ($x ne "okay") {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
# Do the actual job.
|
||||
print "BUILDING REMOTE: $drvPath on $machine\n";
|
||||
|
||||
# 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_PASSWORD_FILE="} = "";
|
||||
$ENV{"SSH_ASKPASS="} = "";
|
||||
|
||||
my $sshOpts = "-i $sshKeys{$machine} -x";
|
||||
|
||||
# Hack to support Cygwin: if we login without a password, we don't
|
||||
# have exactly the same right as when we do. This causes the
|
||||
# Microsoft C compiler to fail with certain flags:
|
||||
#
|
||||
# http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99676
|
||||
#
|
||||
# So as a workaround, we pass a verbatim password. ssh tries to makes
|
||||
# this very hard; the trick is to make it call SSH_ASKPASS to get the
|
||||
# password. (It only calls this command when there is no controlling
|
||||
# terminal, but Nix ensures that is is the case. When doing this
|
||||
# manually, use setsid(1).)
|
||||
if ($sshKeys{$machine} =~ /^password:/) {
|
||||
my $passwordFile = $sshKeys{$machine};
|
||||
$passwordFile =~ s/^password://;
|
||||
$sshOpts = "ssh -x";
|
||||
$ENV{"SSH_PASSWORD_FILE"} = $passwordFile;
|
||||
$ENV{"SSH_ASKPASS"} = "/tmp/writepass";
|
||||
|
||||
open WRITEPASS, ">/tmp/writepass" or die;
|
||||
print WRITEPASS "#! /bin/sh\ncat \"\$SSH_PASSWORD_FILE\"";
|
||||
close WRITEPASS;
|
||||
chmod 0755, "/tmp/writepass" or die;
|
||||
}
|
||||
|
||||
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\" nix-copy-closure $machine $maybeSign $drvPath $inputs") == 0
|
||||
or die "cannot copy inputs to $machine: $?";
|
||||
|
||||
print "BUILDING...\n";
|
||||
|
||||
system("ssh $sshOpts $machine 'nix-store -rvvK $drvPath'") == 0
|
||||
or die "remote build on $machine failed: $?";
|
||||
|
||||
print "REMOTE BUILD DONE: $drvPath on $machine\n";
|
||||
|
||||
foreach my $output (split '\n', $outputs) {
|
||||
my $maybeSignRemote = "";
|
||||
$maybeSignRemote = "--sign" if $UID != 0;
|
||||
|
||||
system("ssh $sshOpts $machine 'nix-store --export $maybeSignRemote $output' > dump") == 0
|
||||
or die "cannot copy $output from $machine: $?";
|
||||
|
||||
# This doesn't work yet, since the caller has a lock on the output
|
||||
# path. We should move towards lock-free invocation of build
|
||||
# hooks and substitutes.
|
||||
#system("nix-store --import < dump") == 0
|
||||
# or die "cannot import $output: $?";
|
||||
|
||||
# Hack: skip the first 8 bytes (the nix-store --export next
|
||||
# archive marker). The archive follows.
|
||||
system("(dd bs=1 count=8 of=/dev/null && cat) < dump | nix-store --restore $output") == 0
|
||||
or die "cannot restore $output: $?";
|
||||
}
|
||||
@@ -10,8 +10,6 @@ my $logFile = "@localstatedir@/log/nix/downloads";
|
||||
|
||||
open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
|
||||
|
||||
delete $ENV{"NIX_ROOT"};
|
||||
|
||||
# Create a temporary directory.
|
||||
my $tmpDir = tempdir("nix-download.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
@@ -21,12 +19,79 @@ 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;
|
||||
my %localPaths;
|
||||
my %patches;
|
||||
|
||||
for my $manifest (glob "$manifestDir/*.nixmanifest") {
|
||||
# print STDERR "reading $manifest\n";
|
||||
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
|
||||
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Check the arguments.
|
||||
die unless scalar @ARGV == 1;
|
||||
my $targetPath = $ARGV[0];
|
||||
# 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;
|
||||
}
|
||||
|
||||
elsif ($ARGV[0] eq "--query-info") {
|
||||
shift @ARGV;
|
||||
foreach my $storePath (@ARGV) {
|
||||
my $info;
|
||||
if (defined $narFiles{$storePath}) {
|
||||
$info = @{$narFiles{$storePath}}[0];
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
my $isStateStorePath = `@bindir@/nix-state --is-state-store-path-download-using-manifests $storePath`;
|
||||
if($isStateStorePath ne "true" && $isStateStorePath ne "false"){
|
||||
die "The call for isStateStorePath must return true or false.....";
|
||||
}
|
||||
|
||||
if($isStateStorePath eq "true"){
|
||||
my @stateReferences = split " ", $info->{stateReferences};
|
||||
my $scount = scalar @stateReferences;
|
||||
print "$scount\n";
|
||||
foreach my $stateReference (@stateReferences) {
|
||||
print "$stateReference\n";
|
||||
}
|
||||
|
||||
print "$info->{revision}\n";
|
||||
}
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
elsif ($ARGV[0] ne "--substitute") {
|
||||
die "syntax: $0 [--query-paths | --query-info PATHS... | --substitute PATH]\n";
|
||||
}
|
||||
|
||||
|
||||
die unless scalar @ARGV == 2;
|
||||
my $targetPath = $ARGV[1];
|
||||
|
||||
|
||||
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
|
||||
print LOGFILE "$$ get $targetPath $date\n";
|
||||
@@ -34,16 +99,15 @@ print LOGFILE "$$ get $targetPath $date\n";
|
||||
print "\n*** Trying to download/patch `$targetPath'\n";
|
||||
|
||||
|
||||
# Load all manifests.
|
||||
my %narFiles;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
for my $manifest (glob "$manifestDir/*.nixmanifest") {
|
||||
# print STDERR "reading $manifest\n";
|
||||
if (readManifest($manifest, \%narFiles, \%patches, \%successors) < 3) {
|
||||
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
|
||||
exit 1;
|
||||
# If we can copy from a local path, do that.
|
||||
my $localPathList = $localPaths{$targetPath};
|
||||
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
|
||||
or die "cannot copy `$sourcePath' to `$targetPath'";
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,3 +56,20 @@ sub lsof {
|
||||
|
||||
readProc;
|
||||
lsof;
|
||||
|
||||
|
||||
sub readFile {
|
||||
my $path = shift;
|
||||
if (-e $path) {
|
||||
if (open FILE, "$path") {
|
||||
while (<FILE>) {
|
||||
print;
|
||||
}
|
||||
close FILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# This is rather NixOS-specific, so it probably shouldn't be here.
|
||||
readFile "/proc/sys/kernel/modprobe";
|
||||
readFile "/proc/sys/kernel/fbsplash";
|
||||
|
||||
@@ -4,6 +4,18 @@ use strict;
|
||||
use File::Temp qw(tempdir);
|
||||
use readmanifest;
|
||||
|
||||
|
||||
# Some patch generations options.
|
||||
|
||||
# Max size of NAR archives to generate patches for.
|
||||
my $maxNarSize = $ENV{"NIX_MAX_NAR_SIZE"};
|
||||
$maxNarSize = 100 * 1024 * 1024 if !defined $maxNarSize;
|
||||
|
||||
# If patch is bigger than this fraction of full archive, reject.
|
||||
my $maxPatchFraction = $ENV{"NIX_PATCH_FRACTION"};
|
||||
$maxPatchFraction = 0.60 if !defined $maxPatchFraction;
|
||||
|
||||
|
||||
die unless scalar @ARGV == 5;
|
||||
|
||||
my $hashAlgo = "sha256";
|
||||
@@ -22,23 +34,22 @@ print "TEMP = $tmpDir\n";
|
||||
#END { rmdir $tmpDir; }
|
||||
|
||||
my %srcNarFiles;
|
||||
my %srcLocalPaths;
|
||||
my %srcPatches;
|
||||
my %srcSuccessors;
|
||||
|
||||
my %dstNarFiles;
|
||||
my %dstLocalPaths;
|
||||
my %dstPatches;
|
||||
my %dstSuccessors;
|
||||
|
||||
readManifest "$srcDir/MANIFEST",
|
||||
\%srcNarFiles, \%srcPatches, \%srcSuccessors;
|
||||
\%srcNarFiles, \%srcLocalPaths, \%srcPatches;
|
||||
|
||||
readManifest "$dstDir/MANIFEST",
|
||||
\%dstNarFiles, \%dstPatches, \%dstSuccessors;
|
||||
\%dstNarFiles, \%dstLocalPaths, \%dstPatches;
|
||||
|
||||
|
||||
sub findOutputPaths {
|
||||
my $narFiles = shift;
|
||||
my $successors = shift;
|
||||
|
||||
my %outPaths;
|
||||
|
||||
@@ -63,10 +74,10 @@ sub findOutputPaths {
|
||||
}
|
||||
|
||||
print "finding src output paths...\n";
|
||||
my %srcOutPaths = findOutputPaths \%srcNarFiles, \%srcSuccessors;
|
||||
my %srcOutPaths = findOutputPaths \%srcNarFiles;
|
||||
|
||||
print "finding dst output paths...\n";
|
||||
my %dstOutPaths = findOutputPaths \%dstNarFiles, \%dstSuccessors;
|
||||
my %dstOutPaths = findOutputPaths \%dstNarFiles;
|
||||
|
||||
|
||||
sub getNameVersion {
|
||||
@@ -277,8 +288,6 @@ foreach my $p (keys %dstOutPaths) {
|
||||
my $srcNarBz2 = getNarBz2 \%srcNarFiles, $closest;
|
||||
my $dstNarBz2 = getNarBz2 \%dstNarFiles, $p;
|
||||
|
||||
my $maxNarSize = 150 * 1024 * 1024;
|
||||
|
||||
system("@bunzip2@ < $srcNarBz2 > $tmpDir/A") == 0
|
||||
or die "cannot unpack $srcNarBz2";
|
||||
|
||||
@@ -310,16 +319,21 @@ foreach my $p (keys %dstOutPaths) {
|
||||
my $narDiffSize = (stat "$tmpDir/DIFF")[7];
|
||||
my $dstNarBz2Size = (stat $dstNarBz2)[7];
|
||||
|
||||
print " size $narDiffSize; full size $dstNarBz2Size\n";
|
||||
|
||||
if ($narDiffSize >= $dstNarBz2Size) {
|
||||
print " rejecting; patch bigger than full archive\n";
|
||||
next;
|
||||
}
|
||||
|
||||
if ($narDiffSize / $dstNarBz2Size >= $maxPatchFraction) {
|
||||
print " rejecting; patch too large relative to full archive\n";
|
||||
next;
|
||||
}
|
||||
|
||||
my $finalName =
|
||||
"$narDiffHash.nar-bsdiff";
|
||||
|
||||
print " size $narDiffSize; full size $dstNarBz2Size\n";
|
||||
|
||||
if (-e "$patchesDir/$finalName") {
|
||||
print " not copying, already exists\n";
|
||||
}
|
||||
@@ -348,11 +362,22 @@ foreach my $p (keys %dstOutPaths) {
|
||||
# patches that produce either paths in the destination or paths that
|
||||
# can be used as the base for other useful patches).
|
||||
|
||||
print "propagating patches...\n";
|
||||
|
||||
my $changed;
|
||||
do {
|
||||
# !!! we repeat this to reach the transitive closure; inefficient
|
||||
$changed = 0;
|
||||
|
||||
print "loop\n";
|
||||
|
||||
my %dstBasePaths;
|
||||
foreach my $q (keys %dstPatches) {
|
||||
foreach my $patch (@{$dstPatches{$q}}) {
|
||||
$dstBasePaths{$patch->{basePath}} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $p (keys %srcPatches) {
|
||||
my $patchList = $srcPatches{$p};
|
||||
|
||||
@@ -360,22 +385,18 @@ do {
|
||||
|
||||
# Is path $p included in the destination? If so, include
|
||||
# patches that produce it.
|
||||
$include = 1 if (defined $dstNarFiles{$p});
|
||||
$include = 1 if defined $dstNarFiles{$p};
|
||||
|
||||
# Is path $p a path that serves as a base for paths in the
|
||||
# destination? If so, include patches that produce it.
|
||||
foreach my $q (keys %dstPatches) {
|
||||
foreach my $patch (@{$dstPatches{$q}}) {
|
||||
# !!! check baseHash
|
||||
$include = 1 if ($p eq $patch->{basePath});
|
||||
}
|
||||
}
|
||||
# !!! check baseHash
|
||||
$include = 1 if defined $dstBasePaths{$p};
|
||||
|
||||
if ($include) {
|
||||
foreach my $patch (@{$patchList}) {
|
||||
$changed = 1 if addPatch \%dstPatches, $p, $patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -384,4 +405,4 @@ do {
|
||||
|
||||
# Rewrite the manifest of the destination (with the new patches).
|
||||
writeManifest "$dstDir/MANIFEST",
|
||||
\%dstNarFiles, \%dstPatches, \%dstSuccessors;
|
||||
\%dstNarFiles, \%dstPatches;
|
||||
|
||||
@@ -7,12 +7,12 @@ use readcache;
|
||||
|
||||
# Read the manifests.
|
||||
my %narFiles;
|
||||
my %localPaths;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
foreach my $manifest (@ARGV) {
|
||||
print STDERR "loading $manifest\n";
|
||||
if (readManifest($manifest, \%narFiles, \%patches, \%successors, 1) < 3) {
|
||||
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches, 1) < 3) {
|
||||
# die "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ sub readDir {
|
||||
}
|
||||
|
||||
readDir "/data/webserver/dist/nix-cache";
|
||||
readDir "/data/webserver/dist/test";
|
||||
readDir "/data/webserver/dist/test-cache";
|
||||
readDir "/data/webserver/dist/patches";
|
||||
|
||||
print STDERR scalar (keys %archives), "\n";
|
||||
|
||||
@@ -6,12 +6,12 @@ use readcache;
|
||||
|
||||
|
||||
my %allNarFiles;
|
||||
my %allLocalPaths;
|
||||
my %allPatches;
|
||||
my %allSuccessors;
|
||||
|
||||
foreach my $manifest (glob "/data/webserver/dist/*/*/MANIFEST") {
|
||||
print STDERR "loading $manifest\n";
|
||||
readManifest($manifest, \%allNarFiles, \%allPatches, \%allSuccessors, 1);
|
||||
readManifest($manifest, \%allNarFiles, \%allLocalPaths, \%allPatches, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ foreach my $manifest (@ARGV) {
|
||||
|
||||
my %narFiles;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
if (readManifest($manifest, \%narFiles, \%patches, \%successors, 1) < 3) {
|
||||
if (readManifest($manifest, \%narFiles, \%patches, 1) < 3) {
|
||||
print STDERR "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
|
||||
next;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ EOF
|
||||
}
|
||||
|
||||
elsif ($arg eq "--no-out-link" or $arg eq "--no-link") {
|
||||
$addOutLink = 1;
|
||||
$addOutLink = 0;
|
||||
}
|
||||
|
||||
elsif ($arg eq "--drv-link") {
|
||||
@@ -77,12 +77,18 @@ EOF
|
||||
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") {
|
||||
$n++;
|
||||
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
|
||||
push @buildArgs, ($arg, $ARGV[$n]);
|
||||
}
|
||||
|
||||
elsif (substr($arg, 0, 1) eq "-") {
|
||||
push @buildArgs, $arg;
|
||||
}
|
||||
@@ -116,17 +122,19 @@ foreach my $expr (@exprs) {
|
||||
close DRVPATHS or exit 1;
|
||||
|
||||
foreach my $drvPath (@drvPaths) {
|
||||
my $target = readlink $drvPath;
|
||||
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
|
||||
print STDERR "store derivation is $target\n";
|
||||
}
|
||||
|
||||
# Build.
|
||||
my $outPaths = `@bindir@/nix-store --add-root "$outLink" --indirect -rv @buildArgs @drvPaths`;
|
||||
my @outPaths = split ' ', $outPaths;
|
||||
|
||||
my @outPaths;
|
||||
$pid = open(OUTPATHS, "-|") || exec "@bindir@/nix-store", "--add-root", $outLink, "--indirect", "-rv",
|
||||
@buildArgs, @drvPaths;
|
||||
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
|
||||
close OUTPATHS or exit 1;
|
||||
|
||||
foreach my $outPath (@outPaths) {
|
||||
my $target = readlink $outPath;
|
||||
my $target = readlink $outPath or die "cannot read symlink `$outPath'";
|
||||
print "$target\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,24 @@
|
||||
|
||||
use strict;
|
||||
|
||||
my $rootsDir = "@localstatedir@/nix/gcroots/channels";
|
||||
my $rootsDir = "@localstatedir@/nix/gcroots";
|
||||
|
||||
my $stateDir = $ENV{"NIX_STATE_DIR"};
|
||||
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
|
||||
|
||||
|
||||
# Turn on caching in nix-prefetch-url.
|
||||
my $channelCache = "$stateDir/channel-cache";
|
||||
mkdir $channelCache, 0755 unless -e $channelCache;
|
||||
$ENV{'NIX_DOWNLOAD_CACHE'} = $channelCache if -W $channelCache;
|
||||
|
||||
|
||||
# Figure out the name of the `.nix-channels' file to use.
|
||||
my $home = $ENV{"HOME"};
|
||||
die '$HOME not set' unless defined $home;
|
||||
my $channelsList = "$home/.nix-channels";
|
||||
|
||||
my $nixDefExpr = "$home/.nix-defexpr";
|
||||
|
||||
|
||||
my @channels;
|
||||
@@ -70,48 +78,56 @@ sub removeChannel {
|
||||
sub update {
|
||||
readChannels;
|
||||
|
||||
# Get rid of all the old substitutes.
|
||||
system("@bindir@/nix-store", "--clear-substitutes") == 0
|
||||
or die "cannot clear substitutes";
|
||||
# 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
|
||||
# multi-user Nix installation, he at least gets installation from
|
||||
# source.
|
||||
if (-W "$stateDir/manifests") {
|
||||
|
||||
# Remove all the old manifests.
|
||||
for my $manifest (glob "$stateDir/manifests/*.nixmanifest") {
|
||||
unlink $manifest or die "cannot remove `$manifest': $!";
|
||||
}
|
||||
# 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";
|
||||
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
|
||||
or die "cannot pull cache manifest from `$url'";
|
||||
}
|
||||
|
||||
# Pull cache manifests.
|
||||
foreach my $url (@channels) {
|
||||
print "pulling cache manifest from `$url'\n";
|
||||
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
|
||||
or die "cannot pull cache manifest from `$url'";
|
||||
}
|
||||
|
||||
# Create a Nix expression that fetches and unpacks the channel Nix
|
||||
# expressions.
|
||||
|
||||
my $nixExpr = "[";
|
||||
my $inputs = "[";
|
||||
foreach my $url (@channels) {
|
||||
$url =~ /\/([^\/]+)\/?$/;
|
||||
my $channelName = $1;
|
||||
$channelName = "unnamed" unless defined $channelName;
|
||||
|
||||
my $fullURL = "$url/nixexprs.tar.bz2";
|
||||
print "downloading Nix expressions from `$fullURL'...\n";
|
||||
$ENV{"PRINT_PATH"} = 1;
|
||||
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL' 2> /dev/null`;
|
||||
$ENV{"QUIET"} = 1;
|
||||
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL'`;
|
||||
die "cannot fetch `$fullURL'" if $? != 0;
|
||||
chomp $path;
|
||||
$nixExpr .= $path . " ";
|
||||
$inputs .= '"' . $channelName . '"' . " " . $path . " ";
|
||||
}
|
||||
$nixExpr .= "]";
|
||||
|
||||
$nixExpr =
|
||||
"(import @datadir@/nix/corepkgs/channels/unpack.nix) " .
|
||||
"{inputs = $nixExpr; system = \"@system@\";}";
|
||||
$inputs .= "]";
|
||||
|
||||
# Figure out a name for the GC root.
|
||||
my $userName = getpwuid($<);
|
||||
die "who ARE you? go away" unless defined $userName;
|
||||
|
||||
my $rootFile = "$rootsDir/$userName";
|
||||
my $rootFile = "$rootsDir/per-user/$userName/channels";
|
||||
|
||||
# Instantiate the Nix expression.
|
||||
my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate --add-root '$rootFile'.tmp -`
|
||||
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;
|
||||
|
||||
@@ -122,9 +138,12 @@ sub update {
|
||||
|
||||
unlink "$rootFile.tmp";
|
||||
|
||||
# Make it the default Nix expression for `nix-env'.
|
||||
system("@bindir@/nix-env", "--import", "$outPath") == 0
|
||||
or die "cannot pull set default Nix expression to `$outPath'";
|
||||
# Make the channels appear in nix-env.
|
||||
unlink $nixDefExpr if -l $nixDefExpr; # old-skool ~/.nix-defexpr
|
||||
mkdir $nixDefExpr or die "cannot create directory `$nixDefExpr'" if !-e $nixDefExpr;
|
||||
my $channelLink = "$nixDefExpr/channels";
|
||||
unlink $channelLink; # !!! not atomic
|
||||
symlink($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,22 +21,31 @@ for my $arg (@ARGV) {
|
||||
# If `-d' was specified, remove all old generations of all profiles.
|
||||
# Of course, this makes rollbacks to before this point in time
|
||||
# impossible.
|
||||
if ($removeOld) {
|
||||
|
||||
opendir DIR, $profilesDir or die;
|
||||
sub removeOldGenerations;
|
||||
sub removeOldGenerations {
|
||||
my $dir = shift;
|
||||
|
||||
foreach my $name (sort (readdir DIR)) {
|
||||
$name = $profilesDir . "/" . $name;
|
||||
my $dh;
|
||||
opendir $dh, $dir or die;
|
||||
|
||||
foreach my $name (sort (readdir $dh)) {
|
||||
next if $name eq "." || $name eq "..";
|
||||
$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");
|
||||
}
|
||||
elsif (! -l $name && -d $name) {
|
||||
removeOldGenerations $name;
|
||||
}
|
||||
}
|
||||
|
||||
closedir DIR or die;
|
||||
|
||||
closedir $dh or die;
|
||||
}
|
||||
|
||||
removeOldGenerations $profilesDir if $removeOld;
|
||||
|
||||
|
||||
# Run the actual garbage collector.
|
||||
exec "@bindir@/nix-store", "--gc", @args;
|
||||
|
||||
148
scripts/nix-copy-closure.in
Normal file
148
scripts/nix-copy-closure.in
Normal file
@@ -0,0 +1,148 @@
|
||||
#! @perl@ -w
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
print STDERR <<EOF
|
||||
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
|
||||
EOF
|
||||
;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
# Get the target host.
|
||||
my $sshHost;
|
||||
my @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
|
||||
|
||||
my $sign = 0;
|
||||
|
||||
my $compressor = "cat";
|
||||
my $decompressor = "cat";
|
||||
|
||||
my $toMode = 1;
|
||||
|
||||
|
||||
# !!! Copied from nix-pack-closure, should put this in a module.
|
||||
my @storePaths = ();
|
||||
|
||||
while (@ARGV) {
|
||||
my $arg = shift @ARGV;
|
||||
|
||||
if ($arg eq "--sign") {
|
||||
$sign = 1;
|
||||
}
|
||||
elsif ($arg eq "--gzip") {
|
||||
$compressor = "gzip";
|
||||
$decompressor = "gunzip";
|
||||
}
|
||||
elsif ($arg eq "--from") {
|
||||
$toMode = 0;
|
||||
}
|
||||
elsif ($arg eq "--to") {
|
||||
$toMode = 1;
|
||||
}
|
||||
elsif (!defined $sshHost) {
|
||||
$sshHost = $arg;
|
||||
}
|
||||
else {
|
||||
push @storePaths, $arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
die "bad: $_" unless /^\//;
|
||||
if (!defined $storePathsSeen{$_}) {
|
||||
push @allStorePaths, $_;
|
||||
$storePathsSeen{$_} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
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|");
|
||||
my @missing = ();
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
print STDERR "target machine needs $_\n";
|
||||
push @missing, $_;
|
||||
}
|
||||
close READ or die;
|
||||
|
||||
|
||||
# Export the store paths and import them on the remote machine.
|
||||
if (scalar @missing > 0) {
|
||||
my $extraOpts = "";
|
||||
$extraOpts .= "--sign" if $sign == 1;
|
||||
system("nix-store --export $extraOpts @missing | $compressor | ssh @sshOpts $sshHost '$decompressor | nix-store --import'") == 0
|
||||
or die "copying store paths to remote machine `$sshHost' failed: $?";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
else { # Copy FROM the remote machine.
|
||||
|
||||
# Query the closure of the given store paths on the remote
|
||||
# machine. Paths are assumed to be store paths; there is no
|
||||
# resolution (following of symlinks).
|
||||
my $pid = open(READ,
|
||||
"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;
|
||||
}
|
||||
}
|
||||
|
||||
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
|
||||
|
||||
|
||||
# What paths are already valid locally?
|
||||
open(READ, "@bindir@/nix-store --check-validity --print-invalid @allStorePaths|");
|
||||
my @missing = ();
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
print STDERR "local machine needs $_\n";
|
||||
push @missing, $_;
|
||||
}
|
||||
close READ or die;
|
||||
|
||||
|
||||
# Export the store paths on the remote machine and import them on locally.
|
||||
if (scalar @missing > 0) {
|
||||
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: $?";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ downloading it from URL.
|
||||
|
||||
Flags:
|
||||
--profile / -p LINK: install into the specified profile
|
||||
--non-interactive: don't run inside a new terminal XXX
|
||||
--non-interactive: don't run inside a new terminal
|
||||
EOF
|
||||
; # '
|
||||
exit 1;
|
||||
|
||||
@@ -17,10 +17,11 @@ $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", 0777 or die;
|
||||
mkdir "$tmpDir/references", 0777 or die;
|
||||
mkdir "$tmpDir/derivers", 0777 or die;
|
||||
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;
|
||||
@@ -29,6 +30,12 @@ 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;
|
||||
@@ -43,6 +50,9 @@ while (@ARGV) {
|
||||
}
|
||||
|
||||
|
||||
close TOPLEVEL or die;
|
||||
|
||||
|
||||
foreach my $storePath (sort(keys %storePaths)) {
|
||||
print STDERR "packing `$storePath'...\n";
|
||||
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
url=$1
|
||||
expHash=$2
|
||||
|
||||
# to prevent doing more than 1 chroot
|
||||
unset NIX_ROOT
|
||||
|
||||
# needed to make it work on NixOS
|
||||
export PATH=$PATH:@coreutils@
|
||||
|
||||
hashType=$NIX_HASH_ALGO
|
||||
if test -z "$hashType"; then
|
||||
hashType=md5
|
||||
hashType=sha256
|
||||
fi
|
||||
|
||||
hashFormat=
|
||||
@@ -39,29 +36,94 @@ if test -n "$expHash"; then
|
||||
fi
|
||||
|
||||
|
||||
mkTempDir() {
|
||||
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 \
|
||||
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
|
||||
}
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
# Optionally do timestamp-based caching of the download.
|
||||
# Actually, the only thing that we cache in $NIX_DOWNLOAD_CACHE is
|
||||
# the hash and the timestamp of the file at $url. The caching of
|
||||
# the file *contents* is done in Nix store, where it can be
|
||||
# garbage-collected independently.
|
||||
if test -n "$NIX_DOWNLOAD_CACHE"; then
|
||||
echo -n "$url" > $tmpPath/url
|
||||
urlHash=$(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"
|
||||
cacheFlags="--remote-time"
|
||||
if test -e "$cachedTimestampFN" -a -e "$cachedHashFN"; then
|
||||
# Only download the file if it is newer than the cached version.
|
||||
cacheFlags="$cacheFlags --time-cond $cachedTimestampFN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Perform the download.
|
||||
@curl@ --fail --location --max-redirs 20 "$url" > $tmpFile
|
||||
doDownload
|
||||
|
||||
# Compute the hash.
|
||||
hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
|
||||
if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi
|
||||
if test -n "$NIX_DOWNLOAD_CACHE" -a ! -e $tmpFile; then
|
||||
# Curl didn't create $tmpFile, so apparently there's no newer
|
||||
# file on the server.
|
||||
hash=$(cat $cachedHashFN)
|
||||
finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$hash" "$name")
|
||||
if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
|
||||
echo "cached contents of \`$url' disappeared, redownloading..." >&2
|
||||
finalPath=
|
||||
cacheFlags="--remote-time"
|
||||
doDownload
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add the downloaded file to the Nix store.
|
||||
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
|
||||
if test -z "$finalPath"; then
|
||||
|
||||
if test -n "$tmpPath"; then rm -rf $tmpPath || true; fi
|
||||
# Compute the hash.
|
||||
hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
|
||||
if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi
|
||||
|
||||
if test -n "$expHash" -a "$expHash" != "$hash"; then
|
||||
echo "hash mismatch for URL \`$url'"
|
||||
exit 1
|
||||
if test -n "$NIX_DOWNLOAD_CACHE"; then
|
||||
echo $hash > $cachedHashFN
|
||||
touch -r $tmpFile $cachedTimestampFN
|
||||
fi
|
||||
|
||||
# Add the downloaded file to the Nix store.
|
||||
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
|
||||
|
||||
if test -n "$expHash" -a "$expHash" != "$hash"; then
|
||||
echo "hash mismatch for URL \`$url'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ use readmanifest;
|
||||
my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
|
||||
or die "cannot create a temporary directory";
|
||||
|
||||
my $manifest = "$tmpDir/manifest";
|
||||
|
||||
my $binDir = $ENV{"NIX_BIN_DIR"};
|
||||
$binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
@@ -21,6 +19,11 @@ $stateDir = "@localstatedir@/nix" unless defined $stateDir;
|
||||
my $storeDir = $ENV{"NIX_STORE_DIR"};
|
||||
$storeDir = "@storedir@" unless defined $storeDir;
|
||||
|
||||
my $storeStateDir = $ENV{"NIX_STORE_STATE_DIR"};
|
||||
$storeStateDir = "@storestatedir@" unless defined $storeStateDir;
|
||||
|
||||
my $ext3cowheader = $ENV{"NIX_EXT3_COW_HEADER"};
|
||||
$ext3cowheader = "@ext3cowheader@" unless defined $ext3cowheader;
|
||||
|
||||
# Prevent access problems in shared-stored installations.
|
||||
umask 0022;
|
||||
@@ -28,23 +31,52 @@ umask 0022;
|
||||
|
||||
# Process the URLs specified on the command line.
|
||||
my %narFiles;
|
||||
my %localPaths;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
my $skipWrongStore = 0;
|
||||
|
||||
sub downloadFile {
|
||||
my $url = shift;
|
||||
$ENV{"PRINT_PATH"} = 1;
|
||||
$ENV{"QUIET"} = 1;
|
||||
my ($dummy, $path) = `$binDir/nix-prefetch-url '$url'`;
|
||||
die "cannot fetch `$url'" if $? != 0;
|
||||
die "nix-prefetch-url did not return a path" unless defined $path;
|
||||
chomp $path;
|
||||
return $path;
|
||||
}
|
||||
|
||||
sub processURL {
|
||||
my $url = shift;
|
||||
|
||||
$url =~ s/\/$//;
|
||||
print "obtaining list of Nix archives at $url...\n";
|
||||
|
||||
system("@curl@ --fail --silent --show-error --location --max-redirs 20 " .
|
||||
"'$url' > '$manifest'") == 0
|
||||
or die "curl failed: $?";
|
||||
my $manifest;
|
||||
|
||||
if (readManifest($manifest, \%narFiles, \%patches, \%successors) < 3) {
|
||||
die "manifest `$url' is too old (i.e., for Nix <= 0.7)\n";
|
||||
# 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";
|
||||
my $bzipped = downloadFile "$url.bz2";
|
||||
|
||||
$manifest = "$tmpDir/MANIFEST";
|
||||
|
||||
system("@bunzip2@ < $bzipped > $manifest") == 0
|
||||
or die "cannot decompress manifest";
|
||||
|
||||
$manifest = (`$binDir/nix-store --add $manifest`
|
||||
or die "cannot copy $manifest to the store");
|
||||
chomp $manifest;
|
||||
}
|
||||
|
||||
# Otherwise, just get the uncompressed manifest.
|
||||
else {
|
||||
print "obtaining list of Nix archives at `$url'...\n";
|
||||
$manifest = downloadFile $url;
|
||||
}
|
||||
|
||||
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
|
||||
die "`$url' is not manifest or it is too old (i.e., for Nix <= 0.7)\n";
|
||||
}
|
||||
|
||||
if ($skipWrongStore) {
|
||||
@@ -67,8 +99,8 @@ sub processURL {
|
||||
|
||||
my $finalPath = "$stateDir/manifests/$baseName-$hash.nixmanifest";
|
||||
|
||||
system ("@coreutils@/mv", "-f", "$manifest", "$finalPath") == 0
|
||||
or die "cannot move `$manifest' to `$finalPath";
|
||||
system("@coreutils@/ln", "-sfn", "$manifest", "$finalPath") == 0
|
||||
or die "cannot link `$finalPath to `$manifest'";
|
||||
}
|
||||
|
||||
while (@ARGV) {
|
||||
@@ -81,30 +113,5 @@ while (@ARGV) {
|
||||
}
|
||||
|
||||
|
||||
my $size = scalar (keys %narFiles);
|
||||
my $size = scalar (keys %narFiles) + scalar (keys %localPaths);
|
||||
print "$size store paths in manifest\n";
|
||||
|
||||
|
||||
# Register all substitutes.
|
||||
print STDERR "registering substitutes...\n";
|
||||
|
||||
my $pid = open(WRITE, "|$binDir/nix-store --register-substitutes")
|
||||
or die "cannot run nix-store";
|
||||
|
||||
foreach my $storePath (keys %narFiles) {
|
||||
my $narFileList = $narFiles{$storePath};
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
print WRITE "$storePath\n";
|
||||
print WRITE "$narFile->{deriver}\n";
|
||||
print WRITE "$libexecDir/nix/download-using-manifests.pl\n";
|
||||
print WRITE "0\n";
|
||||
my @references = split " ", $narFile->{references};
|
||||
my $count = scalar @references;
|
||||
print WRITE "$count\n";
|
||||
foreach my $reference (@references) {
|
||||
print WRITE "$reference\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close WRITE or die "nix-store failed: $?";
|
||||
|
||||
@@ -116,9 +116,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>) {
|
||||
@@ -146,7 +146,7 @@ while (scalar @tmp > 0) {
|
||||
# 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|")
|
||||
my $pid = open(READ, "$binDir/nix-store --no-build-hook --realise @tmp2|")
|
||||
or die "cannot run nix-store";
|
||||
while (<READ>) {
|
||||
chomp;
|
||||
@@ -264,8 +264,12 @@ foreach my $narArchive (@narArchives) {
|
||||
print STDERR "uploading manifest...\n";
|
||||
if ($localCopy) {
|
||||
copyFile $manifest, $localManifestFile;
|
||||
copyFile "$manifest.bz2", "$localManifestFile.bz2";
|
||||
} else {
|
||||
system("$curl --show-error --upload-file " .
|
||||
system("$curl --show-error --upload-file " .
|
||||
"'$manifest' '$manifestPutURL' > /dev/null") == 0 or
|
||||
die "curl failed on $manifest: $?";
|
||||
system("$curl --show-error --upload-file " .
|
||||
"'$manifest'.bz2 '$manifestPutURL'.bz2 > /dev/null") == 0 or
|
||||
die "curl failed on $manifest: $?";
|
||||
}
|
||||
|
||||
68
scripts/nix-reduce-build.in
Normal file
68
scripts/nix-reduce-build.in
Normal file
@@ -0,0 +1,68 @@
|
||||
#! @shell@
|
||||
|
||||
WORKING_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}"/nix-reduce-build-XXXXXX);
|
||||
cd "$WORKING_DIRECTORY";
|
||||
|
||||
if test -z "$1" ; then
|
||||
echo 'nix-reduce-build (paths or Nix expressions) -- (logins at remote computers)' >&2
|
||||
echo As in: >&2
|
||||
echo nix-reduce-build /etc/nixos/nixos -- user@somewhere.nowhere.example.org >&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_PATH:-/nix/store}/*)
|
||||
echo "$REPLY" >> paths; >&2
|
||||
;;
|
||||
*)
|
||||
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
|
||||
|
||||
if test -z "$1" ; then
|
||||
cat needed-paths;
|
||||
fi;
|
||||
|
||||
for i in "$@"; do
|
||||
cat needed-paths | while read; do
|
||||
nix-copy-closure --from "$i" --gzip "$REPLY" </dev/null || true;
|
||||
done;
|
||||
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"
|
||||
@@ -77,3 +77,12 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use File::Basename;
|
||||
|
||||
|
||||
my @paths = ("/nix/store");
|
||||
|
||||
|
||||
print "hashing...\n";
|
||||
|
||||
my $hashList = "/tmp/nix-optimise-hash-list";
|
||||
|
||||
system("find @paths -type f -print0 | xargs -0 md5sum -- > $hashList") == 0
|
||||
or die "cannot hash store files";
|
||||
|
||||
|
||||
print "sorting by hash...\n";
|
||||
|
||||
system("sort $hashList > $hashList.sorted") == 0
|
||||
or die "cannot sort list";
|
||||
|
||||
|
||||
sub atomicLink {
|
||||
my $target = shift;
|
||||
my $new = shift;
|
||||
my $tmpNew = "${new}_optimise.$$";
|
||||
|
||||
# Make the directory writable temporarily.
|
||||
my $dir = dirname $new;
|
||||
my @st = stat $dir or die;
|
||||
|
||||
chmod ($st[2] | 0200, $dir) or die "cannot make `$dir' writable: $!";
|
||||
|
||||
link $target, $tmpNew or die "cannot create hard link `$tmpNew': $!";
|
||||
|
||||
rename $tmpNew, $new or die "cannot rename `$tmpNew' to `$new': $!";
|
||||
|
||||
chmod ($st[2], $dir) or die "cannot restore permission on `$dir': $!";
|
||||
utime ($st[8], $st[9], $dir) or die "cannot restore timestamp on `$dir': $!";
|
||||
}
|
||||
|
||||
|
||||
print "hard-linking...\n";
|
||||
|
||||
open LIST, "<$hashList.sorted" or die;
|
||||
|
||||
my $prevFile;
|
||||
my $prevHash;
|
||||
my $prevInode;
|
||||
my $prevExec;
|
||||
|
||||
my $totalSpace = 0;
|
||||
my $savedSpace = 0;
|
||||
|
||||
while (<LIST>) {
|
||||
/^([0-9a-f]*)\s+(.*)$/ or die;
|
||||
my $curFile = $2;
|
||||
my $curHash = $1;
|
||||
|
||||
my @st = stat $curFile or die;
|
||||
next if ($st[2] & 0222) != 0; # skip writable files
|
||||
|
||||
my $fileSize = $st[7];
|
||||
$totalSpace += $fileSize;
|
||||
my $isExec = ($st[2] & 0111) == 0111;
|
||||
|
||||
if (defined $prevHash && $curHash eq $prevHash
|
||||
&& $prevExec == $isExec)
|
||||
{
|
||||
|
||||
if ($st[1] != $prevInode) {
|
||||
print "$curFile = $prevFile\n";
|
||||
atomicLink $prevFile, $curFile;
|
||||
$savedSpace += $fileSize;
|
||||
}
|
||||
|
||||
} else {
|
||||
$prevFile = $curFile;
|
||||
$prevHash = $curHash;
|
||||
$prevInode = $st[1];
|
||||
$prevExec = ($st[2] & 0111) == 0111;
|
||||
}
|
||||
}
|
||||
|
||||
print "total space = $totalSpace\n";
|
||||
print "saved space = $savedSpace\n";
|
||||
my $savings = ($savedSpace / $totalSpace) * 100.0;
|
||||
print "savings = $savings %\n";
|
||||
|
||||
close LIST;
|
||||
@@ -34,8 +34,8 @@ sub addPatch {
|
||||
sub readManifest {
|
||||
my $manifest = shift;
|
||||
my $narFiles = shift;
|
||||
my $localPaths = shift;
|
||||
my $patches = shift;
|
||||
my $successors = shift;
|
||||
my $allowConflicts = shift;
|
||||
$allowConflicts = 0 unless defined $allowConflicts;
|
||||
|
||||
@@ -51,7 +51,6 @@ sub readManifest {
|
||||
my $url;
|
||||
my $hash;
|
||||
my $size;
|
||||
my @preds;
|
||||
my $basePath;
|
||||
my $baseHash;
|
||||
my $patchType;
|
||||
@@ -59,6 +58,7 @@ sub readManifest {
|
||||
my $references;
|
||||
my $deriver;
|
||||
my $hashAlgo;
|
||||
my $copyFrom;
|
||||
|
||||
while (<MANIFEST>) {
|
||||
chomp;
|
||||
@@ -75,7 +75,6 @@ sub readManifest {
|
||||
undef $url;
|
||||
undef $hash;
|
||||
undef $size;
|
||||
@preds = ();
|
||||
undef $narHash;
|
||||
undef $basePath;
|
||||
undef $baseHash;
|
||||
@@ -117,10 +116,6 @@ sub readManifest {
|
||||
};
|
||||
}
|
||||
|
||||
foreach my $p (@preds) {
|
||||
$$successors{$p} = $storePath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
elsif ($type eq "patch") {
|
||||
@@ -132,13 +127,29 @@ sub readManifest {
|
||||
}, $allowConflicts;
|
||||
}
|
||||
|
||||
elsif ($type eq "localPath") {
|
||||
|
||||
$$localPaths{$storePath} = []
|
||||
unless defined $$localPaths{$storePath};
|
||||
|
||||
my $localPathsList = $$localPaths{$storePath};
|
||||
|
||||
# !!! remove duplicates
|
||||
|
||||
push @{$localPathsList},
|
||||
{ copyFrom => $copyFrom, references => $references
|
||||
, deriver => ""
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
|
||||
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
|
||||
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
|
||||
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
|
||||
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
|
||||
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { push @preds, $1; }
|
||||
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { } # obsolete
|
||||
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
|
||||
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
|
||||
elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }
|
||||
@@ -165,6 +176,7 @@ sub writeManifest
|
||||
my $manifest = shift;
|
||||
my $narFiles = shift;
|
||||
my $patches = shift;
|
||||
my $copySources = shift;
|
||||
|
||||
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
|
||||
|
||||
@@ -210,6 +222,14 @@ sub writeManifest
|
||||
|
||||
rename("$manifest.tmp", $manifest)
|
||||
or die "cannot rename $manifest.tmp: $!";
|
||||
|
||||
|
||||
# Create a bzipped manifest.
|
||||
system("@bzip2@ < $manifest > $manifest.bz2.tmp") == 0
|
||||
or die "cannot compress manifest";
|
||||
|
||||
rename("$manifest.bz2.tmp", "$manifest.bz2")
|
||||
or die "cannot rename $manifest.bz2.tmp: $!";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,14 +6,12 @@ use readmanifest;
|
||||
for my $p (@ARGV) {
|
||||
|
||||
my %narFiles;
|
||||
my %localPaths;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
readManifest $p,
|
||||
\%narFiles, \%patches, \%successors;
|
||||
readManifest $p, \%narFiles, \%localPaths, \%patches;
|
||||
|
||||
%patches = ();
|
||||
|
||||
writeManifest $p,
|
||||
\%narFiles, \%patches, \%successors;
|
||||
writeManifest $p, \%narFiles, \%patches;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ die unless scalar @ARGV == 2;
|
||||
my $cache = $ARGV[0];
|
||||
my $manifest = $ARGV[1];
|
||||
my %narFiles;
|
||||
my %localPaths;
|
||||
my %patches;
|
||||
my %successors;
|
||||
|
||||
readManifest $manifest, \%narFiles, \%patches, \%successors;
|
||||
readManifest $manifest, \%narFiles, \%localPaths, \%patches;
|
||||
|
||||
foreach my $storePath (keys %narFiles) {
|
||||
my $narFileList = $narFiles{$storePath};
|
||||
@@ -50,4 +50,4 @@ if (! -e "$manifest.backup") {
|
||||
system "mv --reply=no '$manifest' '$manifest.backup'";
|
||||
}
|
||||
|
||||
writeManifest $manifest, \%narFiles, \%patches, \%successors;
|
||||
writeManifest $manifest, \%narFiles, \%patches;
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
|
||||
libexpr nix-instantiate nix-env nix-log2xml bsdiff-4.3
|
||||
SUBDIRS = bin2c boost libutil libext3cow libstore libmain nix-store nix-hash \
|
||||
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
|
||||
nix-log2xml bsdiff-4.3 nix-state
|
||||
|
||||
EXTRA_DIST = aterm-helper.pl
|
||||
|
||||
SETUID_PROGS = nix-store nix-instantiate nix-env
|
||||
install-exec-hook:
|
||||
if SETUID_HACK
|
||||
if HAVE_SETRESUID
|
||||
cd $(DESTDIR)$(bindir) && chown @NIX_USER@ $(SETUID_PROGS) \
|
||||
&& chgrp @NIX_GROUP@ $(SETUID_PROGS) && chmod ug+s $(SETUID_PROGS)
|
||||
else
|
||||
cd $(DESTDIR)$(bindir) && chown root $(SETUID_PROGS) && chmod u+s $(SETUID_PROGS)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -47,6 +47,7 @@ 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+)?/) {
|
||||
|
||||
@@ -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,11 +2,11 @@ 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
|
||||
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.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
|
||||
get-drvs.hh attr-path.hh expr-to-xml.hh common-opts.hh
|
||||
|
||||
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
||||
../boost/format/libformat.la
|
||||
|
||||
@@ -46,7 +46,7 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||
|
||||
if (apType == apAttr) {
|
||||
|
||||
ATermMap attrs(128);
|
||||
ATermMap attrs;
|
||||
|
||||
if (!isAttrs(state, e, attrs))
|
||||
throw TypeError(
|
||||
|
||||
32
src/libexpr/common-opts.cc
Normal file
32
src/libexpr/common-opts.cc
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "common-opts.hh"
|
||||
#include "../libmain/shared.hh"
|
||||
#include "util.hh"
|
||||
#include "parser.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
bool parseOptionArg(const string & arg, Strings::iterator & i,
|
||||
const Strings::iterator & argsEnd, EvalState & state,
|
||||
ATermMap & autoArgs)
|
||||
{
|
||||
if (arg != "--arg" && arg != "--argstr") return false;
|
||||
|
||||
UsageError error(format("`%1%' requires two arguments") % arg);
|
||||
|
||||
if (i == argsEnd) throw error;
|
||||
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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
17
src/libexpr/common-opts.hh
Normal file
17
src/libexpr/common-opts.hh
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __COMMON_OPTS_H
|
||||
#define __COMMON_OPTS_H
|
||||
|
||||
#include "eval.hh"
|
||||
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* !__COMMON_OPTS_H */
|
||||
@@ -2,8 +2,14 @@
|
||||
#include "parser.hh"
|
||||
#include "hash.hh"
|
||||
#include "util.hh"
|
||||
#include "store.hh"
|
||||
#include "store-api.hh"
|
||||
#include "derivations.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "globals.hh"
|
||||
|
||||
|
||||
#define LocalNoInline(f) static f __attribute__((noinline)); f
|
||||
#define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f
|
||||
|
||||
|
||||
namespace nix {
|
||||
@@ -27,6 +33,42 @@ void EvalState::addPrimOp(const string & name,
|
||||
}
|
||||
|
||||
|
||||
/* Every "format" object (even temporary) takes up a few hundred bytes
|
||||
of stack space, which is a real killer in the recursive
|
||||
evaluator. So here are some helper functions for throwing
|
||||
exceptions. */
|
||||
|
||||
LocalNoInlineNoReturn(void throwEvalError(const char * s))
|
||||
{
|
||||
throw EvalError(s);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
|
||||
{
|
||||
throw EvalError(format(s) % s2);
|
||||
}
|
||||
|
||||
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
|
||||
{
|
||||
throw TypeError(format(s) % s2);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s))
|
||||
{
|
||||
e.addPrefix(s);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
|
||||
{
|
||||
e.addPrefix(format(s) % s2);
|
||||
}
|
||||
|
||||
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const string & s3))
|
||||
{
|
||||
e.addPrefix(format(s) % s2 % s3);
|
||||
}
|
||||
|
||||
|
||||
/* Substitute an argument set into the body of a function. */
|
||||
static Expr substArgs(EvalState & state,
|
||||
Expr body, ATermList formals, Expr arg)
|
||||
@@ -35,7 +77,7 @@ static Expr substArgs(EvalState & state,
|
||||
ATermMap subs(nrFormals);
|
||||
|
||||
/* Get the actual arguments and put them in the substitution. */
|
||||
ATermMap args(128); /* !!! fix */
|
||||
ATermMap args;
|
||||
queryAllAttrs(arg, args);
|
||||
for (ATermMap::const_iterator i = args.begin(); i != args.end(); ++i)
|
||||
subs.set(i->key, i->value);
|
||||
@@ -109,7 +151,7 @@ static Expr substArgs(EvalState & state,
|
||||
to attributes substituted with selection expressions on the
|
||||
original set. E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f
|
||||
(e.x) (e.y); y = e.x;}'. */
|
||||
ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
|
||||
LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds))
|
||||
{
|
||||
ATerm name;
|
||||
Expr e2;
|
||||
@@ -145,11 +187,11 @@ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
|
||||
}
|
||||
|
||||
|
||||
static Expr updateAttrs(Expr e1, Expr e2)
|
||||
LocalNoInline(Expr updateAttrs(Expr e1, Expr e2))
|
||||
{
|
||||
/* Note: e1 and e2 should be in normal form. */
|
||||
|
||||
ATermMap attrs(128); /* !!! */
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(e1, attrs, true);
|
||||
queryAllAttrs(e2, attrs, true);
|
||||
|
||||
@@ -157,23 +199,24 @@ static Expr updateAttrs(Expr e1, Expr e2)
|
||||
}
|
||||
|
||||
|
||||
string evalString(EvalState & state, Expr e)
|
||||
string evalString(EvalState & state, Expr e, PathSet & context)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATerm s;
|
||||
if (!matchStr(e, s))
|
||||
throw TypeError(format("value is %1% while a string was expected") % showType(e));
|
||||
return aterm2String(s);
|
||||
string s;
|
||||
if (!matchStr(e, s, context))
|
||||
throwTypeError("value is %1% while a string was expected", showType(e));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Path evalPath(EvalState & state, Expr e)
|
||||
string evalStringNoCtx(EvalState & state, Expr e)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
ATerm s;
|
||||
if (!matchPath(e, s))
|
||||
throw TypeError(format("value is %1% while a path was expected") % showType(e));
|
||||
return aterm2String(s);
|
||||
PathSet context;
|
||||
string s = evalString(state, e, context);
|
||||
if (!context.empty())
|
||||
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
|
||||
% s % *(context.begin()));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +225,7 @@ int evalInt(EvalState & state, Expr e)
|
||||
e = evalExpr(state, e);
|
||||
int i;
|
||||
if (!matchInt(e, i))
|
||||
throw TypeError(format("value is %1% while an integer was expected") % showType(e));
|
||||
throwTypeError("value is %1% while an integer was expected", showType(e));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -192,7 +235,7 @@ bool evalBool(EvalState & state, Expr e)
|
||||
e = evalExpr(state, e);
|
||||
if (e == eTrue) return true;
|
||||
else if (e == eFalse) return false;
|
||||
else throw TypeError(format("value is %1% while a boolean was expected") % showType(e));
|
||||
else throwTypeError("value is %1% while a boolean was expected", showType(e));
|
||||
}
|
||||
|
||||
|
||||
@@ -201,110 +244,136 @@ ATermList evalList(EvalState & state, Expr e)
|
||||
e = evalExpr(state, e);
|
||||
ATermList list;
|
||||
if (!matchList(e, list))
|
||||
throw TypeError(format("value is %1% while a list was expected") % showType(e));
|
||||
throwTypeError("value is %1% while a list was expected", showType(e));
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/* String concatenation and context nodes: in order to allow users to
|
||||
write things like
|
||||
|
||||
"--with-freetype2-library=" + freetype + "/lib"
|
||||
|
||||
where `freetype' is a derivation, we automatically coerce
|
||||
derivations into their output path (e.g.,
|
||||
/nix/store/hashcode-freetype) in concatenations. However, if we do
|
||||
this naively, we could introduce an undeclared dependency: when the
|
||||
string is used in another derivation, that derivation would not
|
||||
have an explicitly dependency on `freetype' in its inputDrvs
|
||||
field. Thus `freetype' would not necessarily be built.
|
||||
|
||||
To prevent this, we wrap the string resulting from the
|
||||
concatenation in a *context node*, like this:
|
||||
|
||||
Context([freetype],
|
||||
Str("--with-freetype2-library=/nix/store/hashcode-freetype/lib"))
|
||||
|
||||
Thus the context is the list of all derivations used in the
|
||||
computation of a value. These contexts are propagated through
|
||||
further concatenations. In processBinding() in primops.cc, context
|
||||
nodes are unwrapped and added to inputDrvs.
|
||||
|
||||
!!! Should the ordering of the context list have a canonical form?
|
||||
|
||||
!!! Contexts are not currently recognised in most places in the
|
||||
evaluator. */
|
||||
|
||||
|
||||
/* Coerce a value to a string, keeping track of contexts. */
|
||||
string coerceToStringWithContext(EvalState & state,
|
||||
ATermList & context, Expr e, bool & isPath)
|
||||
static void flattenList(EvalState & state, Expr e, ATermList & result)
|
||||
{
|
||||
ATermList es;
|
||||
e = evalExpr(state, e);
|
||||
if (matchList(e, es))
|
||||
for (ATermIterator i(es); i; ++i)
|
||||
flattenList(state, *i, result);
|
||||
else
|
||||
result = ATinsert(result, e);
|
||||
}
|
||||
|
||||
|
||||
ATermList flattenList(EvalState & state, Expr e)
|
||||
{
|
||||
ATermList result = ATempty;
|
||||
flattenList(state, e, result);
|
||||
return ATreverse(result);
|
||||
}
|
||||
|
||||
|
||||
string coerceToString(EvalState & state, Expr e, PathSet & context,
|
||||
bool coerceMore, bool copyToStore)
|
||||
{
|
||||
isPath = false;
|
||||
|
||||
e = evalExpr(state, e);
|
||||
|
||||
string s;
|
||||
|
||||
if (matchStr(e, s, context)) return s;
|
||||
|
||||
ATerm s2;
|
||||
if (matchPath(e, s2)) {
|
||||
Path path(canonPath(aterm2String(s2)));
|
||||
|
||||
if (!copyToStore) return path;
|
||||
|
||||
if (isDerivation(path))
|
||||
throw EvalError(format("file names are not allowed to end in `%1%'")
|
||||
% drvExtension);
|
||||
|
||||
Path dstPath;
|
||||
if (state.srcToStore[path] != "")
|
||||
dstPath = state.srcToStore[path];
|
||||
else {
|
||||
dstPath = readOnlyMode
|
||||
? computeStorePathForPath(path).first
|
||||
: store->addToStore(path);
|
||||
state.srcToStore[path] = dstPath;
|
||||
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
|
||||
% path % dstPath);
|
||||
}
|
||||
|
||||
context.insert(dstPath);
|
||||
return dstPath;
|
||||
}
|
||||
|
||||
ATermList es;
|
||||
ATerm e2;
|
||||
if (matchContext(e, es, e2)) {
|
||||
e = e2;
|
||||
context = ATconcat(es, context);
|
||||
}
|
||||
|
||||
ATerm s;
|
||||
if (matchStr(e, s) || matchUri(e, s))
|
||||
return aterm2String(s);
|
||||
|
||||
if (matchPath(e, s)) {
|
||||
isPath = true;
|
||||
Path path = aterm2String(s);
|
||||
if (isInStore(path)) {
|
||||
context = ATinsert(context, makePath(toATerm(toStorePath(path))));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
if (matchAttrs(e, es))
|
||||
return coerceToString(state, makeSelect(e, toATerm("outPath")),
|
||||
context, coerceMore, copyToStore);
|
||||
|
||||
if (matchAttrs(e, es)) {
|
||||
ATermMap attrs(128); /* !!! */
|
||||
queryAllAttrs(e, attrs, false);
|
||||
if (coerceMore) {
|
||||
|
||||
Expr a = attrs.get(toATerm("type"));
|
||||
if (a && evalString(state, a) == "derivation") {
|
||||
a = attrs.get(toATerm("outPath"));
|
||||
if (!a) throw TypeError("output path missing from derivation");
|
||||
isPath = true;
|
||||
context = ATinsert(context, e);
|
||||
return evalPath(state, a);
|
||||
/* Note that `false' is represented as an empty string for
|
||||
shell scripting convenience, just like `null'. */
|
||||
if (e == eTrue) return "1";
|
||||
if (e == eFalse) return "";
|
||||
int n;
|
||||
if (matchInt(e, n)) return int2String(n);
|
||||
if (matchNull(e)) return "";
|
||||
|
||||
if (matchList(e, es)) {
|
||||
string result;
|
||||
es = flattenList(state, e);
|
||||
bool first = true;
|
||||
for (ATermIterator i(es); i; ++i) {
|
||||
if (!first) result += " "; else first = false;
|
||||
result += coerceToString(state, *i,
|
||||
context, coerceMore, copyToStore);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw TypeError(format("cannot coerce %1% to a string") % showType(e));
|
||||
throwTypeError("cannot coerce %1% to a string", showType(e));
|
||||
}
|
||||
|
||||
|
||||
/* Wrap an expression in a context if the context is not empty. */
|
||||
Expr wrapInContext(ATermList context, Expr e)
|
||||
/* Common implementation of `+', ConcatStrings and `~'. */
|
||||
static ATerm concatStrings(EvalState & state, ATermVector & args,
|
||||
string separator = "")
|
||||
{
|
||||
return context == ATempty ? e : makeContext(context, e);
|
||||
}
|
||||
|
||||
|
||||
static ATerm concatStrings(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
ATermList context = ATempty;
|
||||
if (args.empty()) return makeStr("", PathSet());
|
||||
|
||||
PathSet context;
|
||||
std::ostringstream s;
|
||||
bool isPath = false;
|
||||
|
||||
/* If the first element is a path, then the result will also be a
|
||||
path, we don't copy anything (yet - that's done later, since
|
||||
paths are copied when they are used in a derivation), and none
|
||||
of the strings are allowed to have contexts. */
|
||||
ATerm dummy;
|
||||
args.front() = evalExpr(state, args.front());
|
||||
bool isPath = matchPath(args.front(), dummy);
|
||||
|
||||
for (ATermVector::const_iterator i = args.begin(); i != args.end(); ++i) {
|
||||
bool isPath2;
|
||||
s << coerceToStringWithContext(state, context, *i, isPath2);
|
||||
if (i == args.begin()) isPath = isPath2;
|
||||
if (i != args.begin()) s << separator;
|
||||
s << coerceToString(state, *i, context, false, !isPath);
|
||||
}
|
||||
|
||||
Expr result = isPath
|
||||
? makePath(toATerm(canonPath(s.str())))
|
||||
: makeStr(toATerm(s.str()));
|
||||
return wrapInContext(context, result);
|
||||
if (isPath && !context.empty())
|
||||
throw EvalError(format("a string that refers to a store path cannot be appended to a path, in `%1%'")
|
||||
% s.str());
|
||||
|
||||
return isPath
|
||||
? makePath(toATerm(s.str()))
|
||||
: makeStr(s.str(), context);
|
||||
}
|
||||
|
||||
|
||||
Path coerceToPath(EvalState & state, Expr e, PathSet & context)
|
||||
{
|
||||
string path = coerceToString(state, e, context, false, false);
|
||||
if (path == "" || path[0] != '/')
|
||||
throw EvalError(format("string `%1%' doesn't represent an absolute path") % path);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,7 +383,7 @@ Expr autoCallFunction(Expr e, const ATermMap & args)
|
||||
ATerm body, pos;
|
||||
|
||||
if (matchFunction(e, formals, body, pos)) {
|
||||
ATermMap actualArgs(128);
|
||||
ATermMap actualArgs(ATgetLength(formals));
|
||||
|
||||
for (ATermIterator i(formals); i; ++i) {
|
||||
Expr name, def, value; ATerm values, def2;
|
||||
@@ -333,16 +402,233 @@ Expr autoCallFunction(Expr e, const ATermMap & args)
|
||||
}
|
||||
|
||||
|
||||
/* Evaluation of various language constructs. These have been taken
|
||||
out of evalExpr2 to reduce stack space usage. (GCC is really dumb
|
||||
about stack space: it just adds up all the local variables and
|
||||
temporaries of every scope into one huge stack frame. This is
|
||||
really bad for deeply recursive functions.) */
|
||||
|
||||
|
||||
LocalNoInline(Expr evalVar(EvalState & state, ATerm name))
|
||||
{
|
||||
ATerm primOp = state.primOps.get(name);
|
||||
if (!primOp)
|
||||
throw EvalError(format("impossible: undefined variable `%1%'") % aterm2String(name));
|
||||
int arity;
|
||||
ATermBlob fun;
|
||||
if (!matchPrimOpDef(primOp, arity, fun)) abort();
|
||||
if (arity == 0)
|
||||
/* !!! backtrace for primop call */
|
||||
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
|
||||
else
|
||||
return makePrimOp(arity, fun, ATempty);
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||
{
|
||||
ATermList formals;
|
||||
ATerm pos, name;
|
||||
Expr body;
|
||||
|
||||
/* Evaluate the left-hand side. */
|
||||
fun = evalExpr(state, fun);
|
||||
|
||||
/* Is it a primop or a function? */
|
||||
int arity;
|
||||
ATermBlob funBlob;
|
||||
ATermList args;
|
||||
if (matchPrimOp(fun, arity, funBlob, args)) {
|
||||
args = ATinsert(args, arg);
|
||||
if (ATgetLength(args) == arity) {
|
||||
/* Put the arguments in a vector in reverse (i.e.,
|
||||
actual) order. */
|
||||
ATermVector args2(arity);
|
||||
for (ATermIterator i(args); i; ++i)
|
||||
args2[--arity] = *i;
|
||||
/* !!! backtrace for primop call */
|
||||
return ((PrimOp) ATgetBlobData(funBlob))
|
||||
(state, args2);
|
||||
} else
|
||||
/* Need more arguments, so propagate the primop. */
|
||||
return makePrimOp(arity, funBlob, args);
|
||||
}
|
||||
|
||||
else if (matchFunction(fun, formals, body, pos)) {
|
||||
arg = evalExpr(state, arg);
|
||||
try {
|
||||
return evalExpr(state, substArgs(state, body, formals, arg));
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the function at %1%:\n",
|
||||
showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
else if (matchFunction1(fun, name, body, pos)) {
|
||||
try {
|
||||
ATermMap subs(1);
|
||||
subs.set(name, arg);
|
||||
return evalExpr(state, substitute(Substitution(0, &subs), body));
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the function at %1%:\n",
|
||||
showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
else throwTypeError(
|
||||
"attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
|
||||
showType(fun));
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalSelect(EvalState & state, Expr e, ATerm name))
|
||||
{
|
||||
ATerm pos;
|
||||
string s = aterm2String(name);
|
||||
Expr a = queryAttr(evalExpr(state, e), s, pos);
|
||||
if (!a) throwEvalError("attribute `%1%' missing", s);
|
||||
try {
|
||||
return evalExpr(state, a);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
|
||||
s, showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos))
|
||||
{
|
||||
if (!evalBool(state, cond))
|
||||
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
|
||||
return evalExpr(state, body);
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos))
|
||||
{
|
||||
ATermMap attrs;
|
||||
try {
|
||||
defs = evalExpr(state, defs);
|
||||
queryAllAttrs(defs, attrs);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the `with' definitions at %1%:\n",
|
||||
showPos(pos));
|
||||
throw;
|
||||
}
|
||||
try {
|
||||
body = substitute(Substitution(0, &attrs), body);
|
||||
checkVarDefs(state.primOps, body);
|
||||
return evalExpr(state, body);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "while evaluating the `with' body at %1%:\n",
|
||||
showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalHasAttr(EvalState & state, Expr e, ATerm name))
|
||||
{
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(evalExpr(state, e), attrs);
|
||||
return makeBool(attrs.get(name) != 0);
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e))
|
||||
{
|
||||
Expr e1, e2;
|
||||
ATermList es;
|
||||
|
||||
ATermVector args;
|
||||
|
||||
if (matchOpPlus(e, e1, e2)) {
|
||||
|
||||
/* !!! Awful compatibility hack for `drv + /path'.
|
||||
According to regular concatenation, /path should be
|
||||
copied to the store and its store path should be
|
||||
appended to the string. However, in Nix <= 0.10, /path
|
||||
was concatenated. So handle that case separately, but
|
||||
do print out a warning. This code can go in Nix 0.12,
|
||||
maybe. */
|
||||
e1 = evalExpr(state, e1);
|
||||
e2 = evalExpr(state, e2);
|
||||
|
||||
ATermList as;
|
||||
ATerm p;
|
||||
if (matchAttrs(e1, as) && matchPath(e2, p)) {
|
||||
static bool haveWarned = false;
|
||||
warnOnce(haveWarned, format(
|
||||
"concatenation of a derivation and a path is deprecated; "
|
||||
"you should write `drv + \"%1%\"' instead of `drv + %1%'")
|
||||
% aterm2String(p));
|
||||
PathSet context;
|
||||
return makeStr(
|
||||
coerceToString(state, makeSelect(e1, toATerm("outPath")), context)
|
||||
+ aterm2String(p), context);
|
||||
}
|
||||
|
||||
args.push_back(e1);
|
||||
args.push_back(e2);
|
||||
}
|
||||
|
||||
else if (matchConcatStrings(e, es))
|
||||
for (ATermIterator i(es); i; ++i) args.push_back(*i);
|
||||
|
||||
try {
|
||||
return concatStrings(state, args);
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "in a string concatenation:\n");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalSubPath(EvalState & state, Expr e1, Expr e2))
|
||||
{
|
||||
static bool haveWarned = false;
|
||||
warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead");
|
||||
ATermVector args;
|
||||
args.push_back(e1);
|
||||
args.push_back(e2);
|
||||
return concatStrings(state, args, "/");
|
||||
}
|
||||
|
||||
|
||||
LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2))
|
||||
{
|
||||
try {
|
||||
ATermList l1 = evalList(state, e1);
|
||||
ATermList l2 = evalList(state, e2);
|
||||
return makeList(ATconcat(l1, l2));
|
||||
} catch (Error & e) {
|
||||
addErrorPrefix(e, "in a list concatenation:\n");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char * deepestStack = (char *) -1; /* for measuring stack usage */
|
||||
|
||||
|
||||
Expr evalExpr2(EvalState & state, Expr e)
|
||||
{
|
||||
Expr e1, e2, e3, e4;
|
||||
/* When changing this function, make sure that you don't cause a
|
||||
(large) increase in stack consumption! */
|
||||
|
||||
char x;
|
||||
if (&x < deepestStack) deepestStack = &x;
|
||||
|
||||
Expr e1, e2, e3;
|
||||
ATerm name, pos;
|
||||
AFun sym = ATgetAFun(e);
|
||||
|
||||
/* Normal forms. */
|
||||
if (sym == symStr ||
|
||||
sym == symPath ||
|
||||
sym == symUri ||
|
||||
sym == symNull ||
|
||||
sym == symInt ||
|
||||
sym == symBool ||
|
||||
@@ -350,8 +636,7 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||
sym == symFunction1 ||
|
||||
sym == symAttrs ||
|
||||
sym == symList ||
|
||||
sym == symPrimOp ||
|
||||
sym == symContext)
|
||||
sym == symPrimOp)
|
||||
return e;
|
||||
|
||||
/* The `Closed' constructor is just a way to prevent substitutions
|
||||
@@ -361,89 +646,13 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||
|
||||
/* Any encountered variables must be primops (since undefined
|
||||
variables are detected after parsing). */
|
||||
if (matchVar(e, name)) {
|
||||
ATerm primOp = state.primOps.get(name);
|
||||
if (!primOp)
|
||||
throw EvalError(format("impossible: undefined variable `%1%'") % aterm2String(name));
|
||||
int arity;
|
||||
ATermBlob fun;
|
||||
if (!matchPrimOpDef(primOp, arity, fun)) abort();
|
||||
if (arity == 0)
|
||||
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
|
||||
else
|
||||
return makePrimOp(arity, fun, ATempty);
|
||||
}
|
||||
if (matchVar(e, name)) return evalVar(state, name);
|
||||
|
||||
/* Function application. */
|
||||
if (matchCall(e, e1, e2)) {
|
||||
|
||||
ATermList formals;
|
||||
ATerm pos;
|
||||
|
||||
/* Evaluate the left-hand side. */
|
||||
e1 = evalExpr(state, e1);
|
||||
|
||||
/* Is it a primop or a function? */
|
||||
int arity;
|
||||
ATermBlob fun;
|
||||
ATermList args;
|
||||
if (matchPrimOp(e1, arity, fun, args)) {
|
||||
args = ATinsert(args, e2);
|
||||
if (ATgetLength(args) == arity) {
|
||||
/* Put the arguments in a vector in reverse (i.e.,
|
||||
actual) order. */
|
||||
ATermVector args2(arity);
|
||||
for (ATermIterator i(args); i; ++i)
|
||||
args2[--arity] = *i;
|
||||
return ((PrimOp) ATgetBlobData((ATermBlob) fun))
|
||||
(state, args2);
|
||||
} else
|
||||
/* Need more arguments, so propagate the primop. */
|
||||
return makePrimOp(arity, fun, args);
|
||||
}
|
||||
|
||||
else if (matchFunction(e1, formals, e4, pos)) {
|
||||
e2 = evalExpr(state, e2);
|
||||
try {
|
||||
return evalExpr(state, substArgs(state, e4, formals, e2));
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the function at %1%:\n")
|
||||
% showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
else if (matchFunction1(e1, name, e4, pos)) {
|
||||
try {
|
||||
ATermMap subs(1);
|
||||
subs.set(name, e2);
|
||||
return evalExpr(state, substitute(Substitution(0, &subs), e4));
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the function at %1%:\n")
|
||||
% showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
else throw TypeError(
|
||||
format("the left-hand side of the function call is neither a function nor a primop (built-in operation) but %1%")
|
||||
% showType(e1));
|
||||
}
|
||||
if (matchCall(e, e1, e2)) return evalCall(state, e1, e2);
|
||||
|
||||
/* Attribute selection. */
|
||||
if (matchSelect(e, e1, name)) {
|
||||
ATerm pos;
|
||||
string s1 = aterm2String(name);
|
||||
Expr a = queryAttr(evalExpr(state, e1), s1, pos);
|
||||
if (!a) throw EvalError(format("attribute `%1%' missing") % s1);
|
||||
try {
|
||||
return evalExpr(state, a);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the attribute `%1%' at %2%:\n")
|
||||
% s1 % showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (matchSelect(e, e1, name)) return evalSelect(state, e1, name);
|
||||
|
||||
/* Mutually recursive sets. */
|
||||
ATermList rbnds, nrbnds;
|
||||
@@ -451,41 +660,14 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||
return expandRec(e, rbnds, nrbnds);
|
||||
|
||||
/* Conditionals. */
|
||||
if (matchIf(e, e1, e2, e3)) {
|
||||
if (evalBool(state, e1))
|
||||
return evalExpr(state, e2);
|
||||
else
|
||||
return evalExpr(state, e3);
|
||||
}
|
||||
if (matchIf(e, e1, e2, e3))
|
||||
return evalExpr(state, evalBool(state, e1) ? e2 : e3);
|
||||
|
||||
/* Assertions. */
|
||||
if (matchAssert(e, e1, e2, pos)) {
|
||||
if (!evalBool(state, e1))
|
||||
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
|
||||
return evalExpr(state, e2);
|
||||
}
|
||||
if (matchAssert(e, e1, e2, pos)) return evalAssert(state, e1, e2, pos);
|
||||
|
||||
/* Withs. */
|
||||
if (matchWith(e, e1, e2, pos)) {
|
||||
ATermMap attrs(128); /* !!! */
|
||||
try {
|
||||
e1 = evalExpr(state, e1);
|
||||
queryAllAttrs(e1, attrs);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the `with' definitions at %1%:\n")
|
||||
% showPos(pos));
|
||||
throw;
|
||||
}
|
||||
try {
|
||||
e2 = substitute(Substitution(0, &attrs), e2);
|
||||
checkVarDefs(state.primOps, e2);
|
||||
return evalExpr(state, e2);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the `with' body at %1%:\n")
|
||||
% showPos(pos));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (matchWith(e, e1, e2, pos)) return evalWith(state, e1, e2, pos);
|
||||
|
||||
/* Generic equality/inequality. Note that the behaviour on
|
||||
composite data (lists, attribute sets) and functions is
|
||||
@@ -520,64 +702,31 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||
return updateAttrs(evalExpr(state, e1), evalExpr(state, e2));
|
||||
|
||||
/* Attribute existence test (?). */
|
||||
if (matchOpHasAttr(e, e1, name)) {
|
||||
ATermMap attrs(128); /* !!! */
|
||||
queryAllAttrs(evalExpr(state, e1), attrs);
|
||||
return makeBool(attrs.get(name) != 0);
|
||||
}
|
||||
if (matchOpHasAttr(e, e1, name)) return evalHasAttr(state, e1, name);
|
||||
|
||||
/* String or path concatenation. */
|
||||
ATermList es = ATempty;
|
||||
if (matchOpPlus(e, e1, e2) || matchConcatStrings(e, es)) {
|
||||
ATermVector args;
|
||||
if (matchOpPlus(e, e1, e2)) {
|
||||
args.push_back(e1);
|
||||
args.push_back(e2);
|
||||
} else
|
||||
for (ATermIterator i(es); i; ++i) args.push_back(*i);
|
||||
|
||||
try {
|
||||
return concatStrings(state, args);
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("in a string concatenation:\n"));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (sym == symOpPlus || sym == symConcatStrings)
|
||||
return evalPlusConcat(state, e);
|
||||
|
||||
/* Backwards compatability: subpath operator (~). */
|
||||
if (matchSubPath(e, e1, e2)) {
|
||||
static bool haveWarned = false;
|
||||
warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead");
|
||||
ATermList context = ATempty;
|
||||
bool dummy;
|
||||
string s1 = coerceToStringWithContext(state, context, e1, dummy);
|
||||
string s2 = coerceToStringWithContext(state, context, e2, dummy);
|
||||
return wrapInContext(context, makePath(toATerm(canonPath(s1 + "/" + s2))));
|
||||
}
|
||||
if (matchSubPath(e, e1, e2)) return evalSubPath(state, e1, e2);
|
||||
|
||||
/* List concatenation. */
|
||||
if (matchOpConcat(e, e1, e2)) {
|
||||
try {
|
||||
ATermList l1 = evalList(state, e1);
|
||||
ATermList l2 = evalList(state, e2);
|
||||
return makeList(ATconcat(l1, l2));
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("in a list concatenation:\n"));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if (matchOpConcat(e, e1, e2)) return evalOpConcat(state, e1, e2);
|
||||
|
||||
/* Barf. */
|
||||
throw badTerm("invalid expression", e);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
Expr evalExpr(EvalState & state, Expr e)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
|
||||
#if 0
|
||||
startNest(nest, lvlVomit,
|
||||
format("evaluating expression: %1%") % e);
|
||||
#endif
|
||||
|
||||
state.nrEvaluated++;
|
||||
|
||||
@@ -586,7 +735,7 @@ Expr evalExpr(EvalState & state, Expr e)
|
||||
Expr nf = state.normalForms.get(e);
|
||||
if (nf) {
|
||||
if (nf == makeBlackHole())
|
||||
throw EvalError("infinite recursion encountered");
|
||||
throwEvalError("infinite recursion encountered");
|
||||
state.nrCached++;
|
||||
return nf;
|
||||
}
|
||||
@@ -596,7 +745,6 @@ Expr evalExpr(EvalState & state, Expr e)
|
||||
try {
|
||||
nf = evalExpr2(state, e);
|
||||
} catch (Error & err) {
|
||||
debug("removing black hole");
|
||||
state.normalForms.remove(e);
|
||||
throw;
|
||||
}
|
||||
@@ -619,7 +767,10 @@ Expr evalFile(EvalState & state, const Path & path)
|
||||
}
|
||||
|
||||
|
||||
Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
|
||||
static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs);
|
||||
|
||||
|
||||
static Expr strictEvalExpr_(EvalState & state, Expr e, ATermMap & nfs)
|
||||
{
|
||||
e = evalExpr(state, e);
|
||||
|
||||
@@ -629,10 +780,8 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
|
||||
for (ATermIterator i(as); i; ++i) {
|
||||
ATerm name; Expr e; ATerm pos;
|
||||
if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
|
||||
as2 = ATinsert(as2, makeBind(name, strictEvalExpr(state, e, canonicalise),
|
||||
canonicalise ? makeNoPos() : pos));
|
||||
as2 = ATinsert(as2, makeBind(name, strictEvalExpr(state, e, nfs), pos));
|
||||
}
|
||||
/* !!! sort attributes if canonicalise == true */
|
||||
return makeAttrs(ATreverse(as2));
|
||||
}
|
||||
|
||||
@@ -640,7 +789,7 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
|
||||
if (matchList(e, es)) {
|
||||
ATermList es2 = ATempty;
|
||||
for (ATermIterator i(es); i; ++i)
|
||||
es2 = ATinsert(es2, strictEvalExpr(state, *i, canonicalise));
|
||||
es2 = ATinsert(es2, strictEvalExpr(state, *i, nfs));
|
||||
return makeList(ATreverse(es2));
|
||||
}
|
||||
|
||||
@@ -657,20 +806,40 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
|
||||
if (matchValidValues(valids, valids2)) {
|
||||
ATermList valids3 = ATempty;
|
||||
for (ATermIterator j(valids2); j; ++j)
|
||||
valids3 = ATinsert(valids3, strictEvalExpr(state, *j, canonicalise));
|
||||
valids3 = ATinsert(valids3, strictEvalExpr(state, *j, nfs));
|
||||
valids = makeValidValues(ATreverse(valids3));
|
||||
}
|
||||
|
||||
formals2 = ATinsert(formals2, makeFormal(name, valids, dummy));
|
||||
}
|
||||
return makeFunction(ATreverse(formals2), body,
|
||||
canonicalise ? makeNoPos() : pos);
|
||||
|
||||
return makeFunction(ATreverse(formals2), body, pos);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs)
|
||||
{
|
||||
Expr nf = nfs.get(e);
|
||||
if (nf) return nf;
|
||||
|
||||
nf = strictEvalExpr_(state, e, nfs);
|
||||
|
||||
nfs.set(e, nf);
|
||||
|
||||
return nf;
|
||||
}
|
||||
|
||||
|
||||
Expr strictEvalExpr(EvalState & state, Expr e)
|
||||
{
|
||||
ATermMap strictNormalForms;
|
||||
return strictEvalExpr(state, e, strictNormalForms);
|
||||
}
|
||||
|
||||
|
||||
/* Yes, this is a really bad idea... */
|
||||
extern "C" {
|
||||
unsigned long AT_calcAllocatedSize();
|
||||
@@ -678,12 +847,14 @@ extern "C" {
|
||||
|
||||
void printEvalStats(EvalState & state)
|
||||
{
|
||||
char x;
|
||||
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
|
||||
printMsg(showStats ? lvlInfo : lvlDebug,
|
||||
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes")
|
||||
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space")
|
||||
% state.nrEvaluated % state.nrCached
|
||||
% ((float) state.nrCached / (float) state.nrEvaluated * 100)
|
||||
% AT_calcAllocatedSize());
|
||||
% AT_calcAllocatedSize()
|
||||
% (&x - deepestStack));
|
||||
if (showStats)
|
||||
printATermMapStats();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Hash;
|
||||
typedef std::map<Path, PathSet> DrvRoots;
|
||||
typedef std::map<Path, Hash> DrvHashes;
|
||||
|
||||
/* Cache for calls to addToStore(); maps source paths to the store
|
||||
/* Cache for calls to addToStore(); maps source paths to the store //THIS OK ????
|
||||
paths. */
|
||||
typedef std::map<Path, Path> SrcToStore;
|
||||
|
||||
@@ -56,21 +56,29 @@ Expr evalFile(EvalState & state, const Path & path);
|
||||
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,
|
||||
bool canonicalise = false);
|
||||
Expr strictEvalExpr(EvalState & state, Expr e);
|
||||
|
||||
/* Specific results. */
|
||||
string evalString(EvalState & state, Expr e);
|
||||
Path evalPath(EvalState & state, Expr e);
|
||||
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);
|
||||
ATerm coerceToString(Expr e);
|
||||
|
||||
/* Contexts. */
|
||||
string coerceToStringWithContext(EvalState & state,
|
||||
ATermList & context, Expr e, bool & isPath);
|
||||
Expr wrapInContext(ATermList context, 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,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "xml-writer.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "aterm.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
@@ -15,29 +16,45 @@ static XMLAttrs singletonAttrs(const string & name, const string & value)
|
||||
}
|
||||
|
||||
|
||||
static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
|
||||
/* 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;
|
||||
ATerm s;
|
||||
string s;
|
||||
ATerm s2;
|
||||
int i;
|
||||
Expr e2;
|
||||
ATermList as, es, formals;
|
||||
ATerm body, pos;
|
||||
|
||||
while (matchContext(e, es, e2)) {
|
||||
e = e2;
|
||||
for (ATermIterator i(es); i; ++i)
|
||||
context = ATinsert(context, *i);
|
||||
}
|
||||
checkInterrupt();
|
||||
|
||||
if (matchStr(e, s))
|
||||
doc.writeEmptyElement("string", singletonAttrs("value", aterm2String(s)));
|
||||
if (matchStr(e, s, context)) /* !!! show the context? */
|
||||
doc.writeEmptyElement("string", singletonAttrs("value", s));
|
||||
|
||||
else if (matchPath(e, s))
|
||||
doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s)));
|
||||
|
||||
else if (matchUri(e, s))
|
||||
doc.writeEmptyElement("uri", singletonAttrs("value", aterm2String(s)));
|
||||
else if (matchPath(e, s2))
|
||||
doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s2)));
|
||||
|
||||
else if (matchNull(e))
|
||||
doc.writeEmptyElement("null");
|
||||
@@ -52,22 +69,42 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
|
||||
doc.writeEmptyElement("bool", singletonAttrs("value", "false"));
|
||||
|
||||
else if (matchAttrs(e, as)) {
|
||||
XMLOpenElement _(doc, "attrs");
|
||||
ATermMap attrs(128);
|
||||
ATermMap attrs;
|
||||
queryAllAttrs(e, attrs);
|
||||
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);
|
||||
|
||||
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);
|
||||
printTermAsXML(*i, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
else if (matchFunction(e, formals, body, pos)) {
|
||||
@@ -82,7 +119,7 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
|
||||
if (matchValidValues(valids, valids2)) {
|
||||
for (ATermIterator j(valids2); j; ++j) {
|
||||
XMLOpenElement _(doc, "value");
|
||||
printTermAsXML(*j, doc, context);
|
||||
printTermAsXML(*j, doc, context, drvsSeen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,11 +130,12 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
|
||||
}
|
||||
|
||||
|
||||
void printTermAsXML(Expr e, std::ostream & out, ATermList & context)
|
||||
void printTermAsXML(Expr e, std::ostream & out, PathSet & context)
|
||||
{
|
||||
XMLWriter doc(true, out);
|
||||
XMLOpenElement root(doc, "expr");
|
||||
printTermAsXML(e, doc, context);
|
||||
ExprSet drvsSeen;
|
||||
printTermAsXML(e, doc, context, drvsSeen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
void printTermAsXML(Expr e, std::ostream & out, ATermList & context);
|
||||
void printTermAsXML(Expr e, std::ostream & out, PathSet & context);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,15 @@ string DrvInfo::queryDrvPath(EvalState & state) const
|
||||
{
|
||||
if (drvPath == "") {
|
||||
Expr a = attrs->get(toATerm("drvPath"));
|
||||
(string &) drvPath = a ? evalPath(state, a) : "";
|
||||
|
||||
/* 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);
|
||||
|
||||
PathSet context;
|
||||
(string &) drvPath = a ? coerceToPath(state, a, context) : "";
|
||||
}
|
||||
return drvPath;
|
||||
}
|
||||
@@ -21,11 +29,59 @@ string DrvInfo::queryOutPath(EvalState & state) const
|
||||
if (outPath == "") {
|
||||
Expr a = attrs->get(toATerm("outPath"));
|
||||
if (!a) throw TypeError("output path missing");
|
||||
(string &) outPath = evalPath(state, a);
|
||||
PathSet context;
|
||||
(string &) outPath = coerceToPath(state, a, context);
|
||||
}
|
||||
return outPath;
|
||||
}
|
||||
|
||||
string DrvInfo::queryStateIdentifier(EvalState & state) const
|
||||
{
|
||||
if (stateIdentifier == "") {
|
||||
ATermMap attrs2 = *attrs;
|
||||
|
||||
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
|
||||
|
||||
string key = (string)aterm2String(i->key); //cast because aterm2String returns a char*
|
||||
//printMsg(lvlError, format("ATTR2: '%1%'") % key);
|
||||
if(key == "stateIdentifier"){
|
||||
PathSet context;
|
||||
string value = coerceToString(state, i->value, context);
|
||||
(string &) stateIdentifier = value;
|
||||
}
|
||||
}
|
||||
|
||||
//If still empty
|
||||
if (trim(stateIdentifier) == "")
|
||||
(string &) stateIdentifier = "__NOSTATE__";
|
||||
}
|
||||
|
||||
return stateIdentifier;
|
||||
}
|
||||
|
||||
string DrvInfo::queryRuntimeStateArgs(EvalState & state) const
|
||||
{
|
||||
if (runtimeStateArgs == "") {
|
||||
ATermMap attrs2 = *attrs;
|
||||
|
||||
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
|
||||
|
||||
string key = (string)aterm2String(i->key); //cast because aterm2String returns a char*
|
||||
if(key == "runtimeStateArgs"){
|
||||
PathSet context;
|
||||
string value = coerceToString(state, i->value, context);
|
||||
(string &) runtimeStateArgs = value;
|
||||
}
|
||||
}
|
||||
|
||||
//If still empty
|
||||
if (trim(runtimeStateArgs) == "")
|
||||
(string &) runtimeStateArgs = "__NOARGS__";
|
||||
}
|
||||
|
||||
return runtimeStateArgs;
|
||||
}
|
||||
|
||||
|
||||
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||
{
|
||||
@@ -34,13 +90,15 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||
Expr a = attrs->get(toATerm("meta"));
|
||||
if (!a) return meta; /* fine, empty meta information */
|
||||
|
||||
ATermMap attrs2(16); /* !!! */
|
||||
ATermMap attrs2;
|
||||
queryAllAttrs(evalExpr(state, a), attrs2);
|
||||
|
||||
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
|
||||
ATerm s = coerceToString(evalExpr(state, i->value));
|
||||
if (s)
|
||||
meta[aterm2String(i->key)] = aterm2String(s);
|
||||
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. */
|
||||
}
|
||||
@@ -49,6 +107,25 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||
}
|
||||
|
||||
|
||||
string 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;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
@@ -70,32 +147,37 @@ static bool getDerivation(EvalState & state, Expr e,
|
||||
e = evalExpr(state, e);
|
||||
if (!matchAttrs(e, es)) return true;
|
||||
|
||||
boost::shared_ptr<ATermMap> attrs(new ATermMap(32)); /* !!! */
|
||||
boost::shared_ptr<ATermMap> attrs(new ATermMap());
|
||||
queryAllAttrs(e, *attrs, false);
|
||||
|
||||
|
||||
Expr a = attrs->get(toATerm("type"));
|
||||
if (!a || evalString(state, a) != "derivation") return true;
|
||||
if (!a || evalStringNoCtx(state, a) != "derivation")
|
||||
return true;
|
||||
|
||||
/* Remove spurious duplicates (e.g., an attribute set like
|
||||
`rec { x = derivation {...}; y = x;}'. */
|
||||
if (doneExprs.find(e) != doneExprs.end()) return false;
|
||||
if (doneExprs.find(e) != doneExprs.end())
|
||||
return false;
|
||||
doneExprs.insert(e);
|
||||
|
||||
DrvInfo drv;
|
||||
|
||||
a = attrs->get(toATerm("name"));
|
||||
/* !!! We really would like to have a decent back trace here. */
|
||||
if (!a) throw TypeError("derivation name missing");
|
||||
drv.name = evalString(state, a);
|
||||
if (!a)
|
||||
throw TypeError("derivation name missing");
|
||||
drv.name = evalStringNoCtx(state, a);
|
||||
|
||||
a = attrs->get(toATerm("system"));
|
||||
if (!a)
|
||||
drv.system = "unknown";
|
||||
else
|
||||
drv.system = evalString(state, a);
|
||||
drv.system = evalStringNoCtx(state, a);
|
||||
|
||||
drv.attrs = attrs;
|
||||
|
||||
|
||||
//printMsg(lvlError, format("TEST '%1%'") % evalStringNoCtx(state, a) );
|
||||
|
||||
drv.attrPath = attrPath;
|
||||
|
||||
drvs.push_back(drv);
|
||||
@@ -112,7 +194,8 @@ bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
|
||||
Exprs doneExprs;
|
||||
DrvInfos drvs;
|
||||
getDerivation(state, e, "", drvs, doneExprs);
|
||||
if (drvs.size() != 1) return false;
|
||||
if (drvs.size() != 1)
|
||||
return false;
|
||||
drv = drvs.front();
|
||||
return true;
|
||||
}
|
||||
@@ -140,12 +223,21 @@ static void getDerivations(EvalState & state, Expr e,
|
||||
if (matchAttrs(e, es)) {
|
||||
ATermMap drvMap(ATgetLength(es));
|
||||
queryAllAttrs(e, drvMap);
|
||||
|
||||
/* !!! 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 (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
|
||||
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)) {
|
||||
/* If the value of this attribute is itself an
|
||||
attribute set, should we recurse into it? => Only
|
||||
if it has a `recurseForDerivations = true'
|
||||
@@ -155,8 +247,8 @@ static void getDerivations(EvalState & state, Expr e,
|
||||
if (matchAttrs(e, es)) {
|
||||
ATermMap attrs(ATgetLength(es));
|
||||
queryAllAttrs(e, attrs, false);
|
||||
Expr e2 = attrs.get(toATerm("recurseForDerivations"));
|
||||
if (e2 && evalBool(state, e2))
|
||||
if (((e2 = attrs.get(toATerm("recurseForDerivations")))
|
||||
&& evalBool(state, e2)))
|
||||
getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,17 +20,25 @@ struct DrvInfo
|
||||
private:
|
||||
string drvPath;
|
||||
string outPath;
|
||||
string stateIdentifier;
|
||||
string runtimeStateArgs;
|
||||
|
||||
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;
|
||||
|
||||
string queryDrvPath(EvalState & state) const;
|
||||
string queryOutPath(EvalState & state) const;
|
||||
string queryStateIdentifier(EvalState & state) const;
|
||||
string queryRuntimeStateArgs(EvalState & state) const;
|
||||
MetaInfo queryMetaInfo(EvalState & state) const;
|
||||
string queryMetaInfo(EvalState & state, const string & name) const;
|
||||
|
||||
void setDrvPath(const string & s)
|
||||
{
|
||||
@@ -41,6 +49,18 @@ public:
|
||||
{
|
||||
outPath = s;
|
||||
}
|
||||
|
||||
void setStateIdentifier(const string & s)
|
||||
{
|
||||
stateIdentifier = s;
|
||||
}
|
||||
|
||||
void setRuntimeStateArgs(const string & s)
|
||||
{
|
||||
runtimeStateArgs = s;
|
||||
}
|
||||
|
||||
void setMetaInfo(const MetaInfo & meta);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
%x STRING
|
||||
%x IND_STRING
|
||||
|
||||
|
||||
%{
|
||||
@@ -64,7 +65,7 @@ static Expr unescapeStr(const char * s)
|
||||
}
|
||||
else t += c;
|
||||
}
|
||||
return makeStr(toATerm(t));
|
||||
return makeStr(toATerm(t), ATempty);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +123,30 @@ inherit { return INHERIT; }
|
||||
<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->t = makeIndStr(toATerm(yytext));
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\$ {
|
||||
yylval->t = makeIndStr(toATerm("$"));
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\' {
|
||||
yylval->t = makeIndStr(toATerm("''"));
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\'\'\\. {
|
||||
yylval->t = unescapeStr(yytext + 2);
|
||||
return IND_STR;
|
||||
}
|
||||
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
||||
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
|
||||
<IND_STRING>\' {
|
||||
yylval->t = makeIndStr(toATerm("'"));
|
||||
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 */ }
|
||||
@@ -148,4 +173,10 @@ void backToString(yyscan_t scanner)
|
||||
BEGIN(STRING);
|
||||
}
|
||||
|
||||
void backToIndString(yyscan_t scanner)
|
||||
{
|
||||
struct yyguts_t * yyg = (struct yyguts_t *) scanner;
|
||||
BEGIN(IND_STRING);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,9 +24,41 @@ Call | Expr Expr | Expr |
|
||||
Select | Expr string | Expr |
|
||||
Var | string | Expr |
|
||||
Int | int | Expr |
|
||||
Str | string | 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
|
||||
|
||||
# Internal to the parser, doesn't occur in ASTs.
|
||||
IndStr | string | Expr |
|
||||
|
||||
# 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 |
|
||||
Uri | string | Expr |
|
||||
|
||||
List | ATermList | Expr |
|
||||
BlackHole | | Expr |
|
||||
Undefined | | Expr |
|
||||
@@ -37,10 +69,9 @@ Closed | Expr | Expr |
|
||||
Rec | ATermList ATermList | Expr |
|
||||
Bool | ATerm | Expr |
|
||||
Null | | Expr |
|
||||
Context | ATermList Expr | Expr |
|
||||
|
||||
Bind | string Expr Pos | ATerm |
|
||||
Bind | string Expr | ATerm | Bind2
|
||||
Bind | string Expr | ATerm | ObsoleteBind
|
||||
Inherit | Expr ATermList Pos | ATerm |
|
||||
|
||||
Scope | | Expr |
|
||||
|
||||
@@ -54,7 +54,7 @@ void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
|
||||
{
|
||||
ATermList bnds;
|
||||
if (!matchAttrs(e, bnds))
|
||||
throw TypeError("attribute set expected");
|
||||
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
|
||||
|
||||
for (ATermIterator i(bnds); i; ++i) {
|
||||
ATerm name;
|
||||
@@ -77,7 +77,7 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos)
|
||||
{
|
||||
ATermList bnds;
|
||||
if (!matchAttrs(e, bnds))
|
||||
throw TypeError("attribute set expected");
|
||||
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
|
||||
|
||||
for (ATermIterator i(bnds); i; ++i) {
|
||||
ATerm name2, pos2;
|
||||
@@ -215,7 +215,11 @@ static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
|
||||
ATerm with, body;
|
||||
ATermList rbnds, nrbnds;
|
||||
|
||||
if (matchVar(e, name)) {
|
||||
/* Closed terms don't have free variables, so we don't have to
|
||||
check by definition. */
|
||||
if (matchClosed(e, value)) return;
|
||||
|
||||
else if (matchVar(e, name)) {
|
||||
if (!defs.get(name))
|
||||
throw EvalError(format("undefined variable `%1%'")
|
||||
% aterm2String(name));
|
||||
@@ -287,21 +291,81 @@ void checkVarDefs(const ATermMap & defs, Expr 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);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Expr canonicaliseExpr(Expr e)
|
||||
{
|
||||
Canonicalise canonicalise;
|
||||
return bottomupRewrite(canonicalise, e);
|
||||
}
|
||||
|
||||
|
||||
Expr makeBool(bool b)
|
||||
{
|
||||
return b ? eTrue : eFalse;
|
||||
}
|
||||
|
||||
|
||||
bool matchStr(Expr e, string & s, PathSet & context)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Expr makeStr(const string & s, const PathSet & context)
|
||||
{
|
||||
return makeStr(toATerm(s), toATermList(context));
|
||||
}
|
||||
|
||||
|
||||
string showType(Expr e)
|
||||
{
|
||||
ATerm t1, t2, t3;
|
||||
ATermList l1;
|
||||
ATermBlob b1;
|
||||
int i1;
|
||||
if (matchStr(e, t1)) return "a string";
|
||||
if (matchStr(e, t1, l1)) return "a string";
|
||||
if (matchPath(e, t1)) return "a path";
|
||||
if (matchUri(e, t1)) return "a path";
|
||||
if (matchNull(e)) return "null";
|
||||
if (matchInt(e, i1)) return "an integer";
|
||||
if (matchBool(e, t1)) return "a boolean";
|
||||
@@ -310,18 +374,19 @@ string showType(Expr e)
|
||||
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";
|
||||
if (matchContext(e, l1, t1)) return "a context containing " + showType(t1);
|
||||
return "an unknown type";
|
||||
}
|
||||
|
||||
|
||||
string showValue(Expr e)
|
||||
{
|
||||
ATerm s;
|
||||
PathSet context;
|
||||
string s;
|
||||
ATerm s2;
|
||||
int i;
|
||||
if (matchStr(e, s)) {
|
||||
string t = aterm2String(s), u;
|
||||
for (string::iterator i = t.begin(); i != t.end(); ++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";
|
||||
@@ -329,8 +394,7 @@ string showValue(Expr e)
|
||||
else u += *i;
|
||||
return "\"" + u + "\"";
|
||||
}
|
||||
if (matchPath(e, s)) return aterm2String(s);
|
||||
if (matchUri(e, s)) return aterm2String(s);
|
||||
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";
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace nix {
|
||||
|
||||
MakeError(EvalError, Error)
|
||||
MakeError(AssertionError, EvalError)
|
||||
MakeError(ThrownError, AssertionError)
|
||||
MakeError(Abort, EvalError)
|
||||
MakeError(TypeError, EvalError)
|
||||
|
||||
@@ -71,6 +72,7 @@ struct TermFun
|
||||
};
|
||||
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);
|
||||
@@ -83,16 +85,33 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos);
|
||||
/* Create an attribute set expression from an Attrs value. */
|
||||
Expr makeAttrs(const ATermMap & attrs);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
%locations
|
||||
%error-verbose
|
||||
%defines
|
||||
%no-lines
|
||||
/* %no-lines */
|
||||
%parse-param { yyscan_t scanner }
|
||||
%parse-param { ParseData * data }
|
||||
%lex-param { yyscan_t scanner }
|
||||
@@ -68,9 +68,100 @@ static Expr fixAttrs(int recursive, ATermList as)
|
||||
}
|
||||
|
||||
|
||||
void backToString(yyscan_t scanner);
|
||||
static Expr stripIndentation(ATermList es)
|
||||
{
|
||||
if (es == ATempty) return makeStr("");
|
||||
|
||||
/* 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;
|
||||
ATerm e;
|
||||
for (ATermIterator i(es); i; ++i) {
|
||||
if (!matchIndStr(*i, e)) {
|
||||
/* Anti-quotations end the current start-of-line whitespace. */
|
||||
if (atStartOfLine) {
|
||||
atStartOfLine = false;
|
||||
if (curIndent < minIndent) minIndent = curIndent;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
string s = aterm2String(e);
|
||||
for (unsigned int j = 0; j < s.size(); ++j) {
|
||||
if (atStartOfLine) {
|
||||
if (s[j] == ' ')
|
||||
curIndent++;
|
||||
else if (s[j] == '\n') {
|
||||
/* Empty line, doesn't influence minimum
|
||||
indentation. */
|
||||
curIndent = 0;
|
||||
} else {
|
||||
atStartOfLine = false;
|
||||
if (curIndent < minIndent) minIndent = curIndent;
|
||||
}
|
||||
} else if (s[j] == '\n') {
|
||||
atStartOfLine = true;
|
||||
curIndent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip spaces from each line. */
|
||||
ATermList es2 = ATempty;
|
||||
atStartOfLine = true;
|
||||
unsigned int curDropped = 0;
|
||||
unsigned int n = ATgetLength(es);
|
||||
for (ATermIterator i(es); i; ++i, --n) {
|
||||
if (!matchIndStr(*i, e)) {
|
||||
atStartOfLine = false;
|
||||
curDropped = 0;
|
||||
es2 = ATinsert(es2, *i);
|
||||
continue;
|
||||
}
|
||||
|
||||
string s = aterm2String(e);
|
||||
string s2;
|
||||
for (unsigned int j = 0; j < s.size(); ++j) {
|
||||
if (atStartOfLine) {
|
||||
if (s[j] == ' ') {
|
||||
if (curDropped++ >= minIndent)
|
||||
s2 += s[j];
|
||||
}
|
||||
else if (s[j] == '\n') {
|
||||
curDropped = 0;
|
||||
s2 += s[j];
|
||||
} else {
|
||||
atStartOfLine = false;
|
||||
curDropped = 0;
|
||||
s2 += s[j];
|
||||
}
|
||||
} else {
|
||||
s2 += s[j];
|
||||
if (s[j] == '\n') atStartOfLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the last line if it is empty and consists only of
|
||||
spaces. */
|
||||
if (n == 1) {
|
||||
unsigned int 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 = ATinsert(es2, makeStr(s2));
|
||||
}
|
||||
|
||||
return makeConcatStrings(ATreverse(es2));
|
||||
}
|
||||
|
||||
|
||||
void backToString(yyscan_t scanner);
|
||||
void backToIndString(yyscan_t scanner);
|
||||
|
||||
|
||||
|
||||
static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
|
||||
{
|
||||
return makePos(toATerm(data->path),
|
||||
@@ -121,10 +212,11 @@ static void freeAndUnprotect(void * p)
|
||||
|
||||
%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 <ts> binds ids expr_list formals string_parts ind_string_parts
|
||||
%token <t> ID INT STR IND_STR PATH 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
|
||||
|
||||
%nonassoc IMPL
|
||||
%left OR
|
||||
@@ -195,12 +287,15 @@ expr_simple
|
||||
| INT { $$ = makeInt(ATgetInt((ATermInt) $1)); }
|
||||
| '"' string_parts '"' {
|
||||
/* For efficiency, and to simplify parse trees a bit. */
|
||||
if ($2 == ATempty) $$ = makeStr(toATerm(""));
|
||||
if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
|
||||
else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
|
||||
else $$ = makeConcatStrings(ATreverse($2));
|
||||
}
|
||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||
$$ = stripIndentation(ATreverse($2));
|
||||
}
|
||||
| PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); }
|
||||
| URI { $$ = makeUri($1); }
|
||||
| URI { $$ = makeStr($1, ATempty); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
/* Let expressions `let {..., body = ...}' are just desugared
|
||||
into `(rec {..., body = ...}).body'. */
|
||||
@@ -219,6 +314,12 @@ string_parts
|
||||
| { $$ = ATempty; }
|
||||
;
|
||||
|
||||
ind_string_parts
|
||||
: ind_string_parts IND_STR { $$ = ATinsert($1, $2); }
|
||||
| ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = ATinsert($1, $3); }
|
||||
| { $$ = ATempty; }
|
||||
;
|
||||
|
||||
binds
|
||||
: binds bind { $$ = ATinsert($1, $2); }
|
||||
| { $$ = ATempty; }
|
||||
@@ -249,6 +350,7 @@ expr_list
|
||||
formals
|
||||
: formal ',' formals { $$ = ATinsert($3, $1); } /* idem - right recursive */
|
||||
| formal { $$ = ATinsert(ATempty, $1); }
|
||||
| { $$ = ATempty; }
|
||||
;
|
||||
|
||||
formal
|
||||
@@ -358,8 +460,6 @@ static Expr parse(EvalState & state,
|
||||
|
||||
Expr parseExprFromFile(EvalState & state, Path path)
|
||||
{
|
||||
SwitchToOriginalUser sw;
|
||||
|
||||
assert(path[0] == '/');
|
||||
|
||||
#if 0
|
||||
@@ -371,9 +471,12 @@ Expr parseExprFromFile(EvalState & state, Path path)
|
||||
/* If `path' is a symlink, follow it. This is so that relative
|
||||
path references work. */
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting status of `%1%'") % path);
|
||||
if (S_ISLNK(st.st_mode)) path = absPath(readLink(path), dirOf(path));
|
||||
while (true) {
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting status of `%1%'") % path);
|
||||
if (!S_ISLNK(st.st_mode)) break;
|
||||
path = absPath(readLink(path), dirOf(path));
|
||||
}
|
||||
|
||||
/* If `path' refers to a directory, append `/default.nix'. */
|
||||
if (stat(path.c_str(), &st))
|
||||
@@ -381,20 +484,8 @@ Expr parseExprFromFile(EvalState & state, Path path)
|
||||
if (S_ISDIR(st.st_mode))
|
||||
path = canonPath(path + "/default.nix");
|
||||
|
||||
/* Read the input file. We can't use SGparseFile() because it's
|
||||
broken, so we read the input ourselves and call
|
||||
SGparseString(). */
|
||||
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
|
||||
if (fd == -1) throw SysError(format("opening `%1%'") % path);
|
||||
|
||||
if (fstat(fd, &st) == -1)
|
||||
throw SysError(format("statting `%1%'") % path);
|
||||
|
||||
char text[st.st_size + 1];
|
||||
readFull(fd, (unsigned char *) text, st.st_size);
|
||||
text[st.st_size] = 0;
|
||||
|
||||
return parse(state, text, path, dirOf(path));
|
||||
/* Read and parse the input file. */
|
||||
return parse(state, readFile(path).c_str(), path, dirOf(path));
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
17
src/libext3cow/Makefile.am
Normal file
17
src/libext3cow/Makefile.am
Normal file
@@ -0,0 +1,17 @@
|
||||
pkglib_LTLIBRARIES = libext3cow.la
|
||||
|
||||
libext3cow_la_SOURCES = epoch2date.c snapshot.cc tt.c ext3cow_tools.h ext3cow_fs.h
|
||||
|
||||
pkginclude_HEADERS = snapshot.hh
|
||||
|
||||
#TODO linux kernel header
|
||||
|
||||
libext3cow_la_LIBADD = ../libutil/libutil.la \
|
||||
../boost/format/libformat.la
|
||||
|
||||
AM_CXXFLAGS = -Wall \
|
||||
-I$(srcdir)/.. ${aterm_include} \
|
||||
-I$(srcdir)/../libutil
|
||||
|
||||
AM_CFLAGS = \
|
||||
${aterm_include}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user