Compare commits
158 Commits
thread-saf
...
state
| 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 |
10
Makefile.am
10
Makefile.am
@@ -35,20 +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
|
||||
|
||||
45
configure.ac
45
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT(nix, 0.11)
|
||||
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)
|
||||
|
||||
@@ -99,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++)
|
||||
|
||||
|
||||
@@ -114,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)
|
||||
@@ -125,6 +135,7 @@ 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)
|
||||
@@ -139,6 +150,7 @@ 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))
|
||||
@@ -164,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=)
|
||||
@@ -178,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=)
|
||||
@@ -244,6 +273,10 @@ AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
|
||||
AC_CHECK_FUNCS([setresuid setreuid lchown])
|
||||
|
||||
|
||||
# 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
|
||||
@@ -261,7 +294,9 @@ 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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 ...
|
||||
@@ -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
|
||||
|
||||
@@ -263,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>
|
||||
|
||||
|
||||
@@ -153,7 +194,7 @@ $ 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
|
||||
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,69 +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>
|
||||
|
||||
warning: the nix-builders group should contain *only* the Nix
|
||||
builders, and nothing else. If the Nix account is compromised, you
|
||||
can execute programs under the accounts in the nix-builders group, so
|
||||
it obviously shouldn’t contain any “real” user accounts. So don’t use
|
||||
an existing group like <literal>users</literal> — just create a new
|
||||
one.
|
||||
</para>
|
||||
|
||||
-->
|
||||
<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>
|
||||
@@ -11,6 +19,7 @@
|
||||
<command>nix-build</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
|
||||
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
|
||||
@@ -1,6 +1,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>
|
||||
@@ -11,13 +19,7 @@
|
||||
<command>nix-env</command>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
|
||||
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--attr</option></arg>
|
||||
<arg choice='plain'><option>-A</option></arg>
|
||||
</group>
|
||||
<replaceable>attrPath</replaceable>
|
||||
</arg>
|
||||
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
|
||||
<arg>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>--file</option></arg>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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-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>
|
||||
@@ -39,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>
|
||||
@@ -649,36 +657,6 @@ $ 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 xml:id='refsec-nix-store-verify'><title>Operation <option>--verify</option></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>
|
||||
|
||||
@@ -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 knows that it can fetch a pre-built component from
|
||||
package, which is Nix’s mechanism for doing binary deployment. It
|
||||
just means that Nix knows that it can fetch a pre-built package from
|
||||
somewhere (typically a network server) instead of building it
|
||||
locally.</para>
|
||||
|
||||
<para>So now that we have a set of Nix expressions we can build the
|
||||
components contained in them. This is done using <literal>nix-env
|
||||
packages contained in them. This is done using <literal>nix-env
|
||||
-i</literal>. For instance,
|
||||
|
||||
<screen>
|
||||
$ nix-env -f nixpkgs-<replaceable>version</replaceable> -i subversion</screen>
|
||||
|
||||
will install the component called <literal>subversion</literal> (which
|
||||
will install the package called <literal>subversion</literal> (which
|
||||
is, of course, the <link
|
||||
xlink:href='http://subversion.tigris.org/'>Subversion version
|
||||
management system</link>).</para>
|
||||
@@ -112,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,5 +1,6 @@
|
||||
<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>
|
||||
|
||||
@@ -7,80 +8,271 @@
|
||||
|
||||
<!--==================================================================-->
|
||||
|
||||
<section><title>Release 0.11 (TBA)</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>TODO: multi-user support.</para></listitem>
|
||||
<listitem><para>Secure multi-user support. A single Nix store can
|
||||
now be shared between multiple (possible untrusted) users. This is
|
||||
an important feature for NixOS, where it allows non-root users to
|
||||
install software. The old setuid method for sharing a store between
|
||||
multiple users has been removed. Details for setting up a
|
||||
multi-user store can be found in the manual.</para></listitem>
|
||||
|
||||
|
||||
<listitem><para><command>nix-copy-closure</command> copies the
|
||||
missing parts of a closure to or from a remote
|
||||
machine.</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><command>nix-prefetch-url</command> now by default
|
||||
computes the SHA-256 hash of the file instead of the MD5 hash. In
|
||||
calls to <function>fetchurl</function> you should pass an
|
||||
<literal>sha256</literal> attribute instead of
|
||||
<literal>md5</literal>. You can pass either a hexadecimal or a
|
||||
base-32 encoding of the hash.</para></listitem>
|
||||
<listitem><para>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: <varname>allowedReferences</varname> for
|
||||
checking the set of references in the output of a
|
||||
derivation.</para></listitem>
|
||||
|
||||
|
||||
<!--
|
||||
<listitem><para>TODO: semantic cleanups of string concatenation
|
||||
etc. (mostly in r6740).</para></listitem>
|
||||
-->
|
||||
|
||||
|
||||
<listitem><para>TODO: now using Berkeley DB 4.5.</para></listitem>
|
||||
<listitem><para>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>
|
||||
|
||||
|
||||
<listitem><para>TODO: option <option>--reregister</option> in
|
||||
<command>nix-store --register-validity</command>.</para></listitem>
|
||||
<!-- foo
|
||||
<listitem><para>TODO: option <option>- -reregister</option> in
|
||||
<command>nix-store - -register-validity</command>.</para></listitem>
|
||||
-->
|
||||
|
||||
|
||||
<listitem><para>TODO: magic <varname>exportReferencesGraph</varname>
|
||||
attribute.</para></listitem>
|
||||
<listitem><para>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>TODO: option <option>--max-silent-time</option>,
|
||||
configuration setting
|
||||
<literal>build-max-silent-time</literal>.</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>TODO: <command>nix-env</command>
|
||||
<option>--set</option>.</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>TODO: <option>--argstr</option>.</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>TODO: <command>nix-env</command> now maintains meta
|
||||
info about installed packages in user
|
||||
environments.</para></listitem>
|
||||
|
||||
<listitem><para>TODO: <command>nix-env</command>
|
||||
<option>--set-flag</option>.</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>TODO: new built-ins
|
||||
|
||||
<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.sub</function>,
|
||||
<function>builtins.isAttrs</function>,
|
||||
<function>builtins.isFunction</function>,
|
||||
<function>builtins.listToAttrs</function>,
|
||||
<function>builtins.stringLength</function>,
|
||||
<function>builtins.substring</function>.</para></listitem>
|
||||
|
||||
<function>builtins.sub</function>,
|
||||
<function>builtins.substring</function>,
|
||||
<function>throw</function>,
|
||||
<function>builtins.trace</function>,
|
||||
<function>builtins.readFile</function>.</para></listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@ h3 /* subsections */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
|
||||
@@ -4,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>
|
||||
@@ -77,6 +79,46 @@ $ nix-store --verify</screen>
|
||||
</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
12
externals/Makefile.am
vendored
12
externals/Makefile.am
vendored
@@ -35,12 +35,12 @@ endif
|
||||
|
||||
# CWI ATerm
|
||||
|
||||
ATERM = aterm-2.4.2-fixes
|
||||
ATERM = aterm-2.4.2-fixes-r2
|
||||
|
||||
$(ATERM).tar.bz2:
|
||||
@echo "Nix requires the CWI ATerm library to build."
|
||||
@echo "Please download version 2.4.2-fixes from"
|
||||
@echo " http://losser.st-lab.cs.uu.nl/~eelco/dist/aterm-2.4.2-fixes.tar.bz2"
|
||||
@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
|
||||
|
||||
@@ -67,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
|
||||
|
||||
|
||||
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
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
### Option `build-max-silent-time'
|
||||
#
|
||||
# This option defines the maximum number of seconds that builder can
|
||||
# This option defines the maximum number of seconds that a builder can
|
||||
# go without producing any data on standard output or standard error.
|
||||
# This is useful (for instance in a automated build system) to catch
|
||||
# builds that are stuck in an infinite loop, or to catch remote builds
|
||||
@@ -135,6 +135,44 @@
|
||||
#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'
|
||||
#
|
||||
# This option specifies the canonical Nix system name of the current
|
||||
|
||||
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
|
||||
@@ -2,9 +2,10 @@ bin_SCRIPTS = nix-collect-garbage \
|
||||
nix-pull nix-push nix-prefetch-url \
|
||||
nix-install-package nix-channel nix-build \
|
||||
nix-pack-closure nix-unpack-closure \
|
||||
nix-copy-closure
|
||||
nix-copy-closure
|
||||
|
||||
noinst_SCRIPTS = nix-profile.sh generate-patches.pl find-runtime-roots.pl
|
||||
noinst_SCRIPTS = nix-profile.sh generate-patches.pl \
|
||||
find-runtime-roots.pl build-remote.pl nix-reduce-build
|
||||
|
||||
nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl
|
||||
|
||||
@@ -17,6 +18,7 @@ install-exec-local: readmanifest.pm download-using-manifests.pl find-runtime-roo
|
||||
$(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
|
||||
@@ -32,4 +34,6 @@ EXTRA_DIST = nix-collect-garbage.in \
|
||||
generate-patches.pl.in \
|
||||
nix-pack-closure.in nix-unpack-closure.in \
|
||||
nix-copy-closure.in \
|
||||
find-runtime-roots.pl.in
|
||||
find-runtime-roots.pl.in \
|
||||
build-remote.pl.in \
|
||||
nix-reduce-build.in
|
||||
|
||||
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: $?";
|
||||
}
|
||||
@@ -19,18 +19,6 @@ chdir $tmpDir or die "cannot change to `$tmpDir': $!";
|
||||
my $tmpNar = "$tmpDir/nar";
|
||||
my $tmpNar2 = "$tmpDir/nar2";
|
||||
|
||||
END { unlink $tmpNar; unlink $tmpNar2; rmdir $tmpDir; }
|
||||
|
||||
|
||||
# Check the arguments.
|
||||
die unless scalar @ARGV == 1;
|
||||
my $targetPath = $ARGV[0];
|
||||
|
||||
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
|
||||
print LOGFILE "$$ get $targetPath $date\n";
|
||||
|
||||
print "\n*** Trying to download/patch `$targetPath'\n";
|
||||
|
||||
|
||||
# Load all manifests.
|
||||
my %narFiles;
|
||||
@@ -46,6 +34,71 @@ for my $manifest (glob "$manifestDir/*.nixmanifest") {
|
||||
}
|
||||
|
||||
|
||||
# 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";
|
||||
|
||||
print "\n*** Trying to download/patch `$targetPath'\n";
|
||||
|
||||
|
||||
# If we can copy from a local path, do that.
|
||||
my $localPathList = $localPaths{$targetPath};
|
||||
foreach my $localPath (@{$localPathList}) {
|
||||
|
||||
@@ -77,9 +77,9 @@ 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;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ 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";
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ foreach my $expr (@exprs) {
|
||||
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,50 +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.
|
||||
print "unpacking channel Nix expressions...\n";
|
||||
my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate --add-root '$rootFile'.tmp -`
|
||||
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;
|
||||
|
||||
@@ -124,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'";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ $binDir = "@bindir@" unless defined $binDir;
|
||||
|
||||
if (scalar @ARGV < 1) {
|
||||
print STDERR <<EOF
|
||||
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] PATHS...
|
||||
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
|
||||
EOF
|
||||
;
|
||||
exit 1;
|
||||
@@ -120,7 +120,6 @@ else { # Copy FROM the remote machine.
|
||||
if (!defined $storePathsSeen{$_}) {
|
||||
push @allStorePaths, $_;
|
||||
$storePathsSeen{$_} = 1;
|
||||
print "GOT $_\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,9 +17,9 @@ $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;
|
||||
|
||||
|
||||
@@ -36,30 +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 --disable-epsv \
|
||||
--cookie-jar $tmpPath/cookies "$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'" >&2
|
||||
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;
|
||||
@@ -33,18 +36,47 @@ my %patches;
|
||||
|
||||
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;
|
||||
|
||||
# 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 "manifest `$url' is too old (i.e., for Nix <= 0.7)\n";
|
||||
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) {
|
||||
@@ -83,41 +115,3 @@ while (@ARGV) {
|
||||
|
||||
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";
|
||||
|
||||
sub writeRegistration {
|
||||
my $storePath = shift;
|
||||
my $object = shift;
|
||||
print WRITE "$storePath\n";
|
||||
print WRITE "$object->{deriver}\n";
|
||||
print WRITE "$libexecDir/nix/download-using-manifests.pl\n";
|
||||
print WRITE "0\n";
|
||||
my @references = split " ", $object->{references};
|
||||
my $count = scalar @references;
|
||||
print WRITE "$count\n";
|
||||
foreach my $reference (@references) {
|
||||
print WRITE "$reference\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $storePath (keys %narFiles) {
|
||||
my $narFileList = $narFiles{$storePath};
|
||||
foreach my $narFile (@{$narFileList}) {
|
||||
writeRegistration $storePath, $narFile;
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $storePath (keys %localPaths) {
|
||||
my $localPathList = $localPaths{$storePath};
|
||||
foreach my $localPath (@{$localPathList}) {
|
||||
writeRegistration $storePath, $localPath;
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
@@ -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;
|
||||
@@ -222,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: $!";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
|
||||
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-log2xml bsdiff-4.3 nix-state
|
||||
|
||||
EXTRA_DIST = aterm-helper.pl
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -478,7 +478,7 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
|
||||
}
|
||||
|
||||
else throwTypeError(
|
||||
"the left-hand side of the function call is neither a function nor a primop (built-in operation) but %1%",
|
||||
"attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
|
||||
showType(fun));
|
||||
}
|
||||
|
||||
@@ -616,6 +616,9 @@ static char * deepestStack = (char *) -1; /* for measuring stack usage */
|
||||
|
||||
Expr evalExpr2(EvalState & state, Expr e)
|
||||
{
|
||||
/* When changing this function, make sure that you don't cause a
|
||||
(large) increase in stack consumption! */
|
||||
|
||||
char x;
|
||||
if (&x < deepestStack) deepestStack = &x;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -35,6 +35,53 @@ string DrvInfo::queryOutPath(EvalState & state) const
|
||||
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
|
||||
{
|
||||
@@ -60,6 +107,15 @@ 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;
|
||||
@@ -93,20 +149,23 @@ static bool getDerivation(EvalState & state, Expr e,
|
||||
|
||||
boost::shared_ptr<ATermMap> attrs(new ATermMap());
|
||||
queryAllAttrs(e, *attrs, false);
|
||||
|
||||
|
||||
Expr a = attrs->get(toATerm("type"));
|
||||
if (!a || evalStringNoCtx(state, a) != "derivation") return true;
|
||||
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");
|
||||
if (!a)
|
||||
throw TypeError("derivation name missing");
|
||||
drv.name = evalStringNoCtx(state, a);
|
||||
|
||||
a = attrs->get(toATerm("system"));
|
||||
@@ -116,7 +175,9 @@ static bool getDerivation(EvalState & state, Expr e,
|
||||
drv.system = evalStringNoCtx(state, a);
|
||||
|
||||
drv.attrs = attrs;
|
||||
|
||||
|
||||
//printMsg(lvlError, format("TEST '%1%'") % evalStringNoCtx(state, a) );
|
||||
|
||||
drv.attrPath = attrPath;
|
||||
|
||||
drvs.push_back(drv);
|
||||
@@ -133,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;
|
||||
}
|
||||
@@ -161,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'
|
||||
@@ -176,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,6 +20,8 @@ struct DrvInfo
|
||||
private:
|
||||
string drvPath;
|
||||
string outPath;
|
||||
string stateIdentifier;
|
||||
string runtimeStateArgs;
|
||||
|
||||
public:
|
||||
string name;
|
||||
@@ -33,7 +35,10 @@ public:
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -44,7 +49,17 @@ 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
|
||||
|
||||
|
||||
%{
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ Int | int | Expr |
|
||||
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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace nix {
|
||||
|
||||
MakeError(EvalError, Error)
|
||||
MakeError(AssertionError, EvalError)
|
||||
MakeError(ThrownError, AssertionError)
|
||||
MakeError(Abort, EvalError)
|
||||
MakeError(TypeError, EvalError)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -199,6 +291,9 @@ expr_simple
|
||||
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 { $$ = makeStr($1, ATempty); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
@@ -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
|
||||
@@ -382,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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "misc.hh"
|
||||
#include "eval.hh"
|
||||
#include "db.hh"
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "util.hh"
|
||||
#include "archive.hh"
|
||||
#include "expr-to-xml.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "local-store.hh"
|
||||
#include "parser.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -114,6 +117,18 @@ static Expr prim_isNull(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is a function. */
|
||||
static Expr prim_isFunction(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
Expr e = evalExpr(state, args[0]);
|
||||
ATermList formals;
|
||||
ATerm name, body, pos;
|
||||
return makeBool(
|
||||
matchFunction(e, formals, body, pos) ||
|
||||
matchFunction1(e, name, body, pos));
|
||||
}
|
||||
|
||||
|
||||
static Path findDependency(Path dir, string dep)
|
||||
{
|
||||
if (dep[0] == '/') throw EvalError(
|
||||
@@ -269,6 +284,14 @@ static Expr prim_abort(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
static Expr prim_throw(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
PathSet context;
|
||||
throw ThrownError(format("user-thrown exception: `%1%'") %
|
||||
evalString(state, args[0], context));
|
||||
}
|
||||
|
||||
|
||||
/* Return an environment variable. Use with care. */
|
||||
static Expr prim_getEnv(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
@@ -277,6 +300,18 @@ static Expr prim_getEnv(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the first expression, and print its abstract syntax tree
|
||||
on standard error. Then return the second expression. Useful for
|
||||
debugging.
|
||||
*/
|
||||
static Expr prim_trace(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
Expr e = evalExpr(state, args[0]);
|
||||
printMsg(lvlError, format("trace: %1%") % e);
|
||||
return evalExpr(state, args[1]);
|
||||
}
|
||||
|
||||
|
||||
static Expr prim_relativise(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
PathSet context; /* !!! what to do? */
|
||||
@@ -313,39 +348,67 @@ static Expr prim_relativise(EvalState & state, const ATermVector & args)
|
||||
(basically) its outputHash. */
|
||||
static Hash hashDerivationModulo(EvalState & state, Derivation drv)
|
||||
{
|
||||
/* Return a fixed hash for fixed-output derivations. */
|
||||
//printMsg(lvlError, format("DRV: %1% %2%") % drv.env.find("name")->second % (drv.outputs.size() == 1));
|
||||
|
||||
/* Return a fixed hash for fixed-output derivations.
|
||||
* E.g. derivations that have a hash
|
||||
*/
|
||||
if (drv.outputs.size() == 1) {
|
||||
DerivationOutputs::const_iterator i = drv.outputs.begin();
|
||||
|
||||
if (i->first == "out" &&
|
||||
i->second.hash != "")
|
||||
{
|
||||
//printMsg(lvlError, format("FIXED OUTPUT: %1% - %2% - %3%") % i->second.hashAlgo % i->second.hash % i->second.path);
|
||||
|
||||
return hashString(htSHA256, "fixed:out:"
|
||||
+ i->second.hashAlgo + ":"
|
||||
+ i->second.hash + ":"
|
||||
+ i->second.path);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a state derivation, we clear state paramters because they (sometimes) can affect the outPath:
|
||||
* If this drv has runtime paramters: The state indentifier and statepath may change, but the componentPath (outPath) can stay the same
|
||||
* If this drv doesnt have runtime paramters: The state indentifier and statepath may change, but the componentPath changes since it is build with another identifier
|
||||
* In both cases: Other runtime state parameters like stateDirs, synchronisation and shareState never change the out or statepath so always need to be out of the hash
|
||||
*/
|
||||
if(isStateDrv(drv)){
|
||||
|
||||
if(drv.stateOutputs.size() != 1)
|
||||
throw EvalError(format("There are more then one stateOutputs in the derviation....."));
|
||||
|
||||
DerivationStateOutput drvso = drv.stateOutputs["state"];
|
||||
|
||||
if(drvso.runtimeStateArgs != ""){ //Has runtime parameters --> Clear all state parameters
|
||||
drv.stateOutputs.clear();
|
||||
drv.stateOutputDirs.clear();
|
||||
drv.env["statePath"] = "";
|
||||
}
|
||||
else{ //Has NO runtime parameters --> Clear state parameters selectively
|
||||
drvso.clearAllRuntimeParamters();
|
||||
drv.stateOutputDirs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* For other derivations, replace the inputs paths with recursive
|
||||
calls to this function.*/
|
||||
DerivationInputs inputs2;
|
||||
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||
i != drv.inputDrvs.end(); ++i)
|
||||
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
||||
{
|
||||
Hash h = state.drvHashes[i->first];
|
||||
if (h.type == htUnknown) {
|
||||
Derivation drv2 = derivationFromPath(i->first);
|
||||
Derivation drv2 = derivationFromPathTxn(noTxn, i->first);
|
||||
h = hashDerivationModulo(state, drv2);
|
||||
state.drvHashes[i->first] = h;
|
||||
}
|
||||
inputs2[printHash(h)] = i->second;
|
||||
}
|
||||
drv.inputDrvs = inputs2;
|
||||
|
||||
return hashTerm(unparseDerivation(drv));
|
||||
//printMsg(lvlError, format("%1% with %2% --> %3%") % drv.env.find("name")->second % printHash(hashTerm(unparseDerivation(drv))) % unparseDerivation(drv));
|
||||
return hashTerm(unparseDerivation(drv));
|
||||
}
|
||||
|
||||
|
||||
/* Construct (as a unobservable side effect) a Nix derivation
|
||||
expression that performs the derivation described by the argument
|
||||
set. Returns the original set extended with the following
|
||||
@@ -384,6 +447,18 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||
string outputHashAlgo;
|
||||
bool outputHashRecursive = false;
|
||||
|
||||
//state vars
|
||||
bool enableState = false; //We dont do state by default, but if a user defines stateDirs for example, than this becomes true.
|
||||
bool disableState = false; //Becomes true if the user explicitly says: no state
|
||||
string shareType = "none";
|
||||
string syncState = "none";
|
||||
string stateIdentifier = "";
|
||||
bool createDirsBeforeInstall = false;
|
||||
string runtimeStateArgs = "";
|
||||
string sharedState = "";
|
||||
string externalState = "";
|
||||
vector<DerivationStateOutputDir> stateDirs;
|
||||
|
||||
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
|
||||
string key = aterm2String(i->key);
|
||||
ATerm value;
|
||||
@@ -409,7 +484,73 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||
drv.args.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
//Add specific state variables
|
||||
else if(key == "stateDirs") {
|
||||
|
||||
enableState = true;
|
||||
value = evalExpr(state, value);
|
||||
ATermList list = evalList(state, value);
|
||||
|
||||
for (ATermIterator j(list); j; ++j){
|
||||
Expr v = evalExpr(state, *j);
|
||||
ATermMap stateDirattrs;
|
||||
queryAllAttrs(evalExpr(state, v), stateDirattrs, true);
|
||||
DerivationStateOutputDir dir = DerivationStateOutputDir();
|
||||
|
||||
for (ATermMap::const_iterator k = stateDirattrs.begin(); k != stateDirattrs.end(); ++k) {
|
||||
|
||||
string statekey = aterm2String(k->key);
|
||||
ATerm statevalue;
|
||||
Expr statepos;
|
||||
ATerm staterhs = k->value;
|
||||
if (!matchAttrRHS(staterhs, statevalue, statepos)) abort();
|
||||
startNest(nest, lvlVomit, format("processing statedir attribute `%1%'") % statekey);
|
||||
try {
|
||||
string s = trim(coerceToString(state, statevalue, context, true));
|
||||
if (statekey == "dir") {
|
||||
|
||||
//Add a / to the end if it's not there
|
||||
if(s[s.length() - 1] != '/')
|
||||
s = s + "/";
|
||||
|
||||
//Remove the / at the beginning if it's there
|
||||
if(s[0] == '/' && s.length() != 1)
|
||||
s = s.substr(1, s.length());
|
||||
|
||||
dir.path = s;
|
||||
}
|
||||
else if (statekey == "file") { dir.path = s; }
|
||||
else if (statekey == "type") { dir.type = s; }
|
||||
else if (statekey == "interval") {
|
||||
if(s == "")
|
||||
continue;
|
||||
int n;
|
||||
if (!string2Int(s, n)) throw Error("interval is not a number");
|
||||
if(n == 0) throw Error("Interval cannot be 0");
|
||||
dir.interval = s;
|
||||
}
|
||||
else throw EvalError(format("invalid sub-attirbute `%1%' for attribute dirs") % statekey);
|
||||
}
|
||||
catch (Error & e) {
|
||||
e.addPrefix(format("while evaluating the state derivation attribute `%1%' at %2%:\n") % key % showPos(statepos));
|
||||
e.addPrefix(format("while instantiating the derivation named `%1%' at %2%:\n") % drvName % showPos(posDrvName));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
stateDirs.push_back(dir);
|
||||
}
|
||||
|
||||
}
|
||||
else if(key == "solidStateDependency"){ externalState = coerceToString(state, value, context, true); }
|
||||
else if(key == "shareType") { shareType = coerceToString(state, value, context, true); }
|
||||
else if(key == "synchronization") { syncState = coerceToString(state, value, context, true); }
|
||||
else if(key == "disableState") { disableState = evalBool(state, value); }
|
||||
else if(key == "identifier"){ stateIdentifier = coerceToString(state, value, context, true); }
|
||||
else if(key == "createDirsBeforeInstall"){ createDirsBeforeInstall = evalBool(state, value); }
|
||||
else if(key == "runtimeStateArgs"){ runtimeStateArgs = coerceToString(state, value, context, true); }
|
||||
else if(key == "shareStateFrom"){ sharedState = coerceToString(state, value, context, true); }
|
||||
|
||||
/* All other attributes are passed to the builder through
|
||||
the environment. */
|
||||
else {
|
||||
@@ -434,7 +575,6 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||
% drvName % showPos(posDrvName));
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Everything in the context of the strings in the derivation
|
||||
@@ -489,24 +629,55 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||
have an empty value. This ensures that changes in the set of
|
||||
output names do get reflected in the hash. */
|
||||
drv.env["out"] = "";
|
||||
drv.outputs["out"] =
|
||||
DerivationOutput("", outputHashAlgo, outputHash);
|
||||
drv.outputs["out"] = DerivationOutput("", outputHashAlgo, outputHash);
|
||||
|
||||
/* If there are no runtime paratermers, then we need to take the the stateIdentifier into account for the hash calcaulation below: hashDerivationModulo(...)
|
||||
* We also add enableState to make it parse the drv to a state-drv
|
||||
* We also add runtimeStateArgs for the hash calc in hashDerivationModulo(...) to check if its needs to take the stateIdentiefier into account in the hash
|
||||
*/
|
||||
|
||||
if(enableState && !disableState){
|
||||
if(runtimeStateArgs == ""){
|
||||
string enableStateS = bool2string("true");
|
||||
drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateArgs, queryCurrentUsername(), "", "", false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the masked derivation expression to compute the output
|
||||
path. */
|
||||
Path outPath = makeStorePath("output:out",
|
||||
hashDerivationModulo(state, drv), drvName);
|
||||
Hash componentHash = hashDerivationModulo(state, drv);
|
||||
Path outPath = makeStorePath("output:out", componentHash, drvName);
|
||||
|
||||
/* Construct the final derivation store expression. */
|
||||
drv.env["out"] = outPath;
|
||||
drv.outputs["out"] =
|
||||
DerivationOutput(outPath, outputHashAlgo, outputHash);
|
||||
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
|
||||
|
||||
//printMsg(lvlError, format("DerivationOutput %1% %2% %3%") % outPath % outputHashAlgo % outputHash);
|
||||
//only add state when we have to to keep compitibilty with the 'old' format.
|
||||
//We add state when it's enbaled by the keywords, and not excplicitly disabled by the user
|
||||
Path stateOutPath;
|
||||
if(enableState && !disableState){
|
||||
/* Add the state path based on the outPath
|
||||
*
|
||||
* NOTE: we do not include the username into the hash calculation of the statepath yet, multiple different users can use the same dervation
|
||||
* but need different state paths. Thats why we keep a 'dummy' value e.g. global hash for everyone, and later at build time recalculate the real state path
|
||||
*/
|
||||
stateOutPath = makeStatePath(printHash(componentHash), drvName, stateIdentifier, queryCurrentUsername()); //State path
|
||||
drv.env["statePath"] = stateOutPath;
|
||||
|
||||
string enableStateS = bool2string("true");
|
||||
string createDirsBeforeInstallS = bool2string(createDirsBeforeInstall);
|
||||
drv.stateOutputs["state"] = DerivationStateOutput(stateOutPath, printHash(componentHash), outputHashAlgo, outputHash, stateIdentifier, enableStateS,
|
||||
shareType, syncState, createDirsBeforeInstallS, runtimeStateArgs, queryCurrentUsername(), sharedState, externalState);
|
||||
|
||||
for(vector<DerivationStateOutputDir>::iterator i = stateDirs.begin(); i != stateDirs.end(); ++i)
|
||||
drv.stateOutputDirs[(*i).path] = *(i);
|
||||
}
|
||||
|
||||
/* Write the resulting term into the Nix store directory. */
|
||||
Path drvPath = writeDerivation(drv, drvName);
|
||||
|
||||
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'")
|
||||
% drvName % drvPath);
|
||||
printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") % drvName % drvPath);
|
||||
|
||||
/* Optimisation, but required in read-only mode! because in that
|
||||
case we don't actually write store expressions, so we can't
|
||||
@@ -515,10 +686,17 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
||||
|
||||
/* !!! assumes a single output */
|
||||
ATermMap outAttrs(2);
|
||||
outAttrs.set(toATerm("outPath"),
|
||||
makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
|
||||
outAttrs.set(toATerm("drvPath"),
|
||||
makeAttrRHS(makeStr(drvPath, singleton<PathSet>(drvPath)), makeNoPos()));
|
||||
outAttrs.set(toATerm("outPath"), makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
|
||||
outAttrs.set(toATerm("drvPath"), makeAttrRHS(makeStr(drvPath, singleton<PathSet>(drvPath)), makeNoPos()));
|
||||
|
||||
/* TODO !!!!!!!!!!!!!!!!!!!! Recheck this !!!!!!!!!!!!!!!!!!!!
|
||||
* We now always set the statePath since someone might 'convert' and old non-state expression into a state expression like this:
|
||||
* let oldDrv = import ../../applications/networking/mailreaders/thunderbird-2.x;
|
||||
* newDrv = stdenv.mkDerivation( oldDrv { ... } // { name = "x-state-v"; stateDirs = [ ... ]; } );
|
||||
* in newDrv
|
||||
*/
|
||||
//if(enableState && !disableState)
|
||||
outAttrs.set(toATerm("statePath"), makeAttrRHS(makeStr(stateOutPath, singleton<PathSet>(drvPath)), makeNoPos()));
|
||||
|
||||
return makeAttrs(outAttrs);
|
||||
}
|
||||
@@ -539,6 +717,8 @@ static Expr prim_derivationLazy(EvalState & state, const ATermVector & args)
|
||||
makeAttrRHS(makeSelect(drvStrict, toATerm("outPath")), makeNoPos()));
|
||||
attrs.set(toATerm("drvPath"),
|
||||
makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos()));
|
||||
attrs.set(toATerm("statePath"),
|
||||
makeAttrRHS(makeSelect(drvStrict, toATerm("statePath")), makeNoPos()));
|
||||
|
||||
return makeAttrs(attrs);
|
||||
}
|
||||
@@ -574,8 +754,8 @@ static Expr prim_baseNameOf(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
PathSet context;
|
||||
return makeStr(baseNameOf(coerceToString(state, args[0], context)), context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Return the directory of the given path, i.e., everything before the
|
||||
last slash. Return either a path or a string depending on the type
|
||||
@@ -590,6 +770,17 @@ static Expr prim_dirOf(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* Return the contents of a file as a string. */
|
||||
static Expr prim_readFile(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
PathSet context;
|
||||
Path path = coerceToPath(state, args[0], context);
|
||||
if (!context.empty())
|
||||
throw EvalError(format("string `%1%' cannot refer to other paths") % path);
|
||||
return makeStr(readFile(path));
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* Creating files
|
||||
*************************************************************/
|
||||
@@ -616,6 +807,7 @@ static Expr prim_toFile(EvalState & state, const ATermVector & args)
|
||||
string contents = evalString(state, args[1], context);
|
||||
|
||||
PathSet refs;
|
||||
PathSet stateRefs; //refs refers to the file references, there are no state references in this case.
|
||||
|
||||
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) {
|
||||
if (isDerivation(*i))
|
||||
@@ -724,6 +916,40 @@ static Expr prim_hasAttr(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* Builds an attribute set from a list specifying (name, value)
|
||||
pairs. To be precise, a list [{name = "name1"; value = value1;}
|
||||
... {name = "nameN"; value = valueN;}] is transformed to {name1 =
|
||||
value1; ... nameN = valueN;}. */
|
||||
static Expr prim_listToAttrs(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
try {
|
||||
ATermMap res = ATermMap();
|
||||
ATermList list;
|
||||
list = evalList(state, args[0]);
|
||||
for (ATermIterator i(list); i; ++i){
|
||||
// *i should now contain a pointer to the list item expression
|
||||
ATermList attrs;
|
||||
Expr evaledExpr = evalExpr(state, *i);
|
||||
if (matchAttrs(evaledExpr, attrs)){
|
||||
Expr e = evalExpr(state, makeSelect(evaledExpr, toATerm("name")));
|
||||
string attr = evalStringNoCtx(state,e);
|
||||
Expr r = makeSelect(evaledExpr, toATerm("value"));
|
||||
res.set(toATerm(attr), makeAttrRHS(r, makeNoPos()));
|
||||
}
|
||||
else
|
||||
throw TypeError(format("list element in `listToAttrs' is %s, expected a set { name = \"<name>\"; value = <value>; }")
|
||||
% showType(evaledExpr));
|
||||
}
|
||||
|
||||
return makeAttrs(res);
|
||||
|
||||
} catch (Error & e) {
|
||||
e.addPrefix(format("in `listToAttrs':\n"));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Expr prim_removeAttrs(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
ATermMap attrs;
|
||||
@@ -739,6 +965,14 @@ static Expr prim_removeAttrs(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether the argument is a list. */
|
||||
static Expr prim_isAttrs(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
ATermList list;
|
||||
return makeBool(matchAttrs(evalExpr(state, args[0]), list));
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* Lists
|
||||
*************************************************************/
|
||||
@@ -832,8 +1066,8 @@ static Expr prim_toString(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
/* `substr start len str' returns the substring of `str' starting at
|
||||
character position `min(start, stringLength str)' inclusive and
|
||||
/* `substring start len str' returns the substring of `str' starting
|
||||
at character position `min(start, stringLength str)' inclusive and
|
||||
ending at `min(start + len, stringLength str)'. `start' must be
|
||||
non-negative. */
|
||||
static Expr prim_substring(EvalState & state, const ATermVector & args)
|
||||
@@ -857,6 +1091,30 @@ static Expr prim_stringLength(EvalState & state, const ATermVector & args)
|
||||
}
|
||||
|
||||
|
||||
static Expr prim_unsafeDiscardStringContext(EvalState & state, const ATermVector & args)
|
||||
{
|
||||
PathSet context;
|
||||
string s = coerceToString(state, args[0], context);
|
||||
return makeStr(s, PathSet());
|
||||
}
|
||||
|
||||
/* Expression serialization/deserialization */
|
||||
|
||||
static Expr prim_ExprToString ( EvalState & state, const ATermVector & args)
|
||||
{
|
||||
return makeStr ( atPrint ( evalExpr ( state, args [ 0 ] ) ) );
|
||||
}
|
||||
|
||||
static Expr prim_StringToExpr ( EvalState & state, const ATermVector & args)
|
||||
{
|
||||
string s;
|
||||
PathSet l;
|
||||
if (! matchStr ( evalExpr ( state, args[0] ), s, l )) {
|
||||
throw EvalError("__stringToExpr needs string argument!");
|
||||
}
|
||||
return ATreadFromString(s.c_str());
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Primop registration
|
||||
*************************************************************/
|
||||
@@ -876,9 +1134,16 @@ void EvalState::addPrimOps()
|
||||
// Miscellaneous
|
||||
addPrimOp("import", 1, prim_import);
|
||||
addPrimOp("isNull", 1, prim_isNull);
|
||||
addPrimOp("__isFunction", 1, prim_isFunction);
|
||||
addPrimOp("dependencyClosure", 1, prim_dependencyClosure);
|
||||
addPrimOp("abort", 1, prim_abort);
|
||||
addPrimOp("throw", 1, prim_throw);
|
||||
addPrimOp("__getEnv", 1, prim_getEnv);
|
||||
addPrimOp("__trace", 2, prim_trace);
|
||||
|
||||
// Expr <-> String
|
||||
addPrimOp("__exprToString", 1, prim_ExprToString);
|
||||
addPrimOp("__stringToExpr", 1, prim_StringToExpr);
|
||||
|
||||
addPrimOp("relativise", 2, prim_relativise);
|
||||
|
||||
@@ -891,6 +1156,7 @@ void EvalState::addPrimOps()
|
||||
addPrimOp("__pathExists", 1, prim_pathExists);
|
||||
addPrimOp("baseNameOf", 1, prim_baseNameOf);
|
||||
addPrimOp("dirOf", 1, prim_dirOf);
|
||||
addPrimOp("__readFile", 1, prim_readFile);
|
||||
|
||||
// Creating files
|
||||
addPrimOp("__toXML", 1, prim_toXML);
|
||||
@@ -901,7 +1167,9 @@ void EvalState::addPrimOps()
|
||||
addPrimOp("__attrNames", 1, prim_attrNames);
|
||||
addPrimOp("__getAttr", 2, prim_getAttr);
|
||||
addPrimOp("__hasAttr", 2, prim_hasAttr);
|
||||
addPrimOp("__isAttrs", 1, prim_isAttrs);
|
||||
addPrimOp("removeAttrs", 2, prim_removeAttrs);
|
||||
addPrimOp("__listToAttrs", 1, prim_listToAttrs);
|
||||
|
||||
// Lists
|
||||
addPrimOp("__isList", 1, prim_isList);
|
||||
@@ -918,6 +1186,8 @@ void EvalState::addPrimOps()
|
||||
addPrimOp("toString", 1, prim_toString);
|
||||
addPrimOp("__substring", 3, prim_substring);
|
||||
addPrimOp("__stringLength", 1, prim_stringLength);
|
||||
addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
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}
|
||||
24
src/libext3cow/epoch2date.c
Normal file
24
src/libext3cow/epoch2date.c
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
/* epoch2date.c - an ext3cow tool for turning epoch numbers into dates.
|
||||
* Copyright (C) 2003-2007 Zachary N. J. Peterson
|
||||
*/
|
||||
|
||||
|
||||
#include "ext3cow_tools.h"
|
||||
|
||||
int main(int argc, char** argv){
|
||||
|
||||
time_t time;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(stderr, "usage: %s seconds\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
time = atoi(argv[1]);
|
||||
|
||||
printf("%s", ctime(&time));
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
10
src/libext3cow/ext3cow_tools.h
Normal file
10
src/libext3cow/ext3cow_tools.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "ext3cow_fs.h"
|
||||
97
src/libext3cow/snapshot.cc
Normal file
97
src/libext3cow/snapshot.cc
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
/* snapshot.c - an ext3cow tool for taking file system snapshots
|
||||
* Copyright (C) 2003-2007 Zachary N. J. Peterson
|
||||
*/
|
||||
|
||||
|
||||
#include "ext3cow_tools.h"
|
||||
#include "snapshot.hh"
|
||||
#include "types.hh"
|
||||
|
||||
//using namespace nix;
|
||||
|
||||
namespace nix {
|
||||
|
||||
/////////////////////Original functions commented out:
|
||||
|
||||
/*
|
||||
void snapshot_usage(void){
|
||||
|
||||
fprintf(stderr, "usage: snapshot <mountpoint>\n");
|
||||
|
||||
}
|
||||
|
||||
int snapshot_main(int argc, char** argv){
|
||||
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int epoch = 0;
|
||||
char path[256] = ".\0";
|
||||
|
||||
if(argc > 1)
|
||||
strcpy(path, argv[1]);
|
||||
|
||||
printf("Snapshot on %s: ", path);
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
|
||||
// test for ext3cow fs type
|
||||
|
||||
if(fd < 0){
|
||||
printf("failed.\n");
|
||||
perror(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
epoch = (int)ioctl(fd, EXT3COW_IOC_TAKESNAPSHOT, &epoch);
|
||||
if((int)epoch < 0){
|
||||
printf("failed.\n");
|
||||
perror(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("%u\n", (unsigned int)epoch);
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
/////////////////////End original functions
|
||||
|
||||
|
||||
unsigned int take_snapshot(const string & dir2) //const string & file_or_dir)
|
||||
{
|
||||
const char* dir = dir2.c_str();
|
||||
|
||||
int fd;
|
||||
unsigned int epoch = 0;
|
||||
|
||||
//char path[256] = ".\0";
|
||||
//TODO 256 length check ???
|
||||
//strcpy(path, dir);
|
||||
|
||||
fd = open(dir, O_RDONLY);
|
||||
|
||||
/* test for ext3cow fs type */
|
||||
|
||||
if(fd < 0){
|
||||
printf("failed.\n");
|
||||
perror(dir);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
epoch = (int)ioctl(fd, EXT3COW_IOC_TAKESNAPSHOT, &epoch);
|
||||
if((int)epoch < 0){
|
||||
printf("failed.\n");
|
||||
perror(dir);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//printf("%u\n", (unsigned int)epoch);
|
||||
|
||||
return epoch;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/libext3cow/snapshot.hh
Normal file
13
src/libext3cow/snapshot.hh
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef SNAPSHOT_H_
|
||||
#define SNAPSHOT_H_
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
//unsigned int take_snapshot(const string & file_or_dir);
|
||||
unsigned int take_snapshot(const string & dir);
|
||||
|
||||
}
|
||||
|
||||
#endif /*SNAPSHOT_H_*/
|
||||
46
src/libext3cow/tt.c
Normal file
46
src/libext3cow/tt.c
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
/* tt.c - an ext3cow tool for retreiving the current file system epoch
|
||||
* Copyright (C) 2003-2007 Zachary N. J. Peterson
|
||||
*/
|
||||
|
||||
#include "ext3cow_tools.h"
|
||||
|
||||
void tt_usage(void){
|
||||
|
||||
fprintf(stderr, "usage: tt <mountpoint>\n");
|
||||
|
||||
}
|
||||
|
||||
int tt_main(int argc, char** argv){
|
||||
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int epoch = 0;
|
||||
char path[255] = ".\0";
|
||||
|
||||
if(argc > 1)
|
||||
strcpy(path, argv[1]);
|
||||
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
|
||||
/* test for ext3cow fs type */
|
||||
|
||||
if(fd < 0){
|
||||
fprintf(stderr, "Couldn't open %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
ret = ioctl(fd, EXT3COW_IOC_GETEPOCH, &epoch);
|
||||
if(ret < 0){
|
||||
printf("tt on %s failed.\n", path);
|
||||
perror(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
printf("Epoch: %d\n", ret);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -4,6 +4,9 @@ libmain_la_SOURCES = shared.cc shared.hh
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
-DNIX_STORE_DIR=\"$(storedir)\" \
|
||||
-DNIX_STORE_STATE_DIR=\"$(storestatedir)\" \
|
||||
-DNIX_EXT3_COW_HEADER=\"$(ext3cowheader)\" \
|
||||
-DNIX_RSYNC=\"$(rsync)\" \
|
||||
-DNIX_DATA_DIR=\"$(datadir)\" \
|
||||
-DNIX_STATE_DIR=\"$(localstatedir)/nix\" \
|
||||
-DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <exception>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -81,20 +82,46 @@ struct RemoveTempRoots
|
||||
void initDerivationsHelpers();
|
||||
|
||||
|
||||
static void closeStore()
|
||||
{
|
||||
try {
|
||||
throw;
|
||||
} catch (std::exception & e) {
|
||||
printMsg(lvlError,
|
||||
format("FATAL: unexpected exception (closing store and aborting): %1%") % e.what());
|
||||
}
|
||||
try {
|
||||
store.reset((StoreAPI *) 0);
|
||||
} catch (...) {
|
||||
ignoreException();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
/* Initialize and reorder arguments, then call the actual argument
|
||||
processor. */
|
||||
static void initAndRun(int argc, char * * argv)
|
||||
{
|
||||
/* Setup Nix paths. */
|
||||
nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR)));
|
||||
nixStoreState = canonPath(getEnv("NIX_STORE_STATE_DIR", NIX_STORE_STATE_DIR)); //store state dir usually /nix/state
|
||||
nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
|
||||
nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
|
||||
nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
|
||||
nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)); //nix global state dir
|
||||
nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
|
||||
nixExt3CowHeader = getEnv("NIX_EXT3_COW_HEADER", NIX_EXT3_COW_HEADER);
|
||||
nixRsync = getEnv("NIX_RSYNC", NIX_RSYNC);
|
||||
nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
|
||||
nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
|
||||
nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
|
||||
|
||||
string subs = getEnv("NIX_SUBSTITUTERS", "default");
|
||||
if (subs == "default")
|
||||
substituters.push_back(nixLibexecDir + "/nix/download-using-manifests.pl");
|
||||
else
|
||||
substituters = tokenizeString(subs, ":");
|
||||
|
||||
/* Get some settings from the configuration file. */
|
||||
thisSystem = querySetting("system", SYSTEM);
|
||||
maxBuildJobs = queryIntSetting("build-max-jobs", 1);
|
||||
@@ -136,23 +163,29 @@ static void initAndRun(int argc, char * * argv)
|
||||
while (argc--) args.push_back(*argv++);
|
||||
args.erase(args.begin());
|
||||
|
||||
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
|
||||
ignore options for the ATerm library. */
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
string arg = *i;
|
||||
if (string(arg, 0, 4) == "-at-") ;
|
||||
else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') {
|
||||
for (unsigned int j = 1; j < arg.length(); j++)
|
||||
if (isalpha(arg[j]))
|
||||
remaining.push_back((string) "-" + arg[j]);
|
||||
else {
|
||||
remaining.push_back(string(arg, j));
|
||||
break;
|
||||
}
|
||||
} else remaining.push_back(arg);
|
||||
/* We dont expand for nix-state since we need to pass arguments to other
|
||||
* programs that can decide for themselves if they want expansion or not
|
||||
*/
|
||||
if(programId != "nix-state")
|
||||
{
|
||||
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
|
||||
ignore options for the ATerm library. */
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
string arg = *i;
|
||||
if (string(arg, 0, 4) == "-at-") ;
|
||||
else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') {
|
||||
for (unsigned int j = 1; j < arg.length(); j++)
|
||||
if (isalpha(arg[j]))
|
||||
remaining.push_back((string) "-" + arg[j]);
|
||||
else {
|
||||
remaining.push_back(string(arg, j));
|
||||
break;
|
||||
}
|
||||
} else remaining.push_back(arg);
|
||||
}
|
||||
args = remaining;
|
||||
remaining.clear();
|
||||
}
|
||||
args = remaining;
|
||||
remaining.clear();
|
||||
|
||||
/* Process default options. */
|
||||
for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
@@ -168,13 +201,15 @@ static void initAndRun(int argc, char * * argv)
|
||||
; /* !!! obsolete - remove eventually */
|
||||
else if (arg == "--no-build-output" || arg == "-Q")
|
||||
buildVerbosity = lvlVomit;
|
||||
else if (arg == "--help") {
|
||||
|
||||
//we need to push back since arguments need to be passed on in the state wrapper script
|
||||
else if (arg == "--help" && programId != "nix-state") {
|
||||
printHelp();
|
||||
return;
|
||||
remaining.push_back(arg);
|
||||
}
|
||||
else if (arg == "--version") {
|
||||
std::cout << format("%1% (Nix) %2%") % programId % NIX_VERSION << std::endl;
|
||||
return;
|
||||
remaining.push_back(arg);
|
||||
}
|
||||
else if (arg == "--keep-failed" || arg == "-K")
|
||||
keepFailed = true;
|
||||
@@ -188,6 +223,8 @@ static void initAndRun(int argc, char * * argv)
|
||||
readOnlyMode = true;
|
||||
else if (arg == "--max-silent-time")
|
||||
maxSilentTime = getIntArg(arg, i, args.end());
|
||||
else if (arg == "--no-build-hook")
|
||||
useBuildHook = false;
|
||||
else remaining.push_back(arg);
|
||||
}
|
||||
|
||||
@@ -195,6 +232,12 @@ static void initAndRun(int argc, char * * argv)
|
||||
exit. */
|
||||
RemoveTempRoots removeTempRoots; /* unused variable - don't remove */
|
||||
|
||||
/* Make sure that the database gets closed properly, even if
|
||||
terminate() is called (which happens sometimes due to bugs in
|
||||
destructor/exceptions interaction, but that needn't preclude a
|
||||
clean shutdown of the database). */
|
||||
std::set_terminate(closeStore);
|
||||
|
||||
run(remaining);
|
||||
|
||||
/* Close the Nix database. */
|
||||
@@ -296,7 +339,7 @@ int main(int argc, char * * argv)
|
||||
"Try `%2% --help' for more information.")
|
||||
% e.what() % programId);
|
||||
return 1;
|
||||
} catch (Error & e) {
|
||||
} catch (BaseError & e) {
|
||||
printMsg(lvlError, format("error: %1%") % e.msg());
|
||||
return 1;
|
||||
} catch (std::exception & e) {
|
||||
|
||||
@@ -2,21 +2,23 @@ pkglib_LTLIBRARIES = libstore.la
|
||||
|
||||
libstore_la_SOURCES = \
|
||||
store-api.cc local-store.cc remote-store.cc derivations.cc build.cc misc.cc \
|
||||
globals.cc db.cc references.cc pathlocks.cc gc.cc
|
||||
globals.cc db.cc references.cc pathlocks.cc gc.cc store-state.cc
|
||||
|
||||
pkginclude_HEADERS = \
|
||||
store-api.hh local-store.hh remote-store.hh derivations.hh misc.hh \
|
||||
globals.hh db.hh references.hh pathlocks.hh \
|
||||
worker-protocol.hh
|
||||
worker-protocol.hh store-state.hh build.hh
|
||||
|
||||
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la
|
||||
libstore_la_LIBADD = ../libutil/libutil.la \
|
||||
../libext3cow/libext3cow.la \
|
||||
../boost/format/libformat.la
|
||||
|
||||
BUILT_SOURCES = derivations-ast.cc derivations-ast.hh
|
||||
|
||||
EXTRA_DIST = derivations-ast.def derivations-ast.cc
|
||||
|
||||
AM_CXXFLAGS = -Wall \
|
||||
-I$(srcdir)/.. ${bdb_include} ${aterm_include} -I$(srcdir)/../libutil
|
||||
-I$(srcdir)/.. ${bdb_include} ${aterm_include} -I$(srcdir)/../libutil -I$(srcdir)/../nix-state -I$(srcdir)/../libext3cow
|
||||
|
||||
derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
|
||||
$(perl) $(srcdir)/../aterm-helper.pl derivations-ast.hh derivations-ast.cc < $(srcdir)/derivations-ast.def
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
12
src/libstore/build.hh
Normal file
12
src/libstore/build.hh
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef BUILD_HH_
|
||||
#define BUILD_HH_
|
||||
|
||||
#include "db.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
void ensurePathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
}
|
||||
|
||||
#endif /*BUILD_HH_*/
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "db.hh"
|
||||
#include "util.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "derivations.hh"
|
||||
#include "local-store.hh"
|
||||
#include "misc.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -68,7 +71,7 @@ Transaction::~Transaction()
|
||||
void Transaction::begin(Database & db)
|
||||
{
|
||||
assert(txn == 0);
|
||||
db.requireEnv();
|
||||
db.requireEnv("begin transaction");
|
||||
try {
|
||||
db.env->txn_begin(0, &txn, 0);
|
||||
} catch (DbException e) { rethrow(e); }
|
||||
@@ -107,11 +110,11 @@ void Transaction::moveTo(Transaction & t)
|
||||
}
|
||||
|
||||
|
||||
void Database::requireEnv()
|
||||
void Database::requireEnv(string debug)
|
||||
{
|
||||
checkInterrupt();
|
||||
if (!env) throw Error("database environment is not open "
|
||||
"(maybe you don't have sufficient permission?)");
|
||||
if (!env) throw Error(format("database environment is not open while trying '%1%'"
|
||||
"(maybe you don't have sufficient permission?)") % debug);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +145,15 @@ Database::~Database()
|
||||
|
||||
void openEnv(DbEnv * & env, const string & path, u_int32_t flags)
|
||||
{
|
||||
try {
|
||||
createDirs(path);
|
||||
} catch (SysError & e) {
|
||||
if (e.errNo == EPERM || e.errNo == EACCES)
|
||||
throw DbNoPermission(format("cannot create the Nix database in `%1%'") % path);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
env->open(path.c_str(),
|
||||
DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN |
|
||||
@@ -185,7 +197,8 @@ void Database::open2(const string & path, bool removeOldEnv)
|
||||
|
||||
env->set_errcall(errorPrinter);
|
||||
env->set_msgcall(messagePrinter);
|
||||
//env->set_verbose(DB_VERB_REGISTER, 1);
|
||||
if (getEnv("NIX_DEBUG_DB_REGISTER") == "1")
|
||||
env->set_verbose(DB_VERB_REGISTER, 1);
|
||||
env->set_verbose(DB_VERB_RECOVERY, 1);
|
||||
|
||||
/* Smaller log files. */
|
||||
@@ -203,9 +216,9 @@ void Database::open2(const string & path, bool removeOldEnv)
|
||||
run db_recover on the database to remove the existing DB
|
||||
environment (since changes only take effect on new
|
||||
environments). */
|
||||
env->set_lk_max_locks(10000);
|
||||
env->set_lk_max_lockers(10000);
|
||||
env->set_lk_max_objects(10000);
|
||||
env->set_lk_max_locks(100000);
|
||||
env->set_lk_max_lockers(100000);
|
||||
env->set_lk_max_objects(100000);
|
||||
env->set_lk_detect(DB_LOCK_DEFAULT);
|
||||
|
||||
/* Dangerous, probably, but from the docs it *seems* that BDB
|
||||
@@ -297,7 +310,7 @@ void Database::close()
|
||||
|
||||
TableId Database::openTable(const string & tableName, bool sorted)
|
||||
{
|
||||
requireEnv();
|
||||
requireEnv(tableName);
|
||||
TableId table = nextId++;
|
||||
|
||||
try {
|
||||
@@ -444,5 +457,16 @@ void Database::enumTable(const Transaction & txn, TableId table,
|
||||
} catch (DbException e) { rethrow(e); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Database::clearTable(const Transaction & txn, TableId table)
|
||||
{
|
||||
try {
|
||||
Db * db = getDb(table);
|
||||
u_int32_t count;
|
||||
db->truncate(txn.txn, &count, 0);
|
||||
} catch (DbException e) { rethrow(e); }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -54,12 +54,14 @@ private:
|
||||
TableId nextId;
|
||||
std::map<TableId, Db *> tables;
|
||||
|
||||
void requireEnv();
|
||||
void requireEnv(string debug);
|
||||
|
||||
Db * getDb(TableId table);
|
||||
|
||||
void open2(const string & path, bool removeOldEnv);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
Database();
|
||||
~Database();
|
||||
@@ -89,6 +91,8 @@ public:
|
||||
|
||||
void enumTable(const Transaction & txn, TableId table,
|
||||
Strings & keys, const string & keyPrefix = "");
|
||||
|
||||
void clearTable(const Transaction & txn, TableId table);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
init initDerivationsHelpers
|
||||
|
||||
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm |
|
||||
|
||||
Derive | ATermList ATermList ATermList ATermList ATermList string string ATermList ATermList | ATerm |
|
||||
| string string | ATerm | EnvBinding |
|
||||
| string ATermList | ATerm | DerivationInput |
|
||||
| string string string string | ATerm | DerivationOutput |
|
||||
| string string string string string string string string string string string string string string | ATerm | DerivationStateOutput |
|
||||
| string string string | ATerm | DerivationStateOutputDir |
|
||||
|
||||
#We use DeriveWithOutState to create derivations that dont use state, and thus dont have the stateDerivationStateOutput and DerivationStateOutputDir in their derivation
|
||||
#Ive put this in becuase its easy to stay backwards compatible, but maybe it should be removed somtime to prevent confusion & duplication
|
||||
#The function will be called matchDerivateWithOutState, but it will match the Derive term to remain backwards compatible
|
||||
|
||||
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm | DeriveWithOutState
|
||||
| string string | ATerm | EnvBindingWithOutState |
|
||||
| string ATermList | ATerm | DerivationInputWithOutState |
|
||||
| string string string string | ATerm | DerivationOutputWithOutState |
|
||||
|
||||
#end drv without state
|
||||
|
||||
Closure | ATermList ATermList | ATerm | OldClosure |
|
||||
| string ATermList | ATerm | OldClosureElem |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "store-api.hh"
|
||||
#include "aterm.hh"
|
||||
#include "globals.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include "derivations-ast.hh"
|
||||
#include "derivations-ast.cc"
|
||||
@@ -20,12 +21,12 @@ Path writeDerivation(const Derivation & drv, const string & name)
|
||||
{
|
||||
PathSet references;
|
||||
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
||||
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin();
|
||||
i != drv.inputDrvs.end(); ++i)
|
||||
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
||||
references.insert(i->first);
|
||||
/* Note that the outputs of a derivation are *not* references
|
||||
(that can be missing (of course) and should not necessarily be
|
||||
held during a garbage collection). */
|
||||
|
||||
string suffix = name + drvExtension;
|
||||
string contents = atPrint(unparseDerivation(drv));
|
||||
return readOnlyMode
|
||||
@@ -66,9 +67,14 @@ Derivation parseDerivation(ATerm t)
|
||||
{
|
||||
Derivation drv;
|
||||
ATermList outs, inDrvs, inSrcs, args, bnds;
|
||||
ATermList stateOuts = ATempty, stateOutDirs = ATempty;
|
||||
|
||||
ATerm builder, platform;
|
||||
|
||||
if (!matchDerive(t, outs, inDrvs, inSrcs, platform, builder, args, bnds))
|
||||
bool withState;
|
||||
if (matchDerive(t, outs, stateOuts, stateOutDirs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = true; }
|
||||
else if (matchDeriveWithOutState(t, outs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = false; }
|
||||
else
|
||||
throwBadDrv(t);
|
||||
|
||||
for (ATermIterator i(outs); i; ++i) {
|
||||
@@ -82,6 +88,46 @@ Derivation parseDerivation(ATerm t)
|
||||
out.hash = aterm2String(hash);
|
||||
drv.outputs[aterm2String(id)] = out;
|
||||
}
|
||||
|
||||
if(withState)
|
||||
{
|
||||
//parse state part
|
||||
for (ATermIterator i(stateOuts); i; ++i) {
|
||||
ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState, externalState; //TODO unitialized warning
|
||||
if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shareType, synchronization, createDirsBeforeInstall, runtimeStateArgs, username, sharedState, externalState))
|
||||
throwBadDrv(t);
|
||||
DerivationStateOutput stateOut;
|
||||
stateOut.statepath = aterm2String(statepath);
|
||||
stateOut.componentHash = aterm2String(componentHash);
|
||||
//checkPath(stateOut.path); //should we check the statpath .... ???
|
||||
stateOut.hashAlgo = aterm2String(hashAlgo);
|
||||
stateOut.hash = aterm2String(hash);
|
||||
stateOut.stateIdentifier = aterm2String(stateIdentifier);
|
||||
stateOut.enabled = aterm2String(enabled);
|
||||
stateOut.shareType = aterm2String(shareType);
|
||||
stateOut.synchronization = aterm2String(synchronization);
|
||||
stateOut.createDirsBeforeInstall = aterm2String(createDirsBeforeInstall);
|
||||
stateOut.runtimeStateArgs = aterm2String(runtimeStateArgs);
|
||||
stateOut.username = aterm2String(username);
|
||||
stateOut.sharedState = aterm2String(sharedState);
|
||||
stateOut.externalState = aterm2String(externalState);
|
||||
drv.stateOutputs[aterm2String(id)] = stateOut;
|
||||
}
|
||||
|
||||
//parse state dirs part
|
||||
for (ATermIterator i(stateOutDirs); i; ++i) {
|
||||
ATerm id, path, type, interval;
|
||||
if (!matchDerivationStateOutputDir(*i, id, type, interval))
|
||||
throwBadDrv(t);
|
||||
path = id; //We prevent duplication since the key is also the path
|
||||
DerivationStateOutputDir stateOutDirs;
|
||||
stateOutDirs.path = aterm2String(path);
|
||||
stateOutDirs.type = aterm2String(type);
|
||||
stateOutDirs.interval = aterm2String(interval);
|
||||
drv.stateOutputDirs[aterm2String(id)] = stateOutDirs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (ATermIterator i(inDrvs); i; ++i) {
|
||||
ATerm drvPath;
|
||||
@@ -120,8 +166,7 @@ Derivation parseDerivation(ATerm t)
|
||||
ATerm unparseDerivation(const Derivation & drv)
|
||||
{
|
||||
ATermList outputs = ATempty;
|
||||
for (DerivationOutputs::const_reverse_iterator i = drv.outputs.rbegin();
|
||||
i != drv.outputs.rend(); ++i)
|
||||
for (DerivationOutputs::const_reverse_iterator i = drv.outputs.rbegin(); i != drv.outputs.rend(); ++i)
|
||||
outputs = ATinsert(outputs,
|
||||
makeDerivationOutput(
|
||||
toATerm(i->first),
|
||||
@@ -129,6 +174,42 @@ ATerm unparseDerivation(const Derivation & drv)
|
||||
toATerm(i->second.hashAlgo),
|
||||
toATerm(i->second.hash)));
|
||||
|
||||
//decide if we need to add state to the derivation
|
||||
bool createState = false;
|
||||
|
||||
ATermList stateOutputs = ATempty;
|
||||
for (DerivationStateOutputs::const_reverse_iterator i = drv.stateOutputs.rbegin(); i != drv.stateOutputs.rend(); ++i){
|
||||
if(i->second.enabled == "true"){
|
||||
createState = true;
|
||||
}
|
||||
stateOutputs = ATinsert(stateOutputs,
|
||||
makeDerivationStateOutput(
|
||||
toATerm(i->first),
|
||||
toATerm(i->second.statepath),
|
||||
toATerm(i->second.componentHash),
|
||||
toATerm(i->second.hashAlgo),
|
||||
toATerm(i->second.hash),
|
||||
toATerm(i->second.stateIdentifier),
|
||||
toATerm(i->second.enabled),
|
||||
toATerm(i->second.shareType),
|
||||
toATerm(i->second.synchronization),
|
||||
toATerm(i->second.createDirsBeforeInstall),
|
||||
toATerm(i->second.runtimeStateArgs),
|
||||
toATerm(i->second.username),
|
||||
toATerm(i->second.sharedState),
|
||||
toATerm(i->second.externalState)
|
||||
));
|
||||
}
|
||||
|
||||
ATermList stateOutputDirs = ATempty;
|
||||
for (DerivationStateOutputDirs::const_reverse_iterator i = drv.stateOutputDirs.rbegin(); i != drv.stateOutputDirs.rend(); ++i)
|
||||
stateOutputDirs = ATinsert(stateOutputDirs,
|
||||
makeDerivationStateOutputDir(
|
||||
toATerm(i->first),
|
||||
toATerm(i->second.type),
|
||||
toATerm(i->second.interval)
|
||||
));
|
||||
|
||||
ATermList inDrvs = ATempty;
|
||||
for (DerivationInputs::const_reverse_iterator i = drv.inputDrvs.rbegin();
|
||||
i != drv.inputDrvs.rend(); ++i)
|
||||
@@ -150,14 +231,28 @@ ATerm unparseDerivation(const Derivation & drv)
|
||||
toATerm(i->first),
|
||||
toATerm(i->second)));
|
||||
|
||||
return makeDerive(
|
||||
outputs,
|
||||
inDrvs,
|
||||
toATermList(drv.inputSrcs),
|
||||
toATerm(drv.platform),
|
||||
toATerm(drv.builder),
|
||||
args,
|
||||
env);
|
||||
if(createState){
|
||||
return makeDerive(
|
||||
outputs,
|
||||
stateOutputs,
|
||||
stateOutputDirs,
|
||||
inDrvs,
|
||||
toATermList(drv.inputSrcs),
|
||||
toATerm(drv.platform),
|
||||
toATerm(drv.builder),
|
||||
args,
|
||||
env);
|
||||
}
|
||||
else{
|
||||
return makeDeriveWithOutState(
|
||||
outputs,
|
||||
inDrvs,
|
||||
toATermList(drv.inputSrcs),
|
||||
toATerm(drv.platform),
|
||||
toATerm(drv.builder),
|
||||
args,
|
||||
env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
typedef struct _ATerm * ATerm;
|
||||
|
||||
#include "hash.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -20,8 +21,8 @@ const string drvExtension = ".drv";
|
||||
struct DerivationOutput
|
||||
{
|
||||
Path path;
|
||||
string hashAlgo; /* hash used for expected hash computation */
|
||||
string hash; /* expected hash, may be null */
|
||||
string hashAlgo; /* hash used for expected hash computation */
|
||||
string hash; /* expected hash, may be null */
|
||||
DerivationOutput()
|
||||
{
|
||||
}
|
||||
@@ -33,17 +34,147 @@ struct DerivationOutput
|
||||
}
|
||||
};
|
||||
|
||||
struct DerivationStateOutput
|
||||
{
|
||||
Path statepath;
|
||||
string componentHash;
|
||||
string hashAlgo;
|
||||
string hash;
|
||||
string stateIdentifier; //the identifier
|
||||
string enabled; //enable or disable state
|
||||
string shareType; //none, full, group
|
||||
string synchronization; //none (no locks), exclusive-lock, recursive-exclusive-lock
|
||||
|
||||
string commitReferences; //TODO none, direct, recursive-all
|
||||
string commitBinaries; //TODO list of binaries that need (or not) to be committed when these binaries are called
|
||||
|
||||
string createDirsBeforeInstall; //if true: creates state dirs before installation
|
||||
string runtimeStateArgs; //if not empty: these are the runtime parameters where state can be found (you can use $statepath here)
|
||||
|
||||
string username;
|
||||
|
||||
string sharedState; //Path to share state From
|
||||
|
||||
string externalState; //a statePath not not in the stateStore (Official hack)
|
||||
|
||||
DerivationStateOutput()
|
||||
{
|
||||
}
|
||||
|
||||
//TODO add const ??
|
||||
DerivationStateOutput(Path statepath, string componentHash, string hashAlgo, string hash, string stateIdentifier, string enabled, string shareType, string synchronization, string createDirsBeforeInstall, string runtimeStateArgs, string username, string sharedState, string externalState, bool check=true)
|
||||
{
|
||||
if(check){
|
||||
if(shareType != "none" && shareType != "full" && shareType != "group")
|
||||
throw Error(format("shareType '%1%' is not a correct type") % shareType);
|
||||
if(synchronization != "none" && synchronization != "exclusive-lock" && synchronization != "recursive-exclusive-lock")
|
||||
throw Error(format("synchronization '%1%' is not a correct type") % synchronization);
|
||||
if(username == "")
|
||||
throw Error(format("Username cannot be empty"));
|
||||
if(stateIdentifier == "__EMTPY__" || stateIdentifier == "__NOSTATE__")
|
||||
throw Error(format("the stateIdenfier cannot be this value '%1%'") % stateIdentifier);
|
||||
if(runtimeStateArgs == "__NOARGS__")
|
||||
throw Error(format("the runtimeStateArgs cannot be this value '%1%'") % runtimeStateArgs);
|
||||
if(externalState != "" && sharedState != "")
|
||||
throw Error(format("You cannot have an externalState and sharedState at the same time"));
|
||||
}
|
||||
|
||||
//TODO
|
||||
//commitReferences
|
||||
//commitBinaries
|
||||
|
||||
this->statepath = statepath;
|
||||
this->componentHash = componentHash;
|
||||
this->hashAlgo = hashAlgo;
|
||||
this->hash = hash;
|
||||
this->stateIdentifier = stateIdentifier;
|
||||
this->enabled = enabled;
|
||||
this->shareType = shareType;
|
||||
this->synchronization = synchronization;
|
||||
this->createDirsBeforeInstall = createDirsBeforeInstall;
|
||||
this->runtimeStateArgs = runtimeStateArgs;
|
||||
this->username = username;
|
||||
this->sharedState = sharedState;
|
||||
this->externalState = externalState;
|
||||
}
|
||||
|
||||
bool getEnabled(){
|
||||
return string2bool(enabled);
|
||||
}
|
||||
|
||||
bool getCreateDirsBeforeInstall(){
|
||||
return string2bool(createDirsBeforeInstall);
|
||||
}
|
||||
|
||||
/*
|
||||
* This sets all the paramters to "" to ensure they're not taken into account for the hash calculation in primops.cc
|
||||
*/
|
||||
void clearAllRuntimeParamters(){
|
||||
this->statepath = "";
|
||||
this->componentHash = "";
|
||||
//this->hashAlgo; //Clear this one?
|
||||
//this->hash; //Clear this one?
|
||||
//this->stateIdentifier; //Changes the statepath directly
|
||||
this->enabled = "";
|
||||
this->shareType = "";
|
||||
this->synchronization = "";
|
||||
this->createDirsBeforeInstall = "";
|
||||
this->runtimeStateArgs = "";
|
||||
//this->username; //Changes the statepath directly
|
||||
this->sharedState = "";
|
||||
this->externalState = "";
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct DerivationStateOutputDir
|
||||
{
|
||||
string path;
|
||||
string type; //none, manual, interval, full
|
||||
string interval; //type int
|
||||
DerivationStateOutputDir()
|
||||
{
|
||||
}
|
||||
DerivationStateOutputDir(string path, string type, string interval)
|
||||
{
|
||||
if(type != "none" && type != "manual" && type != "interval" && type != "full")
|
||||
throw Error(format("interval '%1%' is not a correct type") % type);
|
||||
|
||||
this->path = path;
|
||||
this->type = type;
|
||||
this->interval = interval;
|
||||
}
|
||||
|
||||
int getInterval(){
|
||||
if(interval == "")
|
||||
return 0;
|
||||
else{
|
||||
int i;
|
||||
if (!string2Int(interval, i)) throw Error("interval is not a number");
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//sort function
|
||||
bool operator<(const DerivationStateOutputDir& a) const { return path < a.path; }
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<string, DerivationOutput> DerivationOutputs;
|
||||
typedef std::map<string, DerivationStateOutput> DerivationStateOutputs;
|
||||
typedef std::map<string, DerivationStateOutputDir> DerivationStateOutputDirs;
|
||||
|
||||
|
||||
/* For inputs that are sub-derivations, we specify exactly which
|
||||
output IDs we are interested in. */
|
||||
typedef std::map<Path, StringSet> DerivationInputs;
|
||||
|
||||
typedef std::map<string, string> StringPairs;
|
||||
|
||||
struct Derivation
|
||||
{
|
||||
DerivationOutputs outputs; /* keyed on symbolic IDs */
|
||||
DerivationStateOutputs stateOutputs; /* TODO */
|
||||
DerivationStateOutputDirs stateOutputDirs; /* TODO */
|
||||
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
|
||||
PathSet inputSrcs; /* inputs that are sources */
|
||||
string platform;
|
||||
|
||||
@@ -26,6 +26,8 @@ static string gcLockName = "gc.lock";
|
||||
static string tempRootsDir = "temproots";
|
||||
static string gcRootsDir = "gcroots";
|
||||
|
||||
static const int defaultGcLevel = 1000;
|
||||
|
||||
|
||||
/* Acquire the global GC lock. This is used to prevent new Nix
|
||||
processes from starting after the temporary root files have been
|
||||
@@ -61,6 +63,8 @@ void createSymlink(const Path & link, const Path & target, bool careful)
|
||||
/* Create directories up to `gcRoot'. */
|
||||
createDirs(dirOf(link));
|
||||
|
||||
/* !!! shouldn't removing and creating the symlink be atomic? */
|
||||
|
||||
/* Remove the old symlink. */
|
||||
if (pathExists(link)) {
|
||||
if (careful && (!isLink(link) || !isInStore(readLink(link))))
|
||||
@@ -68,7 +72,7 @@ void createSymlink(const Path & link, const Path & target, bool careful)
|
||||
unlink(link.c_str());
|
||||
}
|
||||
|
||||
/* And create the new own. */
|
||||
/* And create the new one. */
|
||||
if (symlink(target.c_str(), link.c_str()) == -1)
|
||||
throw SysError(format("symlinking `%1%' to `%2%'")
|
||||
% link % target);
|
||||
@@ -97,6 +101,11 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
||||
Path gcRoot(canonPath(_gcRoot));
|
||||
assertStorePath(storePath);
|
||||
|
||||
if (isInStore(gcRoot))
|
||||
throw Error(format(
|
||||
"creating a garbage collector root (%1%) in the Nix store is forbidden "
|
||||
"(are you running nix-build inside the store?)") % gcRoot);
|
||||
|
||||
if (indirect) {
|
||||
createSymlink(gcRoot, storePath, true);
|
||||
store->addIndirectRoot(gcRoot);
|
||||
@@ -114,7 +123,6 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
||||
}
|
||||
|
||||
createSymlink(gcRoot, storePath, false);
|
||||
|
||||
}
|
||||
|
||||
/* Check that the root can be found by the garbage collector. */
|
||||
@@ -401,12 +409,13 @@ static void addAdditionalRoots(PathSet & roots)
|
||||
static void dfsVisit(const PathSet & paths, const Path & path,
|
||||
PathSet & visited, Paths & sorted)
|
||||
{
|
||||
if (visited.find(path) != visited.end()) return;
|
||||
if (visited.find(path) != visited.end())
|
||||
return;
|
||||
visited.insert(path);
|
||||
|
||||
PathSet references;
|
||||
if (store->isValidPath(path))
|
||||
store->queryReferences(path, references);
|
||||
store->queryStoreReferences(path, references, 0);
|
||||
|
||||
for (PathSet::iterator i = references.begin();
|
||||
i != references.end(); ++i)
|
||||
@@ -418,6 +427,8 @@ static void dfsVisit(const PathSet & paths, const Path & path,
|
||||
sorted.push_front(path);
|
||||
}
|
||||
|
||||
//TODO maybe? stateTopoSortPaths(const PathSet & paths)
|
||||
|
||||
|
||||
Paths topoSortPaths(const PathSet & paths)
|
||||
{
|
||||
@@ -429,7 +440,7 @@ Paths topoSortPaths(const PathSet & paths)
|
||||
}
|
||||
|
||||
|
||||
void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete, //TODO ? statePathsToDelete
|
||||
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed)
|
||||
{
|
||||
result.clear();
|
||||
@@ -439,11 +450,15 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
queryBoolSetting("gc-keep-outputs", false);
|
||||
bool gcKeepDerivations =
|
||||
queryBoolSetting("gc-keep-derivations", true);
|
||||
int gcKeepOutputsThreshold =
|
||||
queryIntSetting ("gc-keep-outputs-threshold", defaultGcLevel);
|
||||
|
||||
//printMsg(lvlError, format("gcKeepOutputs %1% gcKeepDerivations: %2%") % gcKeepOutputs % gcKeepDerivations);
|
||||
|
||||
/* Acquire the global GC root. This prevents
|
||||
a) New roots from being added.
|
||||
b) Processes from creating new temporary root files. */
|
||||
AutoCloseFD fdGCLock = openGCLock(ltWrite);
|
||||
AutoCloseFD fdGCLock = openGCLock(ltWrite); //TODO !!!!!!!!!!!!!!!!!!! GET STATE LOCKS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
/* Find the roots. Since we've grabbed the GC lock, the set of
|
||||
permanent roots cannot increase now. */
|
||||
@@ -452,6 +467,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
PathSet roots;
|
||||
for (Roots::iterator i = rootMap.begin(); i != rootMap.end(); ++i)
|
||||
roots.insert(i->second);
|
||||
|
||||
|
||||
/* Add additional roots returned by the program specified by the
|
||||
NIX_ROOT_FINDER environment variable. This is typically used
|
||||
@@ -469,32 +485,85 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
roots under the `references' relation. */
|
||||
PathSet livePaths;
|
||||
for (PathSet::const_iterator i = roots.begin(); i != roots.end(); ++i)
|
||||
computeFSClosure(canonPath(*i), livePaths);
|
||||
computeFSClosure(canonPath(*i), livePaths, true, true, 0);
|
||||
|
||||
/* Note that the deriver need not be valid (e.g., if we
|
||||
previously ran the collector with `gcKeepDerivations'
|
||||
turned off). */
|
||||
if (gcKeepDerivations) {
|
||||
for (PathSet::iterator i = livePaths.begin();
|
||||
i != livePaths.end(); ++i)
|
||||
for (PathSet::iterator i = livePaths.begin(); i != livePaths.end(); ++i)
|
||||
{
|
||||
/* Note that the deriver need not be valid (e.g., if we
|
||||
previously ran the collector with `gcKeepDerivations'
|
||||
turned off). */
|
||||
Path deriver = queryDeriver(noTxn, *i);
|
||||
if (deriver != "" && store->isValidPath(deriver))
|
||||
computeFSClosure(deriver, livePaths);
|
||||
if (store->isStateComponent(*i)){
|
||||
//printMsg(lvlError, format("Live state store '%1%'") % *i);
|
||||
|
||||
PathSet derivers = store->queryDerivers(*i); //we select ALL state Derivations here
|
||||
for (PathSet::const_iterator j = derivers.begin(); j != derivers.end(); ++j)
|
||||
if (*j != "" && store->isValidPath(*j))
|
||||
computeFSClosure(*j, livePaths, true, true, 0);
|
||||
}
|
||||
else if (store->isValidPath(*i)){
|
||||
//printMsg(lvlError, format("Live Store '%1%'") % *i);
|
||||
|
||||
Path deriver = store->queryDeriver(*i);
|
||||
if (deriver != "" && store->isValidPath(deriver))
|
||||
computeFSClosure(deriver, livePaths, true, true, 0);
|
||||
}
|
||||
else if (store->isValidStatePath(*i)){
|
||||
//printMsg(lvlError, format("Live State '%1%'") % *i);
|
||||
Path deriver = queryStatePathDrvTxn(noTxn, *i);
|
||||
|
||||
if(!store->isValidPath(deriver))
|
||||
throw Error(format("deriver `%1%' of state-store component `%2%' in GC is not valid") % deriver % *i);
|
||||
|
||||
computeFSClosure(deriver, livePaths, true, true, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gcKeepOutputs) {
|
||||
/* Hmz, identical to storePathRequisites in nix-store. */
|
||||
for (PathSet::iterator i = livePaths.begin();
|
||||
i != livePaths.end(); ++i)
|
||||
for (PathSet::iterator i = livePaths.begin(); i != livePaths.end(); ++i)
|
||||
if (isDerivation(*i)) {
|
||||
Derivation drv = derivationFromPath(*i);
|
||||
Derivation drv = derivationFromPathTxn(noTxn, *i);
|
||||
|
||||
/*
|
||||
* TODO REMOVE
|
||||
<<<<<<< .working
|
||||
for (DerivationOutputs::iterator j = drv.outputs.begin();
|
||||
j != drv.outputs.end(); ++j)
|
||||
if (store->isValidPath(j->second.path))
|
||||
computeFSClosure(j->second.path, livePaths);
|
||||
}
|
||||
computeFSClosure(j->second.path, livePaths, true, true, 0);
|
||||
else if (store->isValidStatePath(j->second.path))
|
||||
computeFSClosure(j->second.path, livePaths, true, true, 0);
|
||||
=======
|
||||
|
||||
|
||||
string gcLevelStr = drv.env["__gcLevel"];
|
||||
int gcLevel;
|
||||
if (!string2Int(gcLevelStr,gcLevel)) {
|
||||
gcLevel = defaultGcLevel;
|
||||
}
|
||||
|
||||
if (gcLevel >= gcKeepOutputsThreshold)
|
||||
for (DerivationOutputs::iterator j = drv.outputs.begin();
|
||||
j != drv.outputs.end(); ++j)
|
||||
if (store->isValidPath(j->second.path) || store->isValidStatePath(j->second.path))
|
||||
computeFSClosure(j->second.path, livePaths, true, true, 0);
|
||||
}
|
||||
=======
|
||||
*/
|
||||
|
||||
string gcLevelStr = drv.env["__gcLevel"];
|
||||
int gcLevel;
|
||||
if (!string2Int(gcLevelStr, gcLevel))
|
||||
gcLevel = defaultGcLevel;
|
||||
|
||||
if (gcLevel >= gcKeepOutputsThreshold)
|
||||
for (DerivationOutputs::iterator j = drv.outputs.begin();
|
||||
j != drv.outputs.end(); ++j)
|
||||
if (store->isValidPath(j->second.path) || store->isValidStatePath(j->second.path))
|
||||
computeFSClosure(j->second.path, livePaths, true, true, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (action == gcReturnLive) {
|
||||
@@ -508,7 +577,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
PathSet tempRoots;
|
||||
FDs fds;
|
||||
readTempRoots(tempRoots, fds);
|
||||
|
||||
|
||||
/* Close the temporary roots. Note that we *cannot* do this in
|
||||
readTempRoots(), because there we may not have all locks yet,
|
||||
meaning that an invalid path can become valid (and thus add to
|
||||
@@ -518,7 +587,9 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
PathSet tempRootsClosed;
|
||||
for (PathSet::iterator i = tempRoots.begin(); i != tempRoots.end(); ++i)
|
||||
if (store->isValidPath(*i))
|
||||
computeFSClosure(*i, tempRootsClosed);
|
||||
computeFSClosure(*i, tempRootsClosed, true, true, 0);
|
||||
else if(store->isValidStatePath(*i))
|
||||
computeFSClosure(*i, tempRootsClosed, true, true, 0);
|
||||
else
|
||||
tempRootsClosed.insert(*i);
|
||||
|
||||
@@ -531,29 +602,67 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
that is not currently in in `livePaths' or `tempRootsClosed'
|
||||
can be deleted. */
|
||||
|
||||
/* Read the Nix store directory to find all currently existing
|
||||
/*
|
||||
* We lookup all state (also shared) paths for: livePaths, tempRootsClosed
|
||||
*/
|
||||
PathSet allLiveStatePaths;
|
||||
for (PathSet::iterator i = livePaths.begin(); i != livePaths.end(); ++i)
|
||||
if(store->isValidStatePath(*i)){
|
||||
allLiveStatePaths.insert(*i);
|
||||
allLiveStatePaths = pathSets_union(getSharedWithPathSetRecTxn(noTxn, *i), allLiveStatePaths);
|
||||
}
|
||||
for (PathSet::iterator i = tempRootsClosed.begin(); i != tempRootsClosed.end(); ++i)
|
||||
if(store->isValidStatePath(*i)){
|
||||
allLiveStatePaths.insert(*i);
|
||||
allLiveStatePaths = pathSets_union(getSharedWithPathSetRecTxn(noTxn, *i), allLiveStatePaths);
|
||||
}
|
||||
|
||||
|
||||
/* Read the Nix store and state directory's to find all currently existing
|
||||
paths. */
|
||||
PathSet storePathSet;
|
||||
PathSet statePathSet;
|
||||
|
||||
if (action != gcDeleteSpecific) {
|
||||
|
||||
Paths entries = readDirectory(nixStore);
|
||||
Paths stateEntries = readDirectory(nixStoreState);
|
||||
|
||||
for (Paths::iterator i = entries.begin(); i != entries.end(); ++i)
|
||||
storePathSet.insert(canonPath(nixStore + "/" + *i));
|
||||
|
||||
for (Paths::iterator i = stateEntries.begin(); i != stateEntries.end(); ++i)
|
||||
statePathSet.insert(canonPath(nixStoreState + "/" + *i));
|
||||
|
||||
} else {
|
||||
for (PathSet::iterator i = pathsToDelete.begin();
|
||||
i != pathsToDelete.end(); ++i)
|
||||
{
|
||||
assertStorePath(*i);
|
||||
assertStorePath(*i); //TODO ASSERTSTATEPATH, but for now we have no arg statePathsToDelete
|
||||
storePathSet.insert(*i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Topologically sort them under the `referrers' relation. That
|
||||
is, a < b iff a is in referrers(b). This gives us the order in
|
||||
is, a < b if a is in referrers(b). This gives us the order in
|
||||
which things can be deleted safely. */
|
||||
/* !!! when we have multiple output paths per derivation, this
|
||||
will not work anymore because we get cycles. */
|
||||
Paths storePaths = topoSortPaths(storePathSet);
|
||||
|
||||
for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i) {
|
||||
|
||||
if(*i != "/nix/store/zg8x9wdhcs4j0hvf33vg34c7m65adrpa-env-manifest")
|
||||
continue;
|
||||
|
||||
PathSet references;
|
||||
store->queryStoreReferences(*i, references, 0);
|
||||
for (PathSet::iterator j = references.begin(); j != references.end(); ++j) {
|
||||
printMsg(lvlError, format("REF `%1%'") % *j);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Try to delete store paths in the topologically sorted order. */
|
||||
for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i) {
|
||||
|
||||
@@ -570,7 +679,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
debug(format("temporary root `%1%'") % *i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
debug(format("dead path `%1%'") % *i);
|
||||
result.insert(*i);
|
||||
|
||||
@@ -598,7 +707,9 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
}
|
||||
#endif
|
||||
|
||||
printMsg(lvlInfo, format("deleting `%1%'") % *i);
|
||||
if (!pathExists(*i)) continue;
|
||||
|
||||
printMsg(lvlInfo, format("deleting store path `%1%'") % *i);
|
||||
|
||||
/* Okay, it's safe to delete. */
|
||||
try {
|
||||
@@ -607,7 +718,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
bytesFreed += freed;
|
||||
} catch (PathInUse & e) {
|
||||
printMsg(lvlError, format("warning: %1%") % e.msg());
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
if (fdLock != -1)
|
||||
@@ -616,6 +727,87 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to delete state paths. */
|
||||
/* Topologically sort them under the `referrers' relation. That
|
||||
is, a < b if a is in referrers(b). This gives us the order in
|
||||
which things can be deleted safely. */
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! when we have multiple output paths per derivation, this
|
||||
will not work anymore because we get cycles. */
|
||||
Paths statePaths;
|
||||
for (PathSet::iterator i = statePathSet.begin(); i != statePathSet.end(); ++i)
|
||||
statePaths.push_back(*i);
|
||||
|
||||
//
|
||||
for (Paths::iterator i = statePaths.begin(); i != statePaths.end(); ++i) {
|
||||
|
||||
debug(format("considering deletion of state path `%1%'") % *i);
|
||||
|
||||
if (allLiveStatePaths.find(*i) != allLiveStatePaths.end()) {
|
||||
debug(format("State path `%1%' is alive (possibyly shared with another live path)") % *i);
|
||||
continue;
|
||||
}
|
||||
|
||||
string lostAndFound = nixStoreState + "/lost+found";
|
||||
if(*i == lostAndFound){
|
||||
debug(format("Keeping `%1%' because its a special path") % lostAndFound);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug(format("dead path `%1%'") % *i);
|
||||
result.insert(*i);
|
||||
|
||||
/* If just returning the set of dead paths, we also return the
|
||||
space that would be freed if we deleted them. */
|
||||
if (action == gcReturnDead)
|
||||
bytesFreed += computePathSize(*i);
|
||||
|
||||
if (action == gcDeleteDead || action == gcDeleteSpecific) {
|
||||
|
||||
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! state locks
|
||||
/*
|
||||
#ifndef __CYGWIN__
|
||||
AutoCloseFD fdLock;
|
||||
|
||||
/* Only delete a lock file if we can acquire a write lock
|
||||
on it. That means that it's either stale, or the
|
||||
process that created it hasn't locked it yet. In the
|
||||
latter case the other process will detect that we
|
||||
deleted the lock, and retry (see pathlocks.cc). * /
|
||||
if (i->size() >= 5 && string(*i, i->size() - 5) == ".lock") {
|
||||
fdLock = openLockFile(*i, false);
|
||||
if (fdLock != -1 && !lockFile(fdLock, ltWrite, false)) {
|
||||
debug(format("skipping active lock `%1%'") % *i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (!pathExists(*i)) continue;
|
||||
|
||||
printMsg(lvlInfo, format("deleting state path `%1%'") % *i);
|
||||
|
||||
/* Okay, it's safe to delete. */
|
||||
try {
|
||||
unsigned long long freed;
|
||||
deleteFromState(*i, freed);
|
||||
bytesFreed += freed;
|
||||
} catch (PathInUse & e) {
|
||||
printMsg(lvlError, format("warning: %1%") % e.msg());
|
||||
}
|
||||
|
||||
/*
|
||||
#ifndef __CYGWIN__
|
||||
if (fdLock != -1)
|
||||
/* Write token to stale (deleted) lock file. * /
|
||||
writeFull(fdLock, (const unsigned char *) "d", 1);
|
||||
#endif
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
string nixStore = "/UNINIT";
|
||||
string nixStoreState = "/UNINIT";
|
||||
string nixDataDir = "/UNINIT";
|
||||
string nixLogDir = "/UNINIT";
|
||||
string nixStateDir = "/UNINIT";
|
||||
string nixDBPath = "/UNINIT";
|
||||
string nixExt3CowHeader = "/UNINIT";
|
||||
string nixRsync = "/UNINIT";
|
||||
string nixConfDir = "/UNINIT";
|
||||
string nixLibexecDir = "/UNINIT";
|
||||
string nixBinDir = "/UNINIT";
|
||||
@@ -25,10 +28,17 @@ unsigned int maxBuildJobs = 1;
|
||||
bool readOnlyMode = false;
|
||||
string thisSystem = "unset";
|
||||
unsigned int maxSilentTime = 0;
|
||||
Paths substituters;
|
||||
bool useBuildHook = true;
|
||||
|
||||
|
||||
static bool settingsRead = false;
|
||||
|
||||
uid_t callingUID = 0; //A root user will not set this value, so the default uid is 0
|
||||
bool singleThreaded = false; //TODO Gives an error: cannot start worker (environment already open) / waiting for process X: No child processes
|
||||
bool sendOutput = true;
|
||||
bool sleepForGDB = false;
|
||||
|
||||
static std::map<string, Strings> settings;
|
||||
|
||||
|
||||
@@ -114,5 +124,39 @@ unsigned int queryIntSetting(const string & name, unsigned int def)
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uid_t queryCallingUID()
|
||||
{
|
||||
/* A root user will not even bother calling the daemon, so there is no way to check
|
||||
* If the uid is not yet set...
|
||||
*/
|
||||
return callingUID;
|
||||
}
|
||||
|
||||
void setCallingUID(uid_t uid, bool reset)
|
||||
{
|
||||
if(callingUID != 0 && !reset)
|
||||
throw Error(format("The UID of the caller aleady set! at this point"));
|
||||
|
||||
callingUID = uid;
|
||||
}
|
||||
|
||||
string uidToUsername(uid_t uid)
|
||||
{
|
||||
passwd *pwd = getpwuid(uid);
|
||||
char *pw_name = pwd->pw_name;
|
||||
return (string)pw_name;
|
||||
}
|
||||
|
||||
string queryCallingUsername()
|
||||
{
|
||||
uid_t uid = queryCallingUID();
|
||||
return uidToUsername(uid);
|
||||
}
|
||||
|
||||
string queryCurrentUsername()
|
||||
{
|
||||
return uidToUsername(geteuid());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,12 +18,21 @@ extern string nixDataDir; /* !!! fix */
|
||||
/* nixLogDir is the directory where we log various operations. */
|
||||
extern string nixLogDir;
|
||||
|
||||
/* nixStoreState is the directory where the state dirs of the components are stored. */
|
||||
extern string nixStoreState;
|
||||
|
||||
/* nixStateDir is the directory where state is stored. */
|
||||
extern string nixStateDir;
|
||||
|
||||
/* nixDBPath is the path name of our Berkeley DB environment. */
|
||||
extern string nixDBPath;
|
||||
|
||||
/* nixExt3CowHeader is the header file used to communicate with ext3cow. */
|
||||
extern string nixExt3CowHeader;
|
||||
|
||||
/* nixRsync is used to copy from one statedir to the other. */
|
||||
extern string nixRsync;
|
||||
|
||||
/* nixConfDir is the directory where configuration files are
|
||||
stored. */
|
||||
extern string nixConfDir;
|
||||
@@ -35,7 +44,6 @@ extern string nixLibexecDir;
|
||||
/* nixBinDir is the directory where the main programs are stored. */
|
||||
extern string nixBinDir;
|
||||
|
||||
|
||||
/* Misc. global flags. */
|
||||
|
||||
/* Whether to keep temporary directories of failed builds. */
|
||||
@@ -67,6 +75,14 @@ extern string thisSystem;
|
||||
infinity. */
|
||||
extern unsigned int maxSilentTime;
|
||||
|
||||
/* The substituters. There are programs that can somehow realise a
|
||||
store path without building, e.g., by downloading it or copying it
|
||||
from a CD. */
|
||||
extern Paths substituters;
|
||||
|
||||
/* Whether to use build hooks (for distributed builds). Sometimes
|
||||
users want to disable this from the command-line. */
|
||||
extern bool useBuildHook;
|
||||
|
||||
Strings querySetting(const string & name, const Strings & def);
|
||||
|
||||
@@ -76,7 +92,27 @@ bool queryBoolSetting(const string & name, bool def);
|
||||
|
||||
unsigned int queryIntSetting(const string & name, unsigned int def);
|
||||
|
||||
|
||||
/* TODO PRIVATE: UID of the user that calls the nix-worker daemon */
|
||||
extern uid_t callingUID;
|
||||
|
||||
/* get/set the UID of the user that calls the nix-worker daemon */
|
||||
uid_t queryCallingUID();
|
||||
void setCallingUID(uid_t uid, bool reset = false);
|
||||
|
||||
/* Convert a uid to a username: Watch it! this segfaults when given a wrong uid !! */
|
||||
string uidToUsername(uid_t uid);
|
||||
|
||||
/* get the username based on the UID of the user that calls the nix-worker daemon */
|
||||
string queryCallingUsername();
|
||||
|
||||
/* get the username based on the UID of the user currently runs the process */
|
||||
string queryCurrentUsername();
|
||||
|
||||
/* Debugging variables */
|
||||
extern bool singleThreaded;
|
||||
extern bool sendOutput;
|
||||
extern bool sleepForGDB;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,16 +13,34 @@ class Transaction;
|
||||
|
||||
|
||||
/* Nix store and database schema version. Version 1 (or 0) was Nix <=
|
||||
0.7. Version 2 was Nix 0.8 and 0.8. Version 3 is Nix 0.10 and
|
||||
up. */
|
||||
const int nixSchemaVersion = 3;
|
||||
0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10.
|
||||
Version 4 is Nix 0.11. */
|
||||
const int nixSchemaVersion = 4;
|
||||
|
||||
|
||||
extern string drvsLogDir;
|
||||
|
||||
|
||||
struct OptimiseStats
|
||||
{
|
||||
unsigned long totalFiles;
|
||||
unsigned long sameContents;
|
||||
unsigned long filesLinked;
|
||||
unsigned long long bytesFreed;
|
||||
OptimiseStats()
|
||||
{
|
||||
totalFiles = sameContents = filesLinked = 0;
|
||||
bytesFreed = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class LocalStore : public StoreAPI
|
||||
{
|
||||
private:
|
||||
bool substitutablePathsLoaded;
|
||||
PathSet substitutablePaths;
|
||||
|
||||
public:
|
||||
|
||||
/* Open the database environment. If `reserveSpace' is true, make
|
||||
@@ -40,15 +58,31 @@ public:
|
||||
/* Implementations of abstract store API methods. */
|
||||
|
||||
bool isValidPath(const Path & path);
|
||||
|
||||
Substitutes querySubstitutes(const Path & srcPath);
|
||||
|
||||
|
||||
bool isValidStatePath(const Path & path);
|
||||
|
||||
bool isValidComponentOrStatePath(const Path & path);
|
||||
|
||||
PathSet queryValidPaths();
|
||||
|
||||
Hash queryPathHash(const Path & path);
|
||||
|
||||
Path queryStatePathDrv(const Path & statePath);
|
||||
|
||||
void queryReferences(const Path & path, PathSet & references);
|
||||
|
||||
void queryReferrers(const Path & path, PathSet & referrers);
|
||||
void queryStoreReferences(const Path & path, PathSet & references, const unsigned int revision);
|
||||
|
||||
void queryStateReferences(const Path & storePath, PathSet & stateReferences, const unsigned int revision);
|
||||
|
||||
void queryStoreReferrers(const Path & path, PathSet & referrers, const unsigned int revision);
|
||||
|
||||
void queryStateReferrers(const Path & path, PathSet & stateReferrers, const unsigned int revision);
|
||||
|
||||
Path queryDeriver(const Path & path);
|
||||
|
||||
PathSet querySubstitutablePaths();
|
||||
|
||||
bool hasSubstitutes(const Path & path);
|
||||
|
||||
Path addToStore(const Path & srcPath, bool fixed = false,
|
||||
bool recursive = false, string hashAlgo = "",
|
||||
PathFilter & filter = defaultPathFilter);
|
||||
@@ -75,6 +109,49 @@ public:
|
||||
|
||||
void collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
void setStatePathsInterval(const Path & statePath, const CommitIntervals & intervals);
|
||||
|
||||
CommitIntervals getStatePathsInterval(const Path & statePath);
|
||||
|
||||
bool isStateComponent(const Path & storePath);
|
||||
|
||||
void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool withComponents, const bool withState, const unsigned int revision);
|
||||
|
||||
void setStateRevisions(const RevisionClosure & revisions, const Path & rootStatePath, const string & comment);
|
||||
|
||||
bool queryStateRevisions(const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision);
|
||||
|
||||
bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions);
|
||||
|
||||
Snapshots commitStatePath(const Path & statePath);
|
||||
|
||||
PathSet queryDerivers(const Path & storePath); //should these be in here ????
|
||||
|
||||
void scanAndUpdateAllReferences(const Path & statePath, const bool recursive);
|
||||
|
||||
bool getSharedWith(const Path & statePath1, Path & statePath2);
|
||||
|
||||
PathSet toNonSharedPathSet(const PathSet & statePaths);
|
||||
|
||||
void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive);
|
||||
|
||||
void shareState(const Path & from, const Path & to, const bool snapshot);
|
||||
|
||||
void unShareState(const Path & path, const bool branch, const bool restoreOld);
|
||||
|
||||
Path lookupStatePath(const Path & storePath, const string & identifier, const string & user);
|
||||
|
||||
void setStateOptions(const Path & statePath, const string & user, const string & group, int chmod, const string & runtimeArgs);
|
||||
|
||||
void getStateOptions(const Path & statePath, string & user, string & group, int & chmod, string & runtimeArgs);
|
||||
|
||||
|
||||
/* Optimise the disk space usage of the Nix store by hard-linking
|
||||
files with the same contents. */
|
||||
void optimiseStore(bool dryRun, OptimiseStats & stats);
|
||||
};
|
||||
|
||||
|
||||
@@ -84,13 +161,6 @@ void createStoreTransaction(Transaction & txn);
|
||||
/* Copy a path recursively. */
|
||||
void copyPath(const Path & src, const Path & dst);
|
||||
|
||||
/* Register a substitute. */
|
||||
void registerSubstitute(const Transaction & txn,
|
||||
const Path & srcPath, const Substitute & sub);
|
||||
|
||||
/* Deregister all substitutes. */
|
||||
void clearSubstitutes();
|
||||
|
||||
/* Register the validity of a path, i.e., that `path' exists, that the
|
||||
paths referenced by it exists, and in the case of an output path of
|
||||
a derivation, that it has been produced by a succesful execution of
|
||||
@@ -98,16 +168,9 @@ void clearSubstitutes();
|
||||
of the file system contents of the path. The hash must be a
|
||||
SHA-256 hash. */
|
||||
void registerValidPath(const Transaction & txn,
|
||||
const Path & path, const Hash & hash, const PathSet & references,
|
||||
const Path & deriver);
|
||||
|
||||
struct ValidPathInfo
|
||||
{
|
||||
Path path;
|
||||
Path deriver;
|
||||
Hash hash;
|
||||
PathSet references;
|
||||
};
|
||||
const Path & component_or_state_path, const Hash & hash,
|
||||
const PathSet & references, const PathSet & stateReferences,
|
||||
const Path & deriver, const unsigned int revision);
|
||||
|
||||
typedef list<ValidPathInfo> ValidPathInfos;
|
||||
|
||||
@@ -127,22 +190,27 @@ void canonicalisePathMetaData(const Path & path);
|
||||
/* Checks whether a path is valid. */
|
||||
bool isValidPathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
/* Sets the set of outgoing FS references for a store path. Use with
|
||||
care! */
|
||||
void setReferences(const Transaction & txn, const Path & path,
|
||||
const PathSet & references);
|
||||
/* Sets the set of outgoing FS (also state) references for a store path. Use with
|
||||
care!
|
||||
|
||||
0 for revision means overwrite the last revision
|
||||
*/
|
||||
void setReferences(const Transaction & txn, const Path & store_or_statePath,
|
||||
const PathSet & references, const PathSet & stateReferences, const unsigned int revision);
|
||||
|
||||
/* Sets the deriver of a store path. Use with care! */
|
||||
void setDeriver(const Transaction & txn, const Path & path,
|
||||
const Path & deriver);
|
||||
|
||||
/* Query the deriver of a store path. Return the empty string if no
|
||||
deriver has been set. */
|
||||
Path queryDeriver(const Transaction & txn, const Path & path);
|
||||
/* Query the derivers of a state-store path. */
|
||||
PathSet queryDerivers(const Transaction & txn, const Path & storePath);
|
||||
|
||||
/* Delete a value from the nixStore directory. */
|
||||
void deleteFromStore(const Path & path, unsigned long long & bytesFreed);
|
||||
|
||||
/* Delete a value from the nixState directory. */
|
||||
void deleteFromState(const Path & _path, unsigned long long & bytesFreed);
|
||||
|
||||
MakeError(PathInUse, Error);
|
||||
|
||||
void verifyStore(bool checkContents);
|
||||
@@ -162,7 +230,67 @@ void deletePathWrapped(const Path & path,
|
||||
unsigned long long & bytesFreed);
|
||||
|
||||
void deletePathWrapped(const Path & path);
|
||||
|
||||
|
||||
/* Adds a new deriver based on storePath to the dbDerivers table */
|
||||
void addStateDeriver(const Transaction & txn, const Path & storePath, const Path & deriver);
|
||||
|
||||
bool isStateComponentTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
bool isStateDrvPathTxn(const Transaction & txn, const Path & drvPath);
|
||||
|
||||
bool isStateDrv(const Derivation & drv);
|
||||
|
||||
|
||||
//TODO CHECK IF THESE DONT BELONG HERE, REFACTOR CODE, EG MOVE FUNCTIONS AROUND
|
||||
|
||||
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
|
||||
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
void queryXReferencesTxn(const Transaction & txn, const Path & path, PathSet & references, const bool component_or_state, const unsigned int revision, const unsigned int timestamp = 0);
|
||||
|
||||
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
||||
void setStateStateReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
||||
|
||||
void queryStoreReferrersTxn(const Transaction & txn, const Path & storePath, PathSet & referrers, const unsigned int revision);
|
||||
void queryStateReferrersTxn(const Transaction & txn, const Path & storePath, PathSet & stateReferrers, const unsigned int revision);
|
||||
|
||||
Path queryStatePathDrvTxn(const Transaction & txn, const Path & statePath);
|
||||
void storePathRequisitesTxn(const Transaction & txn, const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool withComponents, const bool withState, const unsigned int revision);
|
||||
void setStateRevisionsTxn(const Transaction & txn, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment);
|
||||
|
||||
bool isValidPathTxn(const Transaction & txn, const Path & path);
|
||||
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
void setSolidStateReferencesTxn(const Transaction & txn, const Path & statePath, const PathSet & paths);
|
||||
bool querySolidStateReferencesTxn(const Transaction & txn, const Path & statePath, PathSet & paths);
|
||||
|
||||
void shareStateTxn(const Transaction & txn, const Path & from, const Path & to, const bool snapshot);
|
||||
void unShareStateTxn(const Transaction & txn, const Path & path, const bool branch, const bool restoreOld);
|
||||
|
||||
PathSet toNonSharedPathSetTxn(const Transaction & txn, const PathSet & statePaths);
|
||||
Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath);
|
||||
|
||||
/*
|
||||
* Returns a pathset with all paths (including itself) that eventually share the same statePath
|
||||
*/
|
||||
PathSet getSharedWithPathSetRecTxn(const Transaction & txn, const Path & statePath);
|
||||
|
||||
void ensurePathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
CommitIntervals getStatePathsIntervalTxn(const Transaction & txn, const Path & statePath);
|
||||
void setStatePathsIntervalTxn(const Transaction & txn, const Path & statePath, const CommitIntervals & intervals);
|
||||
|
||||
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision);
|
||||
bool querySharedStateTxn(const Transaction & txn, const Path & statePath, Path & shared_with);
|
||||
|
||||
void setStateComponentTxn(const Transaction & txn, const Path & storePath, const Path & statePath, const string & identifier, const string & user);
|
||||
|
||||
void setVersionedStateEntriesTxn(const Transaction & txn, const Path & statePath, const StateInfos & infos, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
||||
bool getVersionedStateEntriesTxn(const Transaction & txn, const Path & statePath, StateInfos & infos, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
||||
|
||||
void setStateOptionsTxn(const Transaction & txn, const Path & statePath, const string & user, const string & group, int chmod, const string & runtimeArgs);
|
||||
void getStateOptionsTxn(const Transaction & txn, const Path & statePath, string & user, string & group, int & chmod, string & runtimeArgs);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "misc.hh"
|
||||
#include "store-api.hh"
|
||||
#include "db.hh"
|
||||
#include "local-store.hh"
|
||||
|
||||
#include <aterm2.h>
|
||||
|
||||
@@ -8,31 +9,92 @@
|
||||
namespace nix {
|
||||
|
||||
|
||||
Derivation derivationFromPath(const Path & drvPath)
|
||||
Derivation derivationFromPathPrivate(const bool dotxn, const Transaction & txn, const Path & drvPath)
|
||||
{
|
||||
assertStorePath(drvPath);
|
||||
store->ensurePath(drvPath);
|
||||
if(dotxn)
|
||||
ensurePathTxn(txn, drvPath);
|
||||
else
|
||||
store->ensurePath(drvPath);
|
||||
|
||||
ATerm t = ATreadFromNamedFile(drvPath.c_str());
|
||||
if (!t) throw Error(format("cannot read aterm from `%1%'") % drvPath);
|
||||
if (!t)
|
||||
throw Error(format("cannot read aterm from `%1%'") % drvPath);
|
||||
return parseDerivation(t);
|
||||
}
|
||||
|
||||
|
||||
void computeFSClosure(const Path & storePath,
|
||||
PathSet & paths, bool flipDirection)
|
||||
//Wrappers
|
||||
Derivation derivationFromPath(const Path & drvPath)
|
||||
{
|
||||
if (paths.find(storePath) != paths.end()) return;
|
||||
paths.insert(storePath);
|
||||
return derivationFromPathPrivate(false, noTxn, drvPath);
|
||||
}
|
||||
Derivation derivationFromPathTxn(const Transaction & txn, const Path & drvPath)
|
||||
{
|
||||
return derivationFromPathPrivate(true, txn, drvPath);
|
||||
}
|
||||
|
||||
void computeFSClosure(const Path & path, PathSet & paths, const bool & withComponents, const bool & withState, const int revision, bool flipDirection)
|
||||
{
|
||||
computeFSClosureTxn(noTxn, path, paths, withComponents, withState, revision, flipDirection);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notice that the incoming 'paths' parameter can already be filled and only needs to be expanded
|
||||
* Notice that we CANNOT change the order of the existing paths
|
||||
*/
|
||||
void computeFSClosureTxn(const Transaction & txn, const Path & path, PathSet & paths, const bool & withComponents, const bool & withState, const int revision, bool flipDirection)
|
||||
{
|
||||
PathSet allPaths;
|
||||
computeFSClosureRecTxn(txn, path, allPaths, revision, flipDirection);
|
||||
|
||||
if(!withComponents && !withState)
|
||||
throw Error(format("Useless call to computeFSClosure, at leat withComponents or withState must be true"));
|
||||
|
||||
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
||||
if ( !isValidPathTxn(txn, *i) && !isValidStatePathTxn(txn, *i) )
|
||||
throw Error(format("Not a state or store path: ") % *i);
|
||||
|
||||
//if withComponents, we add all component paths
|
||||
if( withComponents ){
|
||||
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
||||
if ( isValidPathTxn(txn, *i) )
|
||||
paths.insert(*i);
|
||||
}
|
||||
|
||||
//if withState, we add all state paths
|
||||
if( withState ){
|
||||
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
||||
if ( isValidStatePathTxn(txn, *i) )
|
||||
paths.insert(*i);
|
||||
}
|
||||
}
|
||||
|
||||
void computeFSClosureRecTxn(const Transaction & txn, const Path & path, PathSet & paths, const int revision, const bool & flipDirection)
|
||||
{
|
||||
if (paths.find(path) != paths.end()) //takes care of double entries
|
||||
return;
|
||||
|
||||
//printMsg(lvlError, format("ComputeFSClosureRec '%1%'") % path);
|
||||
|
||||
paths.insert(path);
|
||||
|
||||
PathSet references;
|
||||
if (flipDirection)
|
||||
store->queryReferrers(storePath, references);
|
||||
else
|
||||
store->queryReferences(storePath, references);
|
||||
PathSet stateReferences;
|
||||
|
||||
if (flipDirection){
|
||||
queryStoreReferrersTxn(txn, path, references, revision);
|
||||
queryStateReferrersTxn(txn, path, stateReferences, revision);
|
||||
}
|
||||
else{
|
||||
queryXReferencesTxn(txn, path, references, true, revision);
|
||||
queryXReferencesTxn(txn, path, stateReferences, false, revision);
|
||||
}
|
||||
|
||||
PathSet allReferences;
|
||||
allReferences = pathSets_union(references, stateReferences);
|
||||
|
||||
for (PathSet::iterator i = references.begin();
|
||||
i != references.end(); ++i)
|
||||
computeFSClosure(*i, paths, flipDirection);
|
||||
for (PathSet::iterator i = allReferences.begin(); i != allReferences.end(); ++i)
|
||||
computeFSClosureRecTxn(txn, *i, paths, revision, flipDirection);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,13 +120,12 @@ void queryMissing(const PathSet & targets,
|
||||
|
||||
if (isDerivation(p)) {
|
||||
if (!store->isValidPath(p)) continue;
|
||||
Derivation drv = derivationFromPath(p);
|
||||
Derivation drv = derivationFromPathTxn(noTxn, p);
|
||||
|
||||
bool mustBuild = false;
|
||||
for (DerivationOutputs::iterator i = drv.outputs.begin();
|
||||
i != drv.outputs.end(); ++i)
|
||||
if (!store->isValidPath(i->second.path) &&
|
||||
!store->hasSubstitutes(i->second.path))
|
||||
if (!store->isValidPath(i->second.path) && !store->hasSubstitutes(i->second.path))
|
||||
mustBuild = true;
|
||||
|
||||
if (mustBuild) {
|
||||
@@ -83,8 +144,8 @@ void queryMissing(const PathSet & targets,
|
||||
if (store->isValidPath(p)) continue;
|
||||
if (store->hasSubstitutes(p))
|
||||
willSubstitute.insert(p);
|
||||
PathSet refs;
|
||||
store->queryReferences(p, todo);
|
||||
// XXX call the substituters
|
||||
// store->queryReferences(p, todo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __MISC_H
|
||||
|
||||
#include "derivations.hh"
|
||||
#include "db.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
@@ -9,6 +10,9 @@ namespace nix {
|
||||
|
||||
/* Read a derivation, after ensuring its existence through
|
||||
ensurePath(). */
|
||||
Derivation derivationFromPathTxn(const Transaction & txn, const Path & drvPath);
|
||||
|
||||
/* Same as above, but wihouth a txn now. This function can be called from the user side */
|
||||
Derivation derivationFromPath(const Path & drvPath);
|
||||
|
||||
/* Place in `paths' the set of all store paths in the file system
|
||||
@@ -17,9 +21,18 @@ Derivation derivationFromPath(const Path & drvPath);
|
||||
`flipDirection' is true, the set of paths that can reach
|
||||
`storePath' is returned; that is, the closures under the
|
||||
`referrers' relation instead of the `references' relation is
|
||||
|
||||
withState = include the state paths into the closure
|
||||
withComponents = include the component paths into the closure
|
||||
|
||||
We can currentky only compute the closure of the latsest revision!
|
||||
|
||||
returned. */
|
||||
void computeFSClosure(const Path & storePath,
|
||||
PathSet & paths, bool flipDirection = false);
|
||||
void computeFSClosure(const Path & storePath, PathSet & paths, const bool & withComponents, const bool & withState, const int revision, bool flipDirection = false);
|
||||
|
||||
void computeFSClosureTxn(const Transaction & txn, const Path & storePath, PathSet & paths, const bool & withComponents, const bool & withState, const int revision, bool flipDirection = false);
|
||||
|
||||
void computeFSClosureRecTxn(const Transaction & txn, const Path & path, PathSet & paths, const int revision, const bool & flipDirection); //TODO private
|
||||
|
||||
/* Return the path corresponding to the output identifier `id' in the
|
||||
given derivation. */
|
||||
|
||||
@@ -161,10 +161,8 @@ void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
|
||||
|
||||
debug(format("locking path `%1%'") % path);
|
||||
|
||||
if (lockedPaths.find(lockPath) != lockedPaths.end()) {
|
||||
debug(format("already holding lock on `%1%'") % lockPath);
|
||||
continue;
|
||||
}
|
||||
if (lockedPaths.find(lockPath) != lockedPaths.end())
|
||||
throw Error("deadlock: trying to re-acquire self-held lock");
|
||||
|
||||
AutoCloseFD fd;
|
||||
|
||||
@@ -225,5 +223,12 @@ void PathLocks::setDeletion(bool deletePaths)
|
||||
this->deletePaths = deletePaths;
|
||||
}
|
||||
|
||||
|
||||
bool pathIsLockedByMe(const Path & path)
|
||||
{
|
||||
Path lockPath = path + ".lock";
|
||||
return lockedPaths.find(lockPath) != lockedPaths.end();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user